mirror of
https://gitlab.ethz.ch/gfattori/glocalize.git
synced 2026-05-03 13:44:26 +02:00
577 lines
22 KiB
C++
577 lines
22 KiB
C++
#include "dicomUtils.h"
|
|
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
|
|
using std::cout;
|
|
using std::endl;
|
|
|
|
namespace {
|
|
|
|
static inline std::string Trim(std::string s)
|
|
{
|
|
auto notSpace = [](unsigned char c) { return !std::isspace(c); };
|
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), notSpace));
|
|
s.erase(std::find_if(s.rbegin(), s.rend(), notSpace).base(), s.end());
|
|
return s;
|
|
}
|
|
|
|
static inline int ParseIntOr(const std::string& s, int fallback)
|
|
{
|
|
const std::string t = Trim(s);
|
|
if (t.empty()) return fallback;
|
|
try
|
|
{
|
|
size_t idx = 0;
|
|
int v = std::stoi(t, &idx);
|
|
(void)idx;
|
|
return v;
|
|
}
|
|
catch (...)
|
|
{
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
static inline double ParseDoubleOr(const std::string& s, double fallback)
|
|
{
|
|
const std::string t = Trim(s);
|
|
if (t.empty()) return fallback;
|
|
try
|
|
{
|
|
size_t idx = 0;
|
|
double v = std::stod(t, &idx);
|
|
(void)idx;
|
|
return v;
|
|
}
|
|
catch (...)
|
|
{
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
static inline int GetTagIntOr(const gdcm::Tag& t, const gdcm::DataSet& ds, int fallback)
|
|
{
|
|
return ParseIntOr(gGetStringValueFromTagStr(t, ds), fallback);
|
|
}
|
|
|
|
static inline double GetTagDoubleOr(const gdcm::Tag& t, const gdcm::DataSet& ds, double fallback)
|
|
{
|
|
return ParseDoubleOr(gGetStringValueFromTagStr(t, ds), fallback);
|
|
}
|
|
|
|
// Parse a DICOM "DS" multi-value string with 3 components separated by '\\'.
|
|
// Returns {BADVALUE,BADVALUE,BADVALUE} if parsing fails.
|
|
std::array<double, 3> Parse3Doubles(const std::string& s)
|
|
{
|
|
std::array<double, 3> out{BADVALUE, BADVALUE, BADVALUE};
|
|
if (s.empty()) return out;
|
|
|
|
std::stringstream ss(s);
|
|
std::string token;
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
if (!std::getline(ss, token, '\\')) return out;
|
|
try
|
|
{
|
|
out[static_cast<size_t>(i)] = std::stod(token);
|
|
}
|
|
catch (...)
|
|
{
|
|
return {BADVALUE, BADVALUE, BADVALUE};
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
//FUNCTION DECLARATION NECESSARY FOR COPY/PASTE FROM vtkGDCMImageReader
|
|
// const char *gGetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds);
|
|
|
|
const char *gGetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds)
|
|
{
|
|
// NOTE: legacy API returning pointer into a static buffer.
|
|
// Keep for older call sites.
|
|
static std::string buffer;
|
|
buffer = gGetStringValueFromTagStr(t, ds);
|
|
return buffer.c_str();
|
|
}
|
|
|
|
std::string gGetStringValueFromTagStr(const gdcm::Tag& t, const gdcm::DataSet& ds)
|
|
{
|
|
if (!ds.FindDataElement(t)) return {};
|
|
const gdcm::DataElement& de = ds.GetDataElement(t);
|
|
const gdcm::ByteValue* bv = de.GetByteValue();
|
|
if (!bv) return {};
|
|
|
|
std::string s(bv->GetPointer(), bv->GetLength());
|
|
// DICOM strings are often space/\0 padded.
|
|
while (!s.empty() && (s.back() == '\0' || s.back() == ' ' || s.back() == '\r' || s.back() == '\n' || s.back() == '\t'))
|
|
s.pop_back();
|
|
return s;
|
|
}
|
|
|
|
//GENERAL INDEPENDENT FUNCTION TO CHECK FOR FILE DICOM MODALITY (PLAN, STRUCT, IMAGE) REQUIRES CORRECT PATH
|
|
const char * gCheckDICOMModality(const char *filename)
|
|
{
|
|
gdcm::Reader gR;
|
|
gR.SetFileName(filename);//str.toAscii().data());
|
|
if(!gR.Read())
|
|
return("NODCMFILE");
|
|
|
|
const gdcm::File &file = gR.GetFile();
|
|
const gdcm::DataSet &ds = file.GetDataSet();
|
|
return(gGetStringValueFromTag( gdcm::Tag(0x0008,0x0060), ds) ); //RETURN MODALITY
|
|
};
|
|
|
|
int gCheckDICOMModalityToInt(const char *filename){
|
|
|
|
const char * tmp = gCheckDICOMModality(filename);
|
|
//cout<< tmp<<endl;
|
|
|
|
if( !strcmp(tmp,"RTSTRUCT") )
|
|
return RTSTRUCT;
|
|
else if ( !strcmp(tmp,"RTPLAN") )
|
|
return RTPLAN;
|
|
else if( !strcmp(tmp,"CT") )
|
|
return IMAGE;
|
|
else
|
|
return NODCMFILE;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
IonBeamProperties::IonBeamProperties()
|
|
{
|
|
BeamNumber = BADVALUE;
|
|
BeamName.clear();
|
|
SupportId.clear();
|
|
SupportType.clear();
|
|
GantryAngle = BADVALUE;
|
|
IsocenterPosition = {BADVALUE, BADVALUE, BADVALUE};
|
|
TablePitchAngle = BADVALUE;
|
|
TableRollAngle = BADVALUE;
|
|
TableYawAngle = BADVALUE;
|
|
TableLatDispl = BADVALUE;
|
|
TableLongDispl = BADVALUE;
|
|
TableVertDispl = BADVALUE;
|
|
}
|
|
|
|
|
|
void IonBeamProperties::PrintSelf(){
|
|
cout<< "__ IonBeamProperties print self ** " <<endl;
|
|
cout<<" |_ BeamNumber = "<<BeamNumber<<endl;
|
|
cout<<" |_ BeamName = "<<BeamName<<endl;
|
|
cout<<" |_ SupportType = " <<SupportType<<endl;
|
|
cout<<" |_ SupportId = "<<SupportId<<endl;
|
|
cout<<" |_ GantryAngle = "<<GantryAngle<<endl;
|
|
cout<<" |_ IsocenterPosition = "<<IsocenterPosition[0]<<" "
|
|
<<IsocenterPosition[1]<<" "
|
|
<<IsocenterPosition[2]<<endl;
|
|
cout<<" |_ TableYawAngle = "<<TableYawAngle<<endl;
|
|
cout<<" |_ TablePitchAngle = "<<TablePitchAngle<<endl;
|
|
cout<<" |_ TableRollAngle = "<<TableRollAngle<<endl;
|
|
cout<<" |_ TableLatDispl = "<<TableLatDispl<<endl;
|
|
cout<<" |_ TableLongDispl = "<<TableLongDispl<<endl;
|
|
cout<<" |_ TableVertDispl = "<<TableVertDispl<<endl;
|
|
}
|
|
|
|
|
|
/*-----*/
|
|
//CLASS gIonBEAMProperties
|
|
RTPlan::RTPlan()
|
|
{
|
|
NumberOfBeams = 0;
|
|
PatientName.clear();
|
|
PatientID.clear();
|
|
PatientSex.clear();
|
|
PatientAge.clear();
|
|
PatientBirthDate.clear();
|
|
|
|
SeriesNumber.clear();
|
|
SeriesDescription.clear();
|
|
StudyID.clear();
|
|
StudyDescription.clear();
|
|
Modality.clear();
|
|
|
|
IsocenterPosition = {BADVALUE, BADVALUE, BADVALUE};
|
|
VolumeCenter = {BADVALUE, BADVALUE, BADVALUE};
|
|
|
|
BeamNumber = BADVALUE;
|
|
BeamName.clear();
|
|
TableRollAngle = BADVALUE;
|
|
TableYawAngle = BADVALUE;
|
|
TablePitchAngle = BADVALUE;
|
|
TableLatDispl = BADVALUE;
|
|
TableVertDispl = BADVALUE;
|
|
TableLongDispl = BADVALUE;
|
|
SupportType.clear();
|
|
SupportId.clear();
|
|
PatientOrientation.clear();
|
|
}
|
|
|
|
void RTPlan::PrintSelf(){
|
|
cout<< "** RTPlan print self ** " <<endl;
|
|
cout<<"PatientName = "<<PatientName<<endl;
|
|
cout<<"PatientID = "<<PatientID<<endl;
|
|
cout<<"PatientSex = "<<PatientSex<<endl;
|
|
cout<<"PatientAge = "<<PatientAge<<endl;
|
|
cout<<"PatientBirthDate = "<<PatientBirthDate<<endl;
|
|
cout<<"SeriesNumber = "<<SeriesNumber<<endl;
|
|
cout<<"SeriesDescription = "<<SeriesDescription<<endl;
|
|
cout<<"StudyID = "<<StudyID<<endl;
|
|
cout<<"StudyDescription = "<<StudyDescription<<endl;
|
|
cout<<"Modality = "<<Modality<<endl;
|
|
cout<<"IsocenterPosition = "<<IsocenterPosition[0]<<" "<<
|
|
IsocenterPosition[1]<<" "<<
|
|
IsocenterPosition[2]<<endl;
|
|
cout<<"VolumeCenter = "<<VolumeCenter[0]<<" "<<
|
|
VolumeCenter[1]<<" "<<
|
|
VolumeCenter[2]<<endl;
|
|
cout<<"BeamNumber = "<<BeamNumber<<endl;
|
|
cout<<"BeamName = "<<BeamName<<endl;
|
|
cout<<"TableRollAngle = "<<TableRollAngle<<endl;
|
|
cout<<"TableYawAngle = "<<TableYawAngle<<endl;
|
|
cout<<"TablePitchAngle = "<<TablePitchAngle<<endl;
|
|
cout<<"TableVertDispl = "<<TableVertDispl<<endl;
|
|
cout<<"TableLongDispl = "<<TableLongDispl<<endl;
|
|
cout<<"SupportType = "<<SupportType<<endl;
|
|
cout<<"SupportId = "<<SupportId<<endl;
|
|
cout<<"PatientOrientation = "<<PatientOrientation<<endl;
|
|
|
|
if(NumberOfBeams > 0)
|
|
for(const auto& b : Beams)
|
|
if(b) b->PrintSelf();
|
|
}
|
|
|
|
bool RTPlan::fillRTPlan(const char *filertionplan){
|
|
|
|
LastError.clear();
|
|
|
|
cout<<"reading filename: "<<filertionplan<<endl;
|
|
|
|
|
|
gdcm::Reader R;
|
|
R.SetFileName(filertionplan);
|
|
if(!R.Read())
|
|
{
|
|
LastError = "Cannot read RT Plan file";
|
|
cout<<"ERROR: cannot read filertionplan."<<endl;
|
|
return false;
|
|
}
|
|
const gdcm::File &file = R.GetFile();
|
|
const gdcm::DataSet &ds = file.GetDataSet();
|
|
|
|
|
|
//GENERAL PATIENT AND STUDY DATE
|
|
//PATIENT NAME
|
|
PatientName = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0010), ds);
|
|
|
|
// // // PATIENT ID For ex: DICOM (0010,0020) = 1933197
|
|
PatientID = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0020), ds);
|
|
// //
|
|
// // // PATIENT AGE For ex: DICOM (0010,1010) = 031Y
|
|
PatientAge = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x1010), ds);
|
|
// //
|
|
// // // PATIENT SEX For ex: DICOM (0010,0040) = M
|
|
PatientSex = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0040), ds);
|
|
// //
|
|
// // // PATIENT BIRTHDATE For ex: DICOM (0010,0030) = 19680427
|
|
PatientBirthDate = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0030), ds);
|
|
// //
|
|
// // // SERIES NUMBER For ex: DICOM (0020,0011) = 902
|
|
SeriesNumber = gGetStringValueFromTagStr(gdcm::Tag(0x0020,0x0011), ds);
|
|
// //
|
|
// // // SERIES DESCRIPTION For ex: DICOM (0008,103e) = SCOUT
|
|
SeriesDescription = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x103e), ds);
|
|
// //
|
|
// // // STUDY ID For ex: DICOM (0020,0010) = 37481
|
|
StudyID = gGetStringValueFromTagStr(gdcm::Tag(0x0020,0x0010), ds);
|
|
// //
|
|
// // // STUDY DESCRIPTION For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL
|
|
StudyDescription = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x1030), ds);
|
|
// //
|
|
// // // STUDY MODALITY For ex: DICOM (0008,0060)= CT
|
|
Modality = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x0060), ds);
|
|
|
|
|
|
//TREATMENT GEOMETRY
|
|
//IONI 0x300a,0x00b0
|
|
// radiation 0x300ax00c6
|
|
//FIND TAG BEAMSequence
|
|
//v04Build27 HANDLE PROTON vs CARBONION
|
|
bool IsCarbon=false;
|
|
//v04Build27 CHECK EXISTANCE SETUP SEQUENCE (PRESENT IN PROTN ABSENT IN IONS)
|
|
if(!ds.FindDataElement(gdcm::Tag(0x300a,0x03a2)))
|
|
IsCarbon=true;
|
|
|
|
|
|
|
|
//QUI HFP vs HFS
|
|
//v04 Build29: LOOK FOR SETUP SEQUENCE TO SEARHC FOR PATINET ORIENTATION
|
|
// Patient orientation comes from Patient Setup Sequence, when present.
|
|
PatientOrientation.clear();
|
|
if (ds.FindDataElement(gdcm::Tag(0x300a,0x0180)))
|
|
{
|
|
const gdcm::DataElement &gSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180));
|
|
gdcm::SmartPointer<gdcm::SequenceOfItems> sqiPS = gSetupSequence.GetValueAsSQ();
|
|
if (sqiPS && sqiPS->GetNumberOfItems() >= 1)
|
|
{
|
|
const gdcm::DataSet& gPatSetupNest = sqiPS->GetItem(1).GetNestedDataSet();
|
|
PatientOrientation = gGetStringValueFromTagStr(gdcm::Tag(0x0018, 0x5100), gPatSetupNest);
|
|
}
|
|
}
|
|
|
|
const gdcm::DataElement &gBeamSequence=ds.GetDataElement(gdcm::Tag(0x300a,(IsCarbon==false ? 0x03a2 : 0x00b0)));
|
|
// (THESE ARE THE BEAMS)
|
|
gdcm::SmartPointer<gdcm::SequenceOfItems> sqi = gBeamSequence.GetValueAsSQ();
|
|
if(!sqi || !sqi->GetNumberOfItems())
|
|
{
|
|
LastError = "Beam sequence not found in RT Plan file";
|
|
cout<<"usteria" <<endl;
|
|
return false;
|
|
}
|
|
const int expectedBeams = static_cast<int>(sqi->GetNumberOfItems());
|
|
NumberOfBeams = expectedBeams;
|
|
|
|
// Own and manage beams with RAII.
|
|
Beams.clear();
|
|
Beams.reserve(static_cast<size_t>(expectedBeams));
|
|
|
|
//ITERATES ON BEAM NUMBER
|
|
for(int i = 0; i < expectedBeams; i++)
|
|
{
|
|
const gdcm::Item & item = sqi->GetItem(i+1); //ITEM START FROM 1
|
|
const gdcm::DataSet& gBeamNestedds = item.GetNestedDataSet(); //THIS IS BEAM DATASET
|
|
|
|
auto beam = std::make_unique<IonBeamProperties>();
|
|
IonBeamProperties* b = beam.get();
|
|
|
|
//READ BEAM DATA
|
|
b->BeamNumber = GetTagIntOr(gdcm::Tag(0x300a, 0x00c0), gBeamNestedds, 0);
|
|
b->BeamName = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x00c2), gBeamNestedds);
|
|
|
|
if(IsCarbon == false)
|
|
b->SupportType = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x0350), gBeamNestedds);
|
|
else
|
|
b->SupportType = "TABLE";
|
|
|
|
b->SupportId = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x0352), gBeamNestedds);
|
|
|
|
//gBeams[i]->gSetSupportType("CHAIR");
|
|
|
|
//READ GEOMETRY
|
|
//READ SEQUENCE OF CONTROL POINTS
|
|
//v04Build27 DO DIFFERENTLY IF PROTONS OR CARBONS
|
|
const gdcm::Tag cpTag(0x300a, IsCarbon==false ? 0x03a8 : 0x0111);
|
|
if (!gBeamNestedds.FindDataElement(cpTag))
|
|
{
|
|
// Skip this beam if control points are missing.
|
|
continue;
|
|
}
|
|
const gdcm::DataElement &gCPSequence=gBeamNestedds.GetDataElement(cpTag);
|
|
gdcm::SmartPointer<gdcm::SequenceOfItems> sqicp = gCPSequence.GetValueAsSQ();
|
|
if (!sqicp || sqicp->GetNumberOfItems() < 1)
|
|
{
|
|
continue;
|
|
}
|
|
const gdcm::DataSet& gCPNestedds = sqicp->GetItem(1).GetNestedDataSet();
|
|
|
|
//GANTRY ANGLE (NEEDED FOR CHAIR ?)
|
|
b->GantryAngle = GetTagIntOr(gdcm::Tag(0x300a, 0x011e), gCPNestedds, 0);
|
|
|
|
// ISOCENTER POSITION (this is beam position, not patient/volume center).
|
|
// DICOM tag (300A,012C) is a multi-value DS string: "x\\y\\z".
|
|
{
|
|
const std::string isoStr = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x012c), gCPNestedds);
|
|
const auto iso = Parse3Doubles(isoStr);
|
|
b->IsocenterPosition[0] = iso[0];
|
|
b->IsocenterPosition[1] = iso[1];
|
|
b->IsocenterPosition[2] = iso[2];
|
|
}
|
|
// Beams[i]->IsocenterPosition[](iso[0],iso[1],iso[2]);
|
|
|
|
//SUPPORT ANGLE (YAW ANGLE OF SUPPORT WITH RESPECT TO FIXED REFERENCE SYSTEM) AROUND Z AXIS (VERTICAL)
|
|
//POSITIVE COUNTER-CLOCKWISE WHEN VIEWED FROM TOP OF Z-Axis
|
|
b->TableYawAngle = static_cast<float>(GetTagDoubleOr(gdcm::Tag(0x300a, 0x0122), gCPNestedds, 0.0));
|
|
/*if(i==1)
|
|
gBeams[i]->gSetTableYawAngle(0);
|
|
*/
|
|
//TABLE TOP PITCH (ROTATION AROUND X AXIS, i.e. LATERAL AXIS OF TABLE AND BEAM DIRECTION IN FIXED REF SYS)
|
|
////v04Build27 IF PROTONS READ IT FROM PLAN; IF CARBONS SET DEFAULT VALUE (0.0) AND FORGET CHAIR
|
|
if(IsCarbon==false)
|
|
{ gdcm::Attribute <0x300a, 0x0140> pa;
|
|
pa.SetFromDataElement(gCPNestedds.GetDataElement( pa.GetTag()));
|
|
b->TablePitchAngle = pa.GetValue();
|
|
}
|
|
else
|
|
b->TablePitchAngle = 0.0;
|
|
|
|
//v04 Build23 SET SUPPORT TYPE CORRECTLY IF PITCH IS 90 (IT IS CHAIR); DO IT FOR ALL BEAMS
|
|
// if(i==0)
|
|
// { if(Beams[i]->TablePitchAngle()>45)
|
|
// strcpy (Beams[i]->SupportType,("CHAIR"));
|
|
// }
|
|
// else if (i>0)
|
|
// { if(Beams[0]->SupportChair()==true)
|
|
// Beams[i]->gSetSupportType("CHAIR");
|
|
// }
|
|
|
|
//TABLE TOP ROLL (ROTATION AROUND Y AXIS, i.e. LONGITUDINAL AXIS OF TABLE)
|
|
//v04Build27 IF PROTONS READ IT FROM PLAN; IF CARBONS SET DEFAULT VALUE (0.0)
|
|
if(IsCarbon==false)
|
|
{ gdcm::Attribute <0x300a, 0x0144> ra;
|
|
ra.SetFromDataElement(gCPNestedds.GetDataElement(ra.GetTag()));
|
|
b->TableRollAngle = ra.GetValue();
|
|
}
|
|
else
|
|
b->TableRollAngle = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
//WHAT ABOUT TABLE TOP VERTICAL POSITION, LOGITUDINAL AND LATERAL POSITION ? USEFUL SOMEHOW ?
|
|
// THEY ARE READ AND USED TO REALIZE VOLUME CENTER ALIGNMENT IN ROOM ISOCENTER
|
|
//FIND PATIENT SETUP SEQUENCE (IT IS UNIQUE FOR ALL BEAMS BUT I DO IT BEAM BY BEAM)
|
|
//v04Build27 DO NOT LOOK FOR PATIENT SETUPSEQUENCE
|
|
/* if(!ds.FindDataElement(gdcm::Tag(0x300a,0x0180)))
|
|
throw(gException("CRITICAL: PATIENT SETUP SEQUENCE NOT FOUND IN RT ION PLAN"));
|
|
const gdcm::DataElement &gPatientSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180));
|
|
gdcm::SmartPointer<gdcm::SequenceOfItems> sqpt = gPatientSetupSequence.GetValueAsSQ();
|
|
int psuseq=sqpt->GetNumberOfItems(); //CHECK NUMBER OF SETUPSEQUENCE VS BEAM NUMBER
|
|
|
|
//READ DATA FROM ITEM 1 OR BEAM IS MORE PATIENT SETUP SEQUENCE ARE FOUND (ATTENTION !!!!)
|
|
//v03 Build30: READ TABLE POSITIONS FROM SETUPSEQUENCE
|
|
const gdcm::DataSet& gPSNestedds = sqpt->GetItem((i+1)<=psuseq ? (i+1) : 1).GetNestedDataSet(); //IF PSTIENT SETUP SEQUENCE < THAN BEAMS USE FIRST
|
|
*/
|
|
//v04Build27 READ BEAMS ABSOLUTE GEOMETRY NOT FROM SETUP SEQUENCE BUT FROM CONTROL POINT SEQUENCE (NEW VERSION OIS FOR CARBONS)
|
|
|
|
/*float tablelat=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x01d6),gPSNestedds));
|
|
float tablelong=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x01d4),gPSNestedds));
|
|
float tablevert=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x01d2),gPSNestedds));*/
|
|
|
|
float deltatablelat = static_cast<float>(GetTagDoubleOr(gdcm::Tag(0x300a, 0x012a), gCPNestedds, 0.0));
|
|
float deltatablelong = static_cast<float>(GetTagDoubleOr(gdcm::Tag(0x300a, 0x0129), gCPNestedds, 0.0));
|
|
float deltatablevert = static_cast<float>(GetTagDoubleOr(gdcm::Tag(0x300a, 0x0128), gCPNestedds, 0.0));
|
|
|
|
//v03 (Build 30) NOW ADD TO TREATMENT BEMA EVENTUAL RELATIVE SHIFTS BETWEEN SETUP SEQUENCE AND STORE IN BEAM STRUCTURE ONLY TO TREATMETN BEAMS
|
|
// if(i==0) //THIS IS SETUP BEAM DO NOTHING
|
|
//v04Build26 TREAT ALL BEAMS THE SAME WAY (SET-UP+BEAMS)(NEW VERSION OF OIS)
|
|
//v04Build27 USE PPS GEOMETRY READ FROM POINT SEQUENCE
|
|
{ b->TableLatDispl = deltatablelat;
|
|
b->TableLongDispl = deltatablelong;
|
|
b->TableVertDispl = deltatablevert;
|
|
}
|
|
/* else
|
|
{ gBeams[i]->gSetTableLatDispl(tablelat);
|
|
gBeams[i]->gSetTableLongDispl(tablelong);
|
|
gBeams[i]->gSetTableVertDispl(tablevert);
|
|
}*/
|
|
//v04Build26 DO NOT ADD DELTASHIFTS (NEW VERSION OF OIS)
|
|
//v04Build1: CHECK FOR VIRTUAL ISO
|
|
|
|
|
|
//ADD DELTASHIFTS TO TABLE DISPLACEMENTS
|
|
//v04Build26 DO NOT ADD DELTASHIFTS (NEW VERSION OF OIS)
|
|
/*gBeams[i]->gSetTableLatDispl(tablelat+atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x012a),gCPNestedds)));
|
|
gBeams[i]->gSetTableLongDispl(tablelong+atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0129),gCPNestedds)));
|
|
gBeams[i]->gSetTableVertDispl(tablevert+atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0128),gCPNestedds)));
|
|
|
|
//UPDATE ISOCENTER POSITION ON TREATMENT BEAM USING CT REFERENCE (LONG IS Z COORDINATE; Y IS VERTICAL; Z I)
|
|
//v04Build26 DO NOT ADD DELTASHIFTS (NEW VERSION OF OIS)
|
|
|
|
gBeams[i]->gSetIsocenterPosition(iso[0]-deltatablelat,iso[1]-deltatablevert,iso[2]-deltatablelong); //SIGNS AND COORDINATE TO BE CHECKED (OK for LONG)
|
|
|
|
}
|
|
*/
|
|
|
|
//v04Build28 CORRECT ISO POSITION IN CASE OF VIRTUAL ISO
|
|
/* if(i<0) //DO THIS ONLY FOR TREATMENT BEAMS
|
|
gBeams[i]->gSetIsocenterPosition(iso[0]-(gBeams[i]->gGetTableLatDispl()-gBeams[0]->gGetTableLatDispl()),iso[1]-(gBeams[i]->gGetTableVertDispl()-gBeams[0]->gGetTableVertDispl()),iso[2]-(gBeams[i]->gGetTableLongDispl()-gBeams[0]->gGetTableLongDispl())); //SIGNS AND COORDINATE TO BE CHECKED (OK for LONG)
|
|
*/
|
|
//UPDATE AT FIRST CNAO PATIENT SET TABLE POSITION FROM PLAN AT THE ISOCENTER POSITION FOR EVERY BEAM
|
|
/* gBeams[i]->gSetTableLatDispl(gBeams[i]->gGetIsocenterPosition()[0]);
|
|
gBeams[i]->gSetTableLongDispl(gBeams[i]->gGetIsocenterPosition()[1]);gui
|
|
gBeams[i]->gSetTableVertDispl(gBeams[i]->gGetIsocenterPosition()[2]);
|
|
*/
|
|
// FILL gPPS CLASS WITH CURRENT PPS CONFIGURATION UPDATING CONVENTIONS FROM PLAN TO PPS (-90 FOR CONVENTION CT-PPS)
|
|
// Beams[i]->gGetCurrentPPS()->gSetPPSXPlan(gBeams[i]->gGetTableLatDispl());
|
|
// Beams[i]->gGetCurrentPPS()->gSetPPSYPlan(gBeams[i]->gGetTableLongDispl());
|
|
// Beams[i]->gGetCurrentPPS()->gSetPPSYOrig(gBeams[i]->gGetTableLongDispl()); //SAVE ALSO AN ORIGINAL COPY FROM PLAN OF LONGITUFINAL POSITION (FOR INDEXING DIALOG)
|
|
// Beams[i]->gGetCurrentPPS()->gSetPPSZPlan(gBeams[i]->gGetTableVertDispl());
|
|
//
|
|
|
|
|
|
//v03 Build35: ADD TO TREATMENT BEAMS YAW THE YAW VALUE OF SETUP BEAM TO RECOVER ABSOLUTE VALUES FROM RELATIVE ONES AS SENT BY OIS
|
|
if(i>0) // THIS IS TREATMENT BEAM
|
|
{ //v04Build03 SET PROPER DELTA ANGLES FOR BEAM ROTATION (IF DELTA IS NEGATIVE SET IT NEGATIVE)
|
|
double yaw = b->TableYawAngle;
|
|
if(yaw>180)
|
|
yaw=yaw-360;
|
|
//V04Build26 NEW VERSION OF MOSAIQ OIS DO NOT USE RELATIVE ANGLES
|
|
//yaw=yaw+gBeams[0]->gGetTableYawAngle();
|
|
b->TableYawAngle = yaw;
|
|
|
|
double pitch = b->TablePitchAngle;
|
|
if(pitch>180)
|
|
pitch=pitch-360;
|
|
//V04Build26 NEW VERSION OF MOSAIQ OIS DO NOT USE RELATIVE ANGLES
|
|
//pitch=pitch+gBeams[0]->gGetTablePitchAngle();
|
|
//v04Build23 SET ALL PITCH AT 90 (NOT STABLE) IT IS FOR THE CHAIR
|
|
if(pitch>150) pitch=90;
|
|
b->TablePitchAngle = pitch;
|
|
|
|
|
|
double roll = b->TableRollAngle;
|
|
if(roll>180)
|
|
roll=roll-360;
|
|
//V04Build26 NEW VERSION OF MOSAIQ OIS DO NOT USE RELATIVE ANGLES
|
|
//roll=roll+gBeams[0]->gGetTableRollAngle();
|
|
b->TableRollAngle = roll;
|
|
}
|
|
|
|
//HERE 90 DEGREES IS SUMMED IN ORDER TO SOLVE TEH AMBIGUITY BETWEEN TPS REFERENCE AND ROOM/ODEVIS REFERENCE
|
|
//0 DEGREE YAW IN TPS BECOMES +90 YAW IN ROOM/PPS MEANING BEAM IS FROM LATERAL
|
|
//THIS WE DO IT JUST FOR THE USER INTERFACE DISPLAYING DEGREES OF YAW ROTATION EXPECTED OR TO BE INSERTED IN THE PPS
|
|
//v04Build24 ADJUST PPS YAW ANGLE FOR PPS AND CHAIR
|
|
// double yaw=gBeams[0]->gIsSupportChair()==false ? gBeams[i]->gGetTableYawAngle()+90.0 : gBeams[i]->gGetTableYawAngle()-90.0;
|
|
// //NOW SET +- 180 YAW ROTATION CONVENTION
|
|
// if(yaw>180)
|
|
// yaw=yaw-360;
|
|
// gBeams[i]->gGetCurrentPPS()->gSetPPSRotateDegreePlan(yaw); //CONVERSION FROM CT BASE PLAN TO PPS (ANGLE RANGES -180 +180)
|
|
//
|
|
// //v04Build23 ATTENZIONE !
|
|
// if(gBeams[0]->gIsSupportChair()==false) gBeams[i]->gGetCurrentPPS()->gSetPPSPitchDegreePlan(gBeams[i]->gGetTablePitchAngle());
|
|
// else gBeams[i]->gGetCurrentPPS()->gSetPPSPitchDegreePlan(gBeams[i]->gGetTablePitchAngle()-90); //NEED TO SUBTRACT 90 DEGRESS FOR PPS CONFIGURATION : THERE IS THE CHAIR
|
|
//
|
|
// gBeams[i]->gGetCurrentPPS()->gSetPPSRollDegreePlan(gBeams[i]->gGetTableRollAngle());
|
|
//
|
|
//
|
|
//
|
|
// //SET CURRENT PPS CONFIGURATION WITH PLAN CONFIGURATION (THERE I TAKE CARE OF THE CHAIR)
|
|
// gBeams[i]->gGetCurrentPPS()->gSetPlanConfig();
|
|
|
|
/* //UPDATE TABLE DISPLACEMENT ACCORDING TO SIEMENS TPS USING THE ISOCENTER CO-ORDINATESIF DEFINE W.R.T. INDEXING POINT
|
|
//MIGHT NEED TO SUBTRACT COORDINATES OF STRUCTURE VOLUMECENTER IF RELATIVE REFERENCE SYSTEM IS NOT DEFINED IN TPS
|
|
gBeams[i]->gSetTableLatDispl(gBeams[i]->gGetIsocenterPosition()[0]);
|
|
gBeams[i]->gSetTableLongDispl(gBeams[i]->gGetIsocenterPosition()[1]);
|
|
gBeams[i]->gSetTableVertDispl(gBeams[i]->gGetIsocenterPosition()[2]);*/
|
|
// gBeams[i]->gSetIsocenterPosition(iso[0]- gBeams[i]->gGetCurrentPPS()->getPPSXPlan(),iso[1]- gBeams[i]->gGetCurrentPPS()->getPPSYPlan(),iso[2]- gBeams[i]->gGetCurrentPPS()->getPPSZPlan());
|
|
|
|
|
|
// Store the parsed beam.
|
|
Beams.push_back(std::move(beam));
|
|
}
|
|
|
|
// Keep legacy field in sync with actual parsed beams.
|
|
NumberOfBeams = static_cast<int>(Beams.size());
|
|
return true;
|
|
};
|