mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
1097 lines
30 KiB
C++
1097 lines
30 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkMedicalImageProperties.cxx,v
|
|
|
|
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 "vtkMedicalImageProperties.h"
|
|
#include "vtkObjectFactory.h"
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <set>
|
|
|
|
#include <ctime> // for strftime
|
|
#include <ctype.h> // for isdigit
|
|
#include <cassert>
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkStandardNewMacro(vtkMedicalImageProperties);
|
|
|
|
static const char *vtkMedicalImagePropertiesOrientationString[] = {
|
|
"AXIAL",
|
|
"CORONAL",
|
|
"SAGITTAL",
|
|
NULL
|
|
};
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
class vtkMedicalImagePropertiesInternals
|
|
{
|
|
public:
|
|
class WindowLevelPreset
|
|
{
|
|
public:
|
|
double Window;
|
|
double Level;
|
|
std::string Comment;
|
|
};
|
|
|
|
class UserDefinedValue
|
|
{
|
|
public:
|
|
UserDefinedValue(const char *name = 0, const char *value = 0):Name(name ? name : ""),Value(value ? value : "") {}
|
|
std::string Name;
|
|
std::string Value;
|
|
// order for the std::set
|
|
bool operator<(const UserDefinedValue &udv) const
|
|
{
|
|
return Name < udv.Name;
|
|
}
|
|
};
|
|
typedef std::set< UserDefinedValue > UserDefinedValues;
|
|
UserDefinedValues UserDefinedValuePool;
|
|
void AddUserDefinedValue(const char *name, const char *value)
|
|
{
|
|
if( name && *name && value && *value )
|
|
{
|
|
UserDefinedValuePool.insert( UserDefinedValues::value_type(name, value) );
|
|
}
|
|
// else raise a warning ?
|
|
}
|
|
const char *GetUserDefinedValue(const char *name) const
|
|
{
|
|
if( name && *name )
|
|
{
|
|
UserDefinedValue key(name);
|
|
UserDefinedValues::const_iterator it = UserDefinedValuePool.find( key );
|
|
if( it != UserDefinedValuePool.end() )
|
|
{
|
|
assert( strcmp(it->Name.c_str(), name) == 0 );
|
|
return it->Value.c_str();
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
unsigned int GetNumberOfUserDefinedValues() const
|
|
{
|
|
return static_cast<unsigned int>(UserDefinedValuePool.size());
|
|
}
|
|
const char *GetUserDefinedNameByIndex(unsigned int idx)
|
|
{
|
|
if( idx < UserDefinedValuePool.size() )
|
|
{
|
|
UserDefinedValues::const_iterator it = UserDefinedValuePool.begin();
|
|
while( idx )
|
|
{
|
|
it++;
|
|
idx--;
|
|
}
|
|
return it->Name.c_str();
|
|
}
|
|
return NULL;
|
|
}
|
|
const char *GetUserDefinedValueByIndex(unsigned int idx)
|
|
{
|
|
if( idx < UserDefinedValuePool.size() )
|
|
{
|
|
UserDefinedValues::const_iterator it = UserDefinedValuePool.begin();
|
|
while( idx )
|
|
{
|
|
it++;
|
|
idx--;
|
|
}
|
|
return it->Value.c_str();
|
|
}
|
|
return NULL;
|
|
}
|
|
void RemoveAllUserDefinedValues()
|
|
{
|
|
UserDefinedValuePool.clear();
|
|
}
|
|
|
|
typedef std::vector<WindowLevelPreset> WindowLevelPresetPoolType;
|
|
typedef std::vector<WindowLevelPreset>::iterator WindowLevelPresetPoolIterator;
|
|
|
|
WindowLevelPresetPoolType WindowLevelPresetPool;
|
|
|
|
// It is also useful to have a mapping from DICOM UID to slice id, for application like VolView
|
|
typedef std::map< unsigned int, std::string> SliceUIDType;
|
|
typedef std::vector< SliceUIDType > VolumeSliceUIDType;
|
|
VolumeSliceUIDType UID;
|
|
void SetNumberOfVolumes(unsigned int n)
|
|
{
|
|
UID.resize(n);
|
|
Orientation.resize(n);
|
|
}
|
|
void SetUID(unsigned int vol, unsigned int slice, const char *uid)
|
|
{
|
|
SetNumberOfVolumes( vol + 1 );
|
|
UID[vol][slice] = uid;
|
|
}
|
|
const char *GetUID(unsigned int vol, unsigned int slice)
|
|
{
|
|
assert( vol < UID.size() );
|
|
assert( UID[vol].find(slice) != UID[vol].end() );
|
|
//if( UID[vol].find(slice) == UID[vol].end() )
|
|
// {
|
|
// this->Print( cerr, vtkIndent() );
|
|
// }
|
|
return UID[vol].find(slice)->second.c_str();
|
|
}
|
|
// Extensive lookup
|
|
int FindSlice(int &vol, const char *uid)
|
|
{
|
|
vol = -1;
|
|
for(unsigned int v = 0; v < UID.size(); ++v )
|
|
{
|
|
SliceUIDType::const_iterator cit = UID[v].begin();
|
|
while (cit != UID[v].end())
|
|
{
|
|
if (cit->second == uid)
|
|
{
|
|
vol = v;
|
|
return static_cast<int>(cit->first);
|
|
}
|
|
++cit;
|
|
}
|
|
}
|
|
return -1; // volume not found.
|
|
}
|
|
int GetSlice(unsigned int vol, const char *uid)
|
|
{
|
|
assert( vol < UID.size() );
|
|
SliceUIDType::const_iterator cit = UID[vol].begin();
|
|
while (cit != UID[vol].end())
|
|
{
|
|
if (cit->second == uid)
|
|
{
|
|
return static_cast<int>(cit->first);
|
|
}
|
|
++cit;
|
|
}
|
|
return -1; // uid not found.
|
|
}
|
|
void Print(ostream &os, vtkIndent indent)
|
|
{
|
|
os << indent << "WindowLevel: \n";
|
|
for( WindowLevelPresetPoolIterator it = WindowLevelPresetPool.begin(); it != WindowLevelPresetPool.end(); ++it )
|
|
{
|
|
const WindowLevelPreset &wlp = *it;
|
|
os << indent.GetNextIndent() << "Window: " << wlp.Window << "\n";
|
|
os << indent.GetNextIndent() << "Level: " << wlp.Level << "\n";
|
|
os << indent.GetNextIndent() << "Comment: " << wlp.Comment << "\n";
|
|
}
|
|
os << indent << "UID(s):\n";
|
|
for( VolumeSliceUIDType::const_iterator it = UID.begin();
|
|
it != UID.end();
|
|
++it)
|
|
{
|
|
for( SliceUIDType::const_iterator it2 = it->begin();
|
|
it2 != it->end();
|
|
++it2)
|
|
{
|
|
os << indent.GetNextIndent()
|
|
<< it2->first << " " << it2->second << "\n";
|
|
}
|
|
}
|
|
os << indent << "Orientation(s):\n";
|
|
for( std::vector<unsigned int>::const_iterator it = Orientation.begin();
|
|
it != Orientation.end(); ++it)
|
|
{
|
|
os << indent.GetNextIndent()
|
|
<< vtkMedicalImageProperties::GetStringFromOrientationType(*it) << "\n";
|
|
}
|
|
os << indent << "User Defined Values: (" << UserDefinedValuePool.size() << ")\n";
|
|
UserDefinedValues::const_iterator it2 = UserDefinedValuePool.begin();
|
|
for(; it2 != UserDefinedValuePool.end(); ++it2)
|
|
{
|
|
os << indent.GetNextIndent()
|
|
<< it2->Name << " -> " << it2->Value << "\n";
|
|
}
|
|
}
|
|
std::vector<unsigned int> Orientation;
|
|
void SetOrientation(unsigned int vol, unsigned int ori)
|
|
{
|
|
// see SetNumberOfVolumes for allocation
|
|
assert( ori <= vtkMedicalImageProperties::SAGITTAL );
|
|
Orientation[vol] = ori;
|
|
}
|
|
unsigned int GetOrientation(unsigned int vol)
|
|
{
|
|
assert( vol < Orientation.size() );
|
|
const unsigned int &val = Orientation[vol];
|
|
assert( val <= vtkMedicalImageProperties::SAGITTAL );
|
|
return val;
|
|
}
|
|
void DeepCopy(vtkMedicalImagePropertiesInternals *p)
|
|
{
|
|
WindowLevelPresetPool = p->WindowLevelPresetPool;
|
|
UserDefinedValuePool = p->UserDefinedValuePool;
|
|
UID = p->UID;
|
|
Orientation = p->Orientation;
|
|
}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkMedicalImageProperties::vtkMedicalImageProperties()
|
|
{
|
|
this->Internals = new vtkMedicalImagePropertiesInternals;
|
|
|
|
this->StudyDate = NULL;
|
|
this->AcquisitionDate = NULL;
|
|
this->StudyTime = NULL;
|
|
this->AcquisitionTime = NULL;
|
|
this->ConvolutionKernel = NULL;
|
|
this->EchoTime = NULL;
|
|
this->EchoTrainLength = NULL;
|
|
this->Exposure = NULL;
|
|
this->ExposureTime = NULL;
|
|
this->GantryTilt = NULL;
|
|
this->ImageDate = NULL;
|
|
this->ImageNumber = NULL;
|
|
this->ImageTime = NULL;
|
|
this->InstitutionName = NULL;
|
|
this->KVP = NULL;
|
|
this->ManufacturerModelName = NULL;
|
|
this->Manufacturer = NULL;
|
|
this->Modality = NULL;
|
|
this->PatientAge = NULL;
|
|
this->PatientBirthDate = NULL;
|
|
this->PatientID = NULL;
|
|
this->PatientName = NULL;
|
|
this->PatientSex = NULL;
|
|
this->RepetitionTime = NULL;
|
|
this->SeriesDescription = NULL;
|
|
this->SeriesNumber = NULL;
|
|
this->SliceThickness = NULL;
|
|
this->StationName = NULL;
|
|
this->StudyDescription = NULL;
|
|
this->StudyID = NULL;
|
|
this->XRayTubeCurrent = NULL;
|
|
|
|
this->DirectionCosine[0] = 1;
|
|
this->DirectionCosine[1] = 0;
|
|
this->DirectionCosine[2] = 0;
|
|
this->DirectionCosine[3] = 0;
|
|
this->DirectionCosine[4] = 1;
|
|
this->DirectionCosine[5] = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkMedicalImageProperties::~vtkMedicalImageProperties()
|
|
{
|
|
this->Clear();
|
|
|
|
delete this->Internals;
|
|
this->Internals = NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::AddUserDefinedValue(const char *name, const char *value)
|
|
{
|
|
this->Internals->AddUserDefinedValue(name, value);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char *vtkMedicalImageProperties::GetUserDefinedValue(const char *name)
|
|
{
|
|
return this->Internals->GetUserDefinedValue(name);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned int vtkMedicalImageProperties::GetNumberOfUserDefinedValues()
|
|
{
|
|
return this->Internals->GetNumberOfUserDefinedValues();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char *vtkMedicalImageProperties::GetUserDefinedValueByIndex(unsigned int idx)
|
|
{
|
|
return this->Internals->GetUserDefinedValueByIndex(idx);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char *vtkMedicalImageProperties::GetUserDefinedNameByIndex(unsigned int idx)
|
|
{
|
|
return this->Internals->GetUserDefinedNameByIndex(idx);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::RemoveAllUserDefinedValues()
|
|
{
|
|
this->Internals->RemoveAllUserDefinedValues();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::Clear()
|
|
{
|
|
this->SetStudyDate(NULL);
|
|
this->SetAcquisitionDate(NULL);
|
|
this->SetStudyTime(NULL);
|
|
this->SetAcquisitionTime(NULL);
|
|
this->SetConvolutionKernel(NULL);
|
|
this->SetEchoTime(NULL);
|
|
this->SetEchoTrainLength(NULL);
|
|
this->SetExposure(NULL);
|
|
this->SetExposureTime(NULL);
|
|
this->SetGantryTilt(NULL);
|
|
this->SetImageDate(NULL);
|
|
this->SetImageNumber(NULL);
|
|
this->SetImageTime(NULL);
|
|
this->SetInstitutionName(NULL);
|
|
this->SetKVP(NULL);
|
|
this->SetManufacturerModelName(NULL);
|
|
this->SetManufacturer(NULL);
|
|
this->SetModality(NULL);
|
|
this->SetPatientAge(NULL);
|
|
this->SetPatientBirthDate(NULL);
|
|
this->SetPatientID(NULL);
|
|
this->SetPatientName(NULL);
|
|
this->SetPatientSex(NULL);
|
|
this->SetRepetitionTime(NULL);
|
|
this->SetSeriesDescription(NULL);
|
|
this->SetSeriesNumber(NULL);
|
|
this->SetSliceThickness(NULL);
|
|
this->SetStationName(NULL);
|
|
this->SetStudyDescription(NULL);
|
|
this->SetStudyID(NULL);
|
|
this->SetXRayTubeCurrent(NULL);
|
|
|
|
this->RemoveAllWindowLevelPresets();
|
|
this->RemoveAllUserDefinedValues();
|
|
|
|
this->Internals->Orientation.clear();
|
|
this->Internals->UID.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::DeepCopy(vtkMedicalImageProperties *p)
|
|
{
|
|
if (p == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Clear();
|
|
|
|
this->SetStudyDate(p->GetStudyDate());
|
|
this->SetAcquisitionDate(p->GetAcquisitionDate());
|
|
this->SetStudyTime(p->GetStudyTime());
|
|
this->SetAcquisitionTime(p->GetAcquisitionTime());
|
|
this->SetConvolutionKernel(p->GetConvolutionKernel());
|
|
this->SetEchoTime(p->GetEchoTime());
|
|
this->SetEchoTrainLength(p->GetEchoTrainLength());
|
|
this->SetExposure(p->GetExposure());
|
|
this->SetExposureTime(p->GetExposureTime());
|
|
this->SetGantryTilt(p->GetGantryTilt());
|
|
this->SetImageDate(p->GetImageDate());
|
|
this->SetImageNumber(p->GetImageNumber());
|
|
this->SetImageTime(p->GetImageTime());
|
|
this->SetInstitutionName(p->GetInstitutionName());
|
|
this->SetKVP(p->GetKVP());
|
|
this->SetManufacturerModelName(p->GetManufacturerModelName());
|
|
this->SetManufacturer(p->GetManufacturer());
|
|
this->SetModality(p->GetModality());
|
|
this->SetPatientAge(p->GetPatientAge());
|
|
this->SetPatientBirthDate(p->GetPatientBirthDate());
|
|
this->SetPatientID(p->GetPatientID());
|
|
this->SetPatientName(p->GetPatientName());
|
|
this->SetPatientSex(p->GetPatientSex());
|
|
this->SetRepetitionTime(p->GetRepetitionTime());
|
|
this->SetSeriesDescription(p->GetSeriesDescription());
|
|
this->SetSeriesNumber(p->GetSeriesNumber());
|
|
this->SetSliceThickness(p->GetSliceThickness());
|
|
this->SetStationName(p->GetStationName());
|
|
this->SetStudyDescription(p->GetStudyDescription());
|
|
this->SetStudyID(p->GetStudyID());
|
|
this->SetXRayTubeCurrent(p->GetXRayTubeCurrent());
|
|
this->SetDirectionCosine(p->GetDirectionCosine());
|
|
|
|
this->Internals->DeepCopy(p->Internals);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::AddWindowLevelPreset(
|
|
double w, double l)
|
|
{
|
|
if (!this->Internals || this->HasWindowLevelPreset(w, l))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
vtkMedicalImagePropertiesInternals::WindowLevelPreset preset;
|
|
preset.Window = w;
|
|
preset.Level = l;
|
|
this->Internals->WindowLevelPresetPool.push_back(preset);
|
|
return static_cast<int>(this->Internals->WindowLevelPresetPool.size() - 1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetWindowLevelPresetIndex(double w, double l)
|
|
{
|
|
if (this->Internals)
|
|
{
|
|
vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator it =
|
|
this->Internals->WindowLevelPresetPool.begin();
|
|
vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator end =
|
|
this->Internals->WindowLevelPresetPool.end();
|
|
int index = 0;
|
|
for (; it != end; ++it, ++index)
|
|
{
|
|
if ((*it).Window == w && (*it).Level == l)
|
|
{
|
|
return index;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::HasWindowLevelPreset(double w, double l)
|
|
{
|
|
return this->GetWindowLevelPresetIndex(w, l) >= 0 ? 1 : 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::RemoveWindowLevelPreset(double w, double l)
|
|
{
|
|
if (this->Internals)
|
|
{
|
|
vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator it =
|
|
this->Internals->WindowLevelPresetPool.begin();
|
|
vtkMedicalImagePropertiesInternals::WindowLevelPresetPoolIterator end =
|
|
this->Internals->WindowLevelPresetPool.end();
|
|
for (; it != end; ++it)
|
|
{
|
|
if ((*it).Window == w && (*it).Level == l)
|
|
{
|
|
this->Internals->WindowLevelPresetPool.erase(it);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::RemoveAllWindowLevelPresets()
|
|
{
|
|
if (this->Internals)
|
|
{
|
|
this->Internals->WindowLevelPresetPool.clear();
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetNumberOfWindowLevelPresets()
|
|
{
|
|
return this->Internals ? static_cast<int>(
|
|
this->Internals->WindowLevelPresetPool.size()) : 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetNthWindowLevelPreset(
|
|
int idx, double *w, double *l)
|
|
{
|
|
if (this->Internals &&
|
|
idx >= 0 && idx < this->GetNumberOfWindowLevelPresets())
|
|
{
|
|
*w = this->Internals->WindowLevelPresetPool[idx].Window;
|
|
*l = this->Internals->WindowLevelPresetPool[idx].Level;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double* vtkMedicalImageProperties::GetNthWindowLevelPreset(int idx)
|
|
|
|
{
|
|
static double wl[2];
|
|
if (this->GetNthWindowLevelPreset(idx, wl, wl + 1))
|
|
{
|
|
return wl;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char* vtkMedicalImageProperties::GetNthWindowLevelPresetComment(
|
|
int idx)
|
|
{
|
|
if (this->Internals &&
|
|
idx >= 0 && idx < this->GetNumberOfWindowLevelPresets())
|
|
{
|
|
return this->Internals->WindowLevelPresetPool[idx].Comment.c_str();
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::SetNthWindowLevelPresetComment(
|
|
int idx, const char *comment)
|
|
{
|
|
if (this->Internals &&
|
|
idx >= 0 && idx < this->GetNumberOfWindowLevelPresets())
|
|
{
|
|
this->Internals->WindowLevelPresetPool[idx].Comment =
|
|
(comment ? comment : "");
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char *vtkMedicalImageProperties::GetInstanceUIDFromSliceID(
|
|
int volumeidx, int sliceid)
|
|
{
|
|
return this->Internals->GetUID(volumeidx, sliceid);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetSliceIDFromInstanceUID(
|
|
int &volumeidx, const char *uid)
|
|
{
|
|
if( volumeidx == -1 )
|
|
{
|
|
return this->Internals->FindSlice(volumeidx, uid);
|
|
}
|
|
else
|
|
{
|
|
return this->Internals->GetSlice(volumeidx, uid);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::SetInstanceUIDFromSliceID(
|
|
int volumeidx, int sliceid, const char *uid)
|
|
{
|
|
this->Internals->SetUID(volumeidx,sliceid, uid);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::SetOrientationType(int volumeidx, int orientation)
|
|
{
|
|
this->Internals->SetOrientation(volumeidx, orientation);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetOrientationType(int volumeidx)
|
|
{
|
|
return this->Internals->GetOrientation(volumeidx);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char *vtkMedicalImageProperties::GetStringFromOrientationType(unsigned int type)
|
|
{
|
|
static unsigned int numtypes = 0;
|
|
// find length of table
|
|
if (!numtypes)
|
|
{
|
|
while (vtkMedicalImagePropertiesOrientationString[numtypes] != NULL)
|
|
{
|
|
numtypes++;
|
|
}
|
|
}
|
|
|
|
if (type < numtypes)
|
|
{
|
|
return vtkMedicalImagePropertiesOrientationString[type];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double vtkMedicalImageProperties::GetSliceThicknessAsDouble()
|
|
{
|
|
if (this->SliceThickness)
|
|
{
|
|
return atof(this->SliceThickness);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double vtkMedicalImageProperties::GetGantryTiltAsDouble()
|
|
{
|
|
if (this->GantryTilt)
|
|
{
|
|
return atof(this->GantryTilt);
|
|
}
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetAgeAsFields(const char *age, int &year,
|
|
int &month, int &week, int &day)
|
|
{
|
|
year = month = week = day = -1;
|
|
if( !age )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t len = strlen(age);
|
|
if( len == 4 )
|
|
{
|
|
// DICOM V3
|
|
unsigned int val;
|
|
char type;
|
|
if( !isdigit(age[0])
|
|
|| !isdigit(age[1])
|
|
|| !isdigit(age[2]))
|
|
{
|
|
return 0;
|
|
}
|
|
if( sscanf(age, "%3u%c", &val, &type) != 2 )
|
|
{
|
|
return 0;
|
|
}
|
|
switch(type)
|
|
{
|
|
case 'Y':
|
|
year = static_cast<int>(val);
|
|
break;
|
|
case 'M':
|
|
month = static_cast<int>(val);
|
|
break;
|
|
case 'W':
|
|
week = static_cast<int>(val);
|
|
break;
|
|
case 'D':
|
|
day = static_cast<int>(val);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientAgeYear()
|
|
{
|
|
const char *age = this->GetPatientAge();
|
|
int year, month, week, day;
|
|
vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day);
|
|
return year;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientAgeMonth()
|
|
{
|
|
const char *age = this->GetPatientAge();
|
|
int year, month, week, day;
|
|
vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day);
|
|
return month;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientAgeWeek()
|
|
{
|
|
const char *age = this->GetPatientAge();
|
|
int year, month, week, day;
|
|
vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day);
|
|
return week;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientAgeDay()
|
|
{
|
|
const char *age = this->GetPatientAge();
|
|
int year, month, week, day;
|
|
vtkMedicalImageProperties::GetAgeAsFields(age, year, month, week, day);
|
|
return day;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetTimeAsFields(const char *time, int &hour,
|
|
int &minute, int &second /* , long &milliseconds */)
|
|
{
|
|
if( !time )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t len = strlen(time);
|
|
if( len == 6 )
|
|
{
|
|
// DICOM V3
|
|
if( sscanf(time, "%02d%02d%02d", &hour, &minute, &second) != 3 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if( len == 8 )
|
|
{
|
|
// Some *very* old ACR-NEMA
|
|
if( sscanf(time, "%02d.%02d.%02d", &hour, &minute, &second) != 3 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetDateAsFields(const char *date, int &year,
|
|
int &month, int &day)
|
|
{
|
|
if( !date )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
size_t len = strlen(date);
|
|
if( len == 8 )
|
|
{
|
|
// DICOM V3
|
|
if( sscanf(date, "%04d%02d%02d", &year, &month, &day) != 3 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else if( len == 10 )
|
|
{
|
|
// Some *very* old ACR-NEMA
|
|
if( sscanf(date, "%04d.%02d.%02d", &year, &month, &day) != 3 )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Some buggy versions of gcc complain about the use of %c: warning: `%c'
|
|
// yields only last 2 digits of year in some locales. Of course program-
|
|
// mers are encouraged to use %c, it gives the preferred date and time
|
|
// representation. One meets all kinds of strange obfuscations to circum-
|
|
// vent this gcc problem. A relatively clean one is to add an intermediate
|
|
// function. This is described as bug #3190 in gcc bugzilla:
|
|
// [-Wformat-y2k doesn't belong to -Wall - it's hard to avoid]
|
|
inline size_t
|
|
my_strftime(char *s, size_t max, const char *fmt, const struct tm *tm)
|
|
{
|
|
return strftime(s, max, fmt, tm);
|
|
}
|
|
// Helper function to convert a DICOM iso date format into a locale one
|
|
// locale buffer should be typically char locale[200]
|
|
int vtkMedicalImageProperties::GetDateAsLocale(const char *iso, char *locale)
|
|
{
|
|
int year, month, day;
|
|
if( vtkMedicalImageProperties::GetDateAsFields(iso, year, month, day) )
|
|
{
|
|
if (year < 1900 || month < 1 || month > 12 || day < 1 || day > 31)
|
|
{
|
|
*locale = '\0';
|
|
}
|
|
else
|
|
{
|
|
struct tm date;
|
|
memset(&date,0, sizeof(date));
|
|
date.tm_mday = day;
|
|
// month are expressed in the [0-11] range:
|
|
date.tm_mon = month - 1;
|
|
// structure is date starting at 1900
|
|
date.tm_year = year - 1900;
|
|
my_strftime(locale, 200, "%x", &date);
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientBirthDateYear()
|
|
{
|
|
const char *date = this->GetPatientBirthDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return year;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientBirthDateMonth()
|
|
{
|
|
const char *date = this->GetPatientBirthDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return month;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetPatientBirthDateDay()
|
|
{
|
|
const char *date = this->GetPatientBirthDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return day;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetAcquisitionDateYear()
|
|
{
|
|
const char *date = this->GetAcquisitionDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return year;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetAcquisitionDateMonth()
|
|
{
|
|
const char *date = this->GetAcquisitionDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return month;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetAcquisitionDateDay()
|
|
{
|
|
const char *date = this->GetAcquisitionDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return day;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetImageDateYear()
|
|
{
|
|
const char *date = this->GetImageDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return year;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetImageDateMonth()
|
|
{
|
|
const char *date = this->GetImageDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return month;
|
|
}
|
|
//----------------------------------------------------------------------------
|
|
int vtkMedicalImageProperties::GetImageDateDay()
|
|
{
|
|
const char *date = this->GetImageDate();
|
|
int year = 0, month = 0, day = 0;
|
|
vtkMedicalImageProperties::GetDateAsFields(date, year, month, day);
|
|
return day;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkMedicalImageProperties::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "PatientName: ";
|
|
if (this->PatientName)
|
|
{
|
|
os << this->PatientName;
|
|
}
|
|
|
|
os << "\n" << indent << "PatientID: ";
|
|
if (this->PatientID)
|
|
{
|
|
os << this->PatientID;
|
|
}
|
|
|
|
os << "\n" << indent << "PatientAge: ";
|
|
if (this->PatientAge)
|
|
{
|
|
os << this->PatientAge;
|
|
}
|
|
|
|
os << "\n" << indent << "PatientSex: ";
|
|
if (this->PatientSex)
|
|
{
|
|
os << this->PatientSex;
|
|
}
|
|
|
|
os << "\n" << indent << "PatientBirthDate: ";
|
|
if (this->PatientBirthDate)
|
|
{
|
|
os << this->PatientBirthDate;
|
|
}
|
|
|
|
os << "\n" << indent << "ImageDate: ";
|
|
if (this->ImageDate)
|
|
{
|
|
os << this->ImageDate;
|
|
}
|
|
|
|
os << "\n" << indent << "ImageTime: ";
|
|
if (this->ImageTime)
|
|
{
|
|
os << this->ImageTime;
|
|
}
|
|
|
|
os << "\n" << indent << "ImageNumber: ";
|
|
if (this->ImageNumber)
|
|
{
|
|
os << this->ImageNumber;
|
|
}
|
|
|
|
os << "\n" << indent << "StudyDate: ";
|
|
if (this->StudyDate)
|
|
{
|
|
os << this->StudyDate;
|
|
}
|
|
|
|
os << "\n" << indent << "AcquisitionDate: ";
|
|
if (this->AcquisitionDate)
|
|
{
|
|
os << this->AcquisitionDate;
|
|
}
|
|
|
|
os << "\n" << indent << "StudyTime: ";
|
|
if (this->StudyTime)
|
|
{
|
|
os << this->StudyTime;
|
|
}
|
|
|
|
os << "\n" << indent << "AcquisitionTime: ";
|
|
if (this->AcquisitionTime)
|
|
{
|
|
os << this->AcquisitionTime;
|
|
}
|
|
|
|
os << "\n" << indent << "SeriesNumber: ";
|
|
if (this->SeriesNumber)
|
|
{
|
|
os << this->SeriesNumber;
|
|
}
|
|
|
|
os << "\n" << indent << "SeriesDescription: ";
|
|
if (this->SeriesDescription)
|
|
{
|
|
os << this->SeriesDescription;
|
|
}
|
|
|
|
os << "\n" << indent << "StudyDescription: ";
|
|
if (this->StudyDescription)
|
|
{
|
|
os << this->StudyDescription;
|
|
}
|
|
|
|
os << "\n" << indent << "StudyID: ";
|
|
if (this->StudyID)
|
|
{
|
|
os << this->StudyID;
|
|
}
|
|
|
|
os << "\n" << indent << "Modality: ";
|
|
if (this->Modality)
|
|
{
|
|
os << this->Modality;
|
|
}
|
|
|
|
os << "\n" << indent << "ManufacturerModelName: ";
|
|
if (this->ManufacturerModelName)
|
|
{
|
|
os << this->ManufacturerModelName;
|
|
}
|
|
|
|
os << "\n" << indent << "Manufacturer: ";
|
|
if (this->Manufacturer)
|
|
{
|
|
os << this->Manufacturer;
|
|
}
|
|
|
|
os << "\n" << indent << "StationName: ";
|
|
if (this->StationName)
|
|
{
|
|
os << this->StationName;
|
|
}
|
|
|
|
os << "\n" << indent << "InstitutionName: ";
|
|
if (this->InstitutionName)
|
|
{
|
|
os << this->InstitutionName;
|
|
}
|
|
|
|
os << "\n" << indent << "ConvolutionKernel: ";
|
|
if (this->ConvolutionKernel)
|
|
{
|
|
os << this->ConvolutionKernel;
|
|
}
|
|
|
|
os << "\n" << indent << "SliceThickness: ";
|
|
if (this->SliceThickness)
|
|
{
|
|
os << this->SliceThickness;
|
|
}
|
|
|
|
os << "\n" << indent << "KVP: ";
|
|
if (this->KVP)
|
|
{
|
|
os << this->KVP;
|
|
}
|
|
|
|
os << "\n" << indent << "GantryTilt: ";
|
|
if (this->GantryTilt)
|
|
{
|
|
os << this->GantryTilt;
|
|
}
|
|
|
|
os << "\n" << indent << "EchoTime: ";
|
|
if (this->EchoTime)
|
|
{
|
|
os << this->EchoTime;
|
|
}
|
|
|
|
os << "\n" << indent << "EchoTrainLength: ";
|
|
if (this->EchoTrainLength)
|
|
{
|
|
os << this->EchoTrainLength;
|
|
}
|
|
|
|
os << "\n" << indent << "RepetitionTime: ";
|
|
if (this->RepetitionTime)
|
|
{
|
|
os << this->RepetitionTime;
|
|
}
|
|
|
|
os << "\n" << indent << "ExposureTime: ";
|
|
if (this->ExposureTime)
|
|
{
|
|
os << this->ExposureTime;
|
|
}
|
|
|
|
os << "\n" << indent << "XRayTubeCurrent: ";
|
|
if (this->XRayTubeCurrent)
|
|
{
|
|
os << this->XRayTubeCurrent;
|
|
}
|
|
|
|
os << "\n" << indent << "Exposure: ";
|
|
if (this->Exposure)
|
|
{
|
|
os << this->Exposure;
|
|
}
|
|
|
|
os << "\n" << indent << "DirectionCosine: ("
|
|
<< this->DirectionCosine[0] << ", " << this->DirectionCosine[1]
|
|
<< ", " << this->DirectionCosine[2] << "), ("
|
|
<< this->DirectionCosine[3] << ", " << this->DirectionCosine[4]
|
|
<< ", " << this->DirectionCosine[5] << ")\n";
|
|
|
|
this->Internals->Print(os, indent);
|
|
}
|
|
|