diff --git a/CMakeLists.txt b/CMakeLists.txt old mode 100755 new mode 100644 index 08d26a1..fb79746 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,132 +1,155 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.22) -IF (NOT CMAKE_BUILD_TYPE) - SET (CMAKE_BUILD_TYPE "Release" CACHE STRING - "Choose the type of build, options are: Debug Release - RelWithDebInfo MinSizeRel." FORCE) -ENDIF () - -project(gLocalize) +project(gLocalize LANGUAGES CXX) set(TRG gLocalize) - -SET(SOURCE_FILES ${CMAKE_SOURCE_DIR}) - -INCLUDE_DIRECTORIES( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${SOURCE_FILES} - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} - ${CMAKE_BINARY_DIR} - ) - - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) - -find_package(HDF5 REQUIRED COMPONENTS C CXX HL) -INCLUDE_DIRECTORIES(${HDF5_INCLUDE_DIRS}) - -find_package(Qt6Core REQUIRED) -find_package(Qt6Gui REQUIRED) -find_package(Qt6Widgets REQUIRED) -find_package(Qt6Network REQUIRED) -find_package(Qt6Xml REQUIRED) -find_package(Qt6Svg REQUIRED) - -include_directories( - ${Qt6Core_INCLUDE_DIRS} - ${Qt65Gui_INCLUDE_DIRS} - ${Qt6Widgets_INCLUDE_DIRS} - ${Qt6Network_INCLUDE_DIRS} - ${Qt6Xml_INCLUDE_DIRS} - ${Qt6Svg_INCLUDE_DIRS} - ) - - -find_package(ITK REQUIRED) -include(${ITK_USE_FILE}) -INCLUDE_DIRECTORIES(${ITK_INCLUDE_DIRS}) - -find_package(VTK REQUIRED) -INCLUDE_DIRECTORIES(${VTK_INCLUDE_DIRS}) - -FIND_PACKAGE(GDCM REQUIRED) -include(${GDCM_USE_FILE}) -INCLUDE_DIRECTORIES(${GDCM_INCLUDE_DIRS}) - - -set(SRCS - ${SOURCE_FILES}/main.cpp - ${SOURCE_FILES}/mainw.cpp - ${SOURCE_FILES}/mainw.h - ${SOURCE_FILES}/connectITKVTK.h - ${SOURCE_FILES}/dicomUtils.cpp - ${SOURCE_FILES}/dicomUtils.h - ${SOURCE_FILES}/gPatientRTGeneralInfos.h - ${SOURCE_FILES}/gRen.h - ${SOURCE_FILES}/gRen.cpp - ${SOURCE_FILES}/gLoadPatient.h - ${SOURCE_FILES}/gLoadPatient.cpp - ${SOURCE_FILES}/gLocalize.h - ${SOURCE_FILES}/gLocalize.cpp - ${SOURCE_FILES}/gSkullRemoval.h - ${SOURCE_FILES}/gSkullRemoval.cpp - ${SOURCE_FILES}/itkQtAdaptor.h - ) - -set(HDR - ${SOURCE_FILES}/mainw.h - ${SOURCE_FILES}/connectITKVTK.h - ${SOURCE_FILES}/dicomUtils.h - ${SOURCE_FILES}/gPatientRTGeneralInfos.h - ${SOURCE_FILES}/gRen.h - ${SOURCE_FILES}/gLoadPatient.h - ${SOURCE_FILES}/gLocalize.h - ${SOURCE_FILES}/gSkullRemoval.h - ${SOURCE_FILES}/itkQtAdaptor.h - ) - - -SET(RES ${PROJECT_SOURCE_DIR}/images.qrc) -QT6_ADD_RESOURCES(RES_RCC ${RES}) - - -add_executable(${TRG} - ${SRCS} - ${RES_RCC} -) - -set(GDCM_PREFIX "/usr/local/gdcm" CACHE PATH "GDCM install prefix") -set(GDCM_LIBDIR "${GDCM_PREFIX}/lib") -if(EXISTS "${GDCM_PREFIX}/lib64") - set(GDCM_LIBDIR "${GDCM_PREFIX}/lib64") +# --- Build type default --- +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() -set_property(TARGET gLocalize PROPERTY BUILD_RPATH "${GDCM_LIBDIR}") -set_property(TARGET gLocalize PROPERTY INSTALL_RPATH "${GDCM_LIBDIR}") +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) -target_link_options(gLocalize PRIVATE "-Wl,-rpath,/usr/local/gdcm/lib") +# Qt: enable automoc/uic/rcc +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) -target_link_libraries(${TRG} - PRIVATE - Qt6::Network +# Prefer sane RPATH behavior without hardcoding /usr/local paths. +# If dependencies are properly installed in system paths, no RPATH is needed. +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +set(CMAKE_BUILD_RPATH_USE_ORIGIN TRUE) + +# --- Dependencies --- +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets Network Xml Svg) + +# HDF5: use imported targets if provided, otherwise fall back to variables. +find_package(HDF5 REQUIRED COMPONENTS C CXX HL) + +# ITK config package generally exports ITK_LIBRARIES as imported targets. +find_package(ITK REQUIRED) + +# VTK: list the modules actually used by the code (Qt widget + volume rendering + widgets + imaging). +find_package(VTK REQUIRED + COMPONENTS + CommonCore + CommonDataModel + CommonTransforms + FiltersCore + FiltersGeneral + FiltersGeometry + FiltersModeling + FiltersSources + ImagingCore + ImagingGeneral + ImagingHybrid + InteractionStyle + InteractionWidgets + RenderingCore + RenderingOpenGL2 + RenderingVolumeOpenGL2 + RenderingAnnotation + RenderingFreeType + RenderingImage + RenderingQt +) + +# GDCM: prefer config targets when available. +find_package(GDCM REQUIRED) + +# --- Sources --- +set(SRCS + main.cpp + mainw.cpp + dicomUtils.cpp + gRen.cpp + gLoadPatient.cpp + gLocalize.cpp + gSkullRemoval.cpp +) + +set(HDR + mainw.h + connectITKVTK.h + dicomUtils.h + gPatientRTGeneralInfos.h + gRen.h + gLoadPatient.h + gLocalize.h + gSkullRemoval.h + itkQtAdaptor.h +) + +qt_add_resources(RES_RCC images.qrc) + +add_executable(${TRG} + ${SRCS} + ${HDR} + ${RES_RCC} +) + +target_compile_definitions(${TRG} PRIVATE QT_NO_KEYWORDS) + +target_include_directories(${TRG} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +# --- Link libraries --- +target_link_libraries(${TRG} + PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network + Qt6::Xml Qt6::Svg - ${VTK_LIBRARIES} - ${ITK_LIBRARIES} - ${GDCM_LIBRARIES} - m - ${HDF5_CXX_LIBRARIES} - ${HDF5_LIBRARIES} - ) +# ITK: imported targets are typically in ITK_LIBRARIES +if(DEFINED ITK_LIBRARIES) + target_link_libraries(${TRG} PRIVATE ${ITK_LIBRARIES}) +endif() +# VTK +target_link_libraries(${TRG} PRIVATE ${VTK_LIBRARIES}) +# VTK module auto-init (needed especially when VTK is built static or with some build options) +if(COMMAND vtk_module_autoinit) + vtk_module_autoinit( + TARGETS ${TRG} + MODULES ${VTK_LIBRARIES} + ) +endif() +# GDCM (prefer targets; otherwise fallback to variables) +if(TARGET GDCM::gdcmMSFF) + target_link_libraries(${TRG} PRIVATE GDCM::gdcmMSFF) +elseif(DEFINED GDCM_LIBRARIES) + target_link_libraries(${TRG} PRIVATE ${GDCM_LIBRARIES}) +endif() +# HDF5 (prefer targets; otherwise fallback to variables) +if(TARGET hdf5::hdf5_cpp) + target_link_libraries(${TRG} PRIVATE hdf5::hdf5_cpp) +endif() +if(TARGET hdf5::hdf5_hl_cpp) + target_link_libraries(${TRG} PRIVATE hdf5::hdf5_hl_cpp) +endif() +if(DEFINED HDF5_LIBRARIES) + target_link_libraries(${TRG} PRIVATE ${HDF5_LIBRARIES}) +endif() +if(DEFINED HDF5_CXX_LIBRARIES) + target_link_libraries(${TRG} PRIVATE ${HDF5_CXX_LIBRARIES}) +endif() + +# math lib (Linux) +target_link_libraries(${TRG} PRIVATE m) + +# Helpful warnings (tweak as you like) +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + target_compile_options(${TRG} PRIVATE -Wall -Wextra -Wpedantic) +endif() diff --git a/connectITKVTK.h b/connectITKVTK.h old mode 100755 new mode 100644 diff --git a/dicomUtils.cpp b/dicomUtils.cpp old mode 100755 new mode 100644 index b33d25b..2784a87 --- a/dicomUtils.cpp +++ b/dicomUtils.cpp @@ -1,26 +1,118 @@ #include "dicomUtils.h" +#include +#include +#include + +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 Parse3Doubles(const std::string& s) +{ + std::array 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(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) +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 = ""; // cleanup previous call - if( ds.FindDataElement( t ) ) - { - const gdcm::DataElement& de = ds.GetDataElement( t ); - const gdcm::ByteValue *bv = de.GetByteValue(); - if( bv ) // Can be Type 2 - { - buffer = std::string( bv->GetPointer(), bv->GetLength() ); - // Will be padded with at least one \0 - } - } - // Since return is a const char* the very first \0 will be considered + 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) @@ -55,27 +147,20 @@ int gCheckDICOMModalityToInt(const char *filename){ -IonBeamProperties::IonBeamProperties(){ - BeamNumber = BADVALUE; - BeamName = new char [MAXSTRINGLENGHT]; - SupportId = new char [MAXSTRINGLENGHT]; - SupportType = new char [MAXSTRINGLENGHT]; - GantryAngle = BADVALUE; - IsocenterPosition = new double [3]; - TablePitchAngle= BADVALUE; +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; - -} - -IonBeamProperties::~IonBeamProperties(){ -delete[] BeamName; -delete[] SupportId; -delete[] IsocenterPosition; -delete[] SupportType; + TableYawAngle = BADVALUE; + TableLatDispl = BADVALUE; + TableLongDispl = BADVALUE; + TableVertDispl = BADVALUE; } @@ -86,9 +171,9 @@ void IonBeamProperties::PrintSelf(){ cout<<" |_ SupportType = " < sqiPS = gSetupSequence.GetValueAsSQ(); - const gdcm::DataSet& gPatSetupNest = sqiPS->GetItem(1).GetNestedDataSet(); - //SET PATIENT ORIENTATION STRING - strcpy(PatientOrientation, gGetStringValueFromTag(gdcm::Tag(0x0018, 0x5100),gPatSetupNest)); + // 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 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 sqi = gBeamSequence.GetValueAsSQ(); if(!sqi || !sqi->GetNumberOfItems()) { - cout<<"usteria" <GetNumberOfItems(); - //ALLOCATE BEAM STRUCTURES - Beams=new IonBeamProperties* [NumberOfBeams]; - //memset(Beams,NULL,NumberOfBeams*sizeof(IonBeamProperties *)); - memset(Beams, 0, NumberOfBeams * sizeof(IonBeamProperties*)); + const int expectedBeams = static_cast(sqi->GetNumberOfItems()); + NumberOfBeams = expectedBeams; + + // Own and manage beams with RAII. + Beams.clear(); + Beams.reserve(static_cast(expectedBeams)); //ITERATES ON BEAM NUMBER - for(int i=0;iGetItem(i+1); //ITEM START FROM 1 + 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 - //ALLOCATE BEAM CLASS - Beams[i]=new IonBeamProperties; + auto beam = std::make_unique(); + IonBeamProperties* b = beam.get(); + //READ BEAM DATA - Beams[i]->BeamNumber = (atoi(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x00c0),gBeamNestedds))); //BEAM NUMBER - strcpy (Beams[i]->BeamName,(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x00c2),gBeamNestedds))); //BEAM NAME + b->BeamNumber = GetTagIntOr(gdcm::Tag(0x300a, 0x00c0), gBeamNestedds, 0); + b->BeamName = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x00c2), gBeamNestedds); - if(IsCarbon==false) - strcpy (Beams[i]->SupportType,gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0350),gBeamNestedds));//PATIENT SUPPORT TYPE IMPLEMENT TRICK FOR THE CHAIR - else strcpy(Beams[i]->SupportType,"TABLE"); + if(IsCarbon == false) + b->SupportType = gGetStringValueFromTagStr(gdcm::Tag(0x300a, 0x0350), gBeamNestedds); + else + b->SupportType = "TABLE"; - strcpy(Beams[i]->SupportId,gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0352),gBeamNestedds));//PATIENT SUPPORT TYPE IMPLEMENT TRICK FOR THE CHAIR + 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::DataElement &gCPSequence=gBeamNestedds.GetDataElement(gdcm::Tag(0x300a,IsCarbon==false ? 0x03a8 : 0x0111)); - //FIND ITEM SEQUENCE (THESE ARE THE CONTROL POINTS) + 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 sqicp = gCPSequence.GetValueAsSQ(); - - //READ DATA FROM ITEM 1 + if (!sqicp || sqicp->GetNumberOfItems() < 1) + { + continue; + } const gdcm::DataSet& gCPNestedds = sqicp->GetItem(1).GetNestedDataSet(); //GANTRY ANGLE (NEEDED FOR CHAIR ?) - Beams[i]->GantryAngle=atoi(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x011e),gCPNestedds)); + b->GantryAngle = GetTagIntOr(gdcm::Tag(0x300a, 0x011e), gCPNestedds, 0); - //ISOCENTER POSITION (THIS IS BEAM POSITION NOT PATIENT ALIGNMENT (VOLUME CENTER) POSITION) - double iso[3]; - char str[MAXSTRINGLENGHT]; - strcpy(str,gGetStringValueFromTag(gdcm::Tag(0x300a, 0x012c),gCPNestedds)); - - Beams[i]->IsocenterPosition[0]=atof(strtok(str,"\\")); - Beams[i]->IsocenterPosition[1]=atof(strtok(NULL,"\\")); - Beams[i]->IsocenterPosition[2]=atof(strtok(NULL,"\\")); + // 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 - Beams[i]->TableYawAngle=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0122),gCPNestedds)); + b->TableYawAngle = static_cast(GetTagDoubleOr(gdcm::Tag(0x300a, 0x0122), gCPNestedds, 0.0)); /*if(i==1) gBeams[i]->gSetTableYawAngle(0); */ @@ -322,10 +408,10 @@ RTPlan::~RTPlan(){ if(IsCarbon==false) { gdcm::Attribute <0x300a, 0x0140> pa; pa.SetFromDataElement(gCPNestedds.GetDataElement( pa.GetTag())); - Beams[i]->TablePitchAngle =pa.GetValue(); + b->TablePitchAngle = pa.GetValue(); } else - (Beams[i]->TablePitchAngle)=(0.0); + 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) @@ -342,10 +428,10 @@ RTPlan::~RTPlan(){ if(IsCarbon==false) { gdcm::Attribute <0x300a, 0x0144> ra; ra.SetFromDataElement(gCPNestedds.GetDataElement(ra.GetTag())); - Beams[i]->TableRollAngle =(ra.GetValue()); + b->TableRollAngle = ra.GetValue(); } else - (Beams[i]->TableRollAngle)=(0.0); + b->TableRollAngle = 0.0; @@ -371,17 +457,17 @@ RTPlan::~RTPlan(){ float tablelong=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x01d4),gPSNestedds)); float tablevert=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x01d2),gPSNestedds));*/ - float deltatablelat=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x012a),gCPNestedds)); - float deltatablelong=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0129),gCPNestedds)); - float deltatablevert=atof(gGetStringValueFromTag(gdcm::Tag(0x300a, 0x0128),gCPNestedds)); + float deltatablelat = static_cast(GetTagDoubleOr(gdcm::Tag(0x300a, 0x012a), gCPNestedds, 0.0)); + float deltatablelong = static_cast(GetTagDoubleOr(gdcm::Tag(0x300a, 0x0129), gCPNestedds, 0.0)); + float deltatablevert = static_cast(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 - { Beams[i]->TableLatDispl=(deltatablelat); - Beams[i]->TableLongDispl=(deltatablelong); - Beams[i]->TableVertDispl=(deltatablevert); + { b->TableLatDispl = deltatablelat; + b->TableLongDispl = deltatablelong; + b->TableVertDispl = deltatablevert; } /* else { gBeams[i]->gSetTableLatDispl(tablelat); @@ -426,29 +512,29 @@ RTPlan::~RTPlan(){ //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=Beams[i]->TableYawAngle; + 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(); - Beams[i]->TableYawAngle=(yaw); + b->TableYawAngle = yaw; - double pitch=Beams[i]->TablePitchAngle; + 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; - Beams[i]->TablePitchAngle=(pitch); + b->TablePitchAngle = pitch; - double roll=Beams[i]->TableRollAngle; + 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(); - Beams[i]->TableRollAngle=(roll); + b->TableRollAngle = roll; } //HERE 90 DEGREES IS SUMMED IN ORDER TO SOLVE TEH AMBIGUITY BETWEEN TPS REFERENCE AND ROOM/ODEVIS REFERENCE @@ -480,6 +566,11 @@ RTPlan::~RTPlan(){ // gBeams[i]->gSetIsocenterPosition(iso[0]- gBeams[i]->gGetCurrentPPS()->getPPSXPlan(),iso[1]- gBeams[i]->gGetCurrentPPS()->getPPSYPlan(),iso[2]- gBeams[i]->gGetCurrentPPS()->getPPSZPlan()); - } - return true; + // Store the parsed beam. + Beams.push_back(std::move(beam)); + } + + // Keep legacy field in sync with actual parsed beams. + NumberOfBeams = static_cast(Beams.size()); + return true; }; diff --git a/dicomUtils.h b/dicomUtils.h old mode 100755 new mode 100644 index cbfdd3c..d50fa4b --- a/dicomUtils.h +++ b/dicomUtils.h @@ -11,7 +11,12 @@ #include #include -using namespace std; +#include +#include +#include +#include + +// Avoid `using namespace` in headers; keep symbols qualified. #define MAXSTRINGLENGHT 255 #define BADVALUE -9999 @@ -23,7 +28,10 @@ enum{ NODCMFILE }; +// Legacy helper: returns a pointer to an internal static buffer. +// Prefer gGetStringValueFromTagStr() in new code. const char *gGetStringValueFromTag(const gdcm::Tag& t, const gdcm::DataSet& ds); +std::string gGetStringValueFromTagStr(const gdcm::Tag& t, const gdcm::DataSet& ds); const char * gCheckDICOMModality(const char *filename); int gCheckDICOMModalityToInt(const char *filename); @@ -32,20 +40,20 @@ class IonBeamProperties{ public: IonBeamProperties(); -~IonBeamProperties(); +~IonBeamProperties() = default; -int BeamNumber; -char* BeamName; -char* SupportType; -char* SupportId; -int GantryAngle; -double* IsocenterPosition; -float TableYawAngle; -float TablePitchAngle; -float TableRollAngle; -float TableLatDispl; -float TableLongDispl; -float TableVertDispl; +int BeamNumber; +std::string BeamName; +std::string SupportType; +std::string SupportId; +int GantryAngle; +std::array IsocenterPosition; +float TableYawAngle; +float TablePitchAngle; +float TableRollAngle; +float TableLatDispl; +float TableLongDispl; +float TableVertDispl; void PrintSelf(); }; @@ -55,41 +63,45 @@ void PrintSelf(); class RTPlan { public: - char* PatientName; - char* PatientID; - char* PatientSex; - char* PatientAge; - char* PatientBirthDate; - char* SeriesNumber; - char* SeriesDescription; - char* StudyID; - char* StudyDescription; - char* Modality; + std::string PatientName; + std::string PatientID; + std::string PatientSex; + std::string PatientAge; + std::string PatientBirthDate; + std::string SeriesNumber; + std::string SeriesDescription; + std::string StudyID; + std::string StudyDescription; + std::string Modality; - double* IsocenterPosition; - double* VolumeCenter; - int BeamNumber; - char* BeamName; - double TableRollAngle; - double TableYawAngle; - double TablePitchAngle; - double TableLatDispl; - double TableVertDispl; - double TableLongDispl; - char* SupportType; - char* SupportId; - char* PatientOrientation; - int NumberOfBeams; + std::array IsocenterPosition; + std::array VolumeCenter; + int BeamNumber; + std::string BeamName; + double TableRollAngle; + double TableYawAngle; + double TablePitchAngle; + double TableLatDispl; + double TableVertDispl; + double TableLongDispl; + std::string SupportType; + std::string SupportId; + std::string PatientOrientation; + int NumberOfBeams; - IonBeamProperties** Beams; + // Owns all beams. + std::vector> Beams; + + // Last error message set by fillRTPlan() when it returns false. + std::string LastError; - ~RTPlan(); + ~RTPlan() = default; RTPlan(); void PrintSelf(); - bool fillRTPlan( char *filertionplan); + bool fillRTPlan(const char *filertionplan); }; #endif \ No newline at end of file diff --git a/gLoadPatient.cpp b/gLoadPatient.cpp old mode 100755 new mode 100644 index 25bd8d7..e4edba7 --- a/gLoadPatient.cpp +++ b/gLoadPatient.cpp @@ -1,436 +1,441 @@ -#include "gLoadPatient.h" - - -/*_________________________________________________________- - -Patient loader for gLocalize. -no wrkDir behaviour. just load data -____________________________________________________________*/ - - -gLoadPatient::gLoadPatient(){ - patientInfos = new gPatientRTGeneralInfos; - readRT=0; - m_rtIsocenter=0; - initialized=false; - virtualIso=false; - //cout<< "gLoadPatient::gLoadPatient" <parse(p_loadDir); - - if(patientInfos->CTfiles .size()!=0){ - cout<< "this->load2VTK(patientInfos)" <rtIonPlanPath.isEmpty()){ - readRT = new RTPlan; - readRT->fillRTPlan(patientInfos->rtIonPlanPath.toLatin1().data() ); - m_rtIsocenter = new double[3]; - if (readRT->NumberOfBeams > 0){ - memcpy(m_rtIsocenter, readRT->Beams[0]->IsocenterPosition, 3* sizeof(double) ); - if (strncmp (readRT->PatientOrientation,"HFS",3) == 0 ) - m_patientOrientation = SUPINE; - else if (strncmp (readRT->PatientOrientation,"HFP",3) == 0 ) - m_patientOrientation = PRONE; - else m_patientOrientation = NOTDEFINED; - - emit loadedRTIso(m_rtIsocenter); - //for (int ii=0;iiNumberOfBeams; ii++){ - // cout<< readRT->Beams[ii]->IsocenterPosition[0]<<" "; - // cout<< readRT->Beams[ii]->IsocenterPosition[1]<<" "; - // cout<< readRT->Beams[ii]->IsocenterPosition[2]<<" "<NumberOfBeams <Beams[0]->IsocenterPosition[0] <Beams[2]->IsocenterPosition[0]<Beams[0]->IsocenterPosition[1] <Beams[2]->IsocenterPosition[1]<Beams[0]->IsocenterPosition[2] <Beams[2]->IsocenterPosition[2]<NumberOfBeams > 2 && - (readRT->Beams[0]->IsocenterPosition[0] != readRT->Beams[2]->IsocenterPosition[0] || - readRT->Beams[0]->IsocenterPosition[1] != readRT->Beams[2]->IsocenterPosition[1] || - readRT->Beams[0]->IsocenterPosition[2] != readRT->Beams[2]->IsocenterPosition[2]) - ) - virtualIso=true; - else - virtualIso=false; - //cout << "virtual Iso: "<loadDICOM(patientInfos->CTfiles); - this->connectToVTK(); -// this->changeRef(GOTSREF); - /* use DCM as default */ - this->changeRef(DCMREF); - //trueOffset_rot_prev=trueOffset_rot; - - - //this->load2VTK(patientInfos); - } else { - //DO NOTHING. THE folderisempty signal was already emitted. - } - cout<< " gLoadPatient::load _ END" <SetDirection( /*imageDir*/directionToWCS ); - myImage->SetOrigin( trueOffset_rot ); - myImage->Update(); - - in->SetInput(myImage); - this->connectToVTK(); - this->actualizeOut(); - - /*calculate deltas for marker representation update*/ - if(initialized){ - emit referenceChange( - trueOffset_rot_prev[0]-trueOffset_rot[0], - trueOffset_rot_prev[1]-trueOffset_rot[1], - trueOffset_rot_prev[2]-trueOffset_rot[2]); - trueOffset_rot_prev=trueOffset_rot; - } else { - trueOffset_rot_prev=trueOffset_rot; - initialized=true; - } - -} - -void gLoadPatient::loadDICOM(std::vector CTfilenames){ - - myImage = myImageType::New(); - rDICOM = itk::ImageSeriesReader::New(); - iGDCMimage = itk::GDCMImageIO::New(); - myDICOMseries = itk::GDCMSeriesFileNames::New(); - - rDICOM->SetImageIO(iGDCMimage); - rDICOM->SetFileNames(CTfilenames); - // rDICOM->SetReverseOrder(true); - try{ - rDICOM->Update(); - } - catch (itk::ExceptionObject &ex){ - std::cout << ex << std::endl; - return; // error! - } - - myImage=rDICOM->GetOutput(); - imageDir = myImage->GetDirection( ); - origin = myImage->GetOrigin( ); - sizeOfImage = myImage->GetLargestPossibleRegion().GetSize(); - -} - -void gLoadPatient::connectToVTK(){ - - - out = vtkSmartPointer::New(); - - in = itk::VTKImageExport ::New(); - in->SetInput(myImage); - - out->SetUpdateInformationCallback(in->GetUpdateInformationCallback()); - out->SetPipelineModifiedCallback(in->GetPipelineModifiedCallback()); - out->SetWholeExtentCallback(in->GetWholeExtentCallback()); - out->SetSpacingCallback(in->GetSpacingCallback()); - out->SetOriginCallback(in->GetOriginCallback()); - out->SetScalarTypeCallback(in->GetScalarTypeCallback()); - out->SetNumberOfComponentsCallback(in->GetNumberOfComponentsCallback()); - out->SetPropagateUpdateExtentCallback(in->GetPropagateUpdateExtentCallback()); - out->SetUpdateDataCallback(in->GetUpdateDataCallback()); - out->SetDataExtentCallback(in->GetDataExtentCallback()); - out->SetBufferPointerCallback(in->GetBufferPointerCallback()); - out->SetCallbackUserData(in->GetCallbackUserData()); - -} - -void gLoadPatient::actualizeOut(){ - - //in->Update(); - out->Update(); - //vol3D = vtkSmartPointer ::New(); - //vol3D->DeepCopy(out->GetOutput()); - //vol3D->Update(); - vol3D = out->GetOutput(); - cout<GetSpacing()[0] <<" "<GetSpacing()[1] <<" "<GetSpacing()[2] <clearInfo() " <clearInfo(); - - std::cout<<"parsing dir: "<c_str()).fileName().split(".").last() != QString("raw") ) - patientInfos->filenames.push_back( it->c_str() ); - } - patientInfos->filenames.size() == 0 ? result = PARSER_FOLDER_EMPTY : result = NOERRORS; - } else { - result=PARSER_FOLDER_NOTEXISTING; - }; - - cout << " patientInfos->filenames.size() "<filenames.size() <filenames.size()-1);i>-1;i--) - { - //cout << gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) <SetFileName (patientInfos->filenames.at(i).c_str()); - - if( !fileReader->Read() ) { - cout<< "Error reading file: "<< patientInfos->filenames.at(i).data() <filenames.erase(patientInfos->filenames.begin()+i); - continue; - } - - //msStructRTIonPlan.SetFromFile( fileReader->GetFile() ); - //if( msStructRTIonPlan == gdcm::MediaStorage::RTIonPlanStorage ) - if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTPLAN ) - { - if(!patientInfos->rtIonPlanPath.isEmpty()) { -// result=PARSER_RTPLAN_NOTUNIQUE; - continue; - } else { - const gdcm::File &file = fileReader->GetFile(); - const gdcm::DataSet &ds = file.GetDataSet(); - //PATIENT NAME - strcpy( patientInfos->PatientName,gGetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds)); - // // // PATIENT ID For ex: DICOM (0010,0020) = 1933197 - strcpy( patientInfos->PatientID , gGetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds)); - // // // PATIENT AGE For ex: DICOM (0010,1010) = 031Y - strcpy( patientInfos->PatientAge , gGetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds)) ; - // // // PATIENT SEX For ex: DICOM (0010,0040) = M - strcpy( patientInfos->PatientSex, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds) ); - // // // PATIENT BIRTHDATE For ex: DICOM (0010,0030) = 19680427 - strcpy( patientInfos->PatientBirthDate, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds) ); - // // // SERIES NUMBER For ex: DICOM (0020,0011) = 902 - strcpy( patientInfos->SeriesNumber, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds) ); - // // // SERIES DESCRIPTION For ex: DICOM (0008,103e) = SCOUT - strcpy( patientInfos->SeriesDescription , gGetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds) ); - // // // STUDY ID For ex: DICOM (0020,0010) = 37481 - strcpy( patientInfos->StudyID, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds) ); - // // // STUDY DESCRIPTION For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL - strcpy( patientInfos->StudyDescription, gGetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds) ); - - const gdcm::DataElement &gSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180)); - //LOOK FOR PATIENT ORIENTATION - gdcm::SmartPointer sqiPS = gSetupSequence.GetValueAsSQ(); - const gdcm::DataSet& gPatSetupNest = sqiPS->GetItem(1).GetNestedDataSet(); - //SET PATIENT ORIENTATION STRING - strcpy(patientInfos->PatientOrientation, gGetStringValueFromTag(gdcm::Tag(0x0018, 0x5100),gPatSetupNest)); - - - - patientInfos->rtIonPlanPath=QString(patientInfos->filenames.at(i).c_str()); - cout<< "RTPlan import success" <filenames.erase(patientInfos->filenames.begin()+i); - delete fileReader; - continue; - } - } - - // msStructRTStruct.SetFromFile( fileReader->GetFile() ); - // if( msStructRTStruct == gdcm::MediaStorage::RTStructureSetStorage ) { - if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTSTRUCT ){ - if(!patientInfos->rtStructurePath.isEmpty()) { - patientInfos->rtStructurePath.clear(); -// result=PARSER_RTSTRUCT_NOTUNIQUE; - continue; - } else { - patientInfos->rtStructurePath=QString(patientInfos->filenames.at(i).c_str()); - cout<< "RTStruct import success" <filenames.erase(patientInfos->filenames.begin()+i); - delete fileReader; - continue; - } - } - delete fileReader; - } - - - //OK - //if(result == NOERRORS && patientInfos->rtIonPlanPath.isEmpty() ) - // result= PARSER_RTPLAN_MISSING; - //if(result == NOERRORS && patientInfos->rtStructurePath.isEmpty()) - // result=PARSER_RTSTRUCT_MISSING; - - s.SetComputeZSpacing( true ); - s.SetZSpacingTolerance( 1e-2 ); - - if(result==NOERRORS) - if(!s.Sort( patientInfos->filenames ) ) { - result=PARSER_CT_FAILED_SORTING; - } else { - s.GetFilenames().size() == 0 ? result = PARSER_CT_FILES_MISSING : result=NOERRORS; - } - - if(result == NOERRORS){ - patientInfos->CTfiles=s.GetFilenames (); - //cout<< "CT files sorting succeeded" <parse(p_loadDir); + + if(patientInfos->CTfiles .size()!=0){ + cout<< "this->load2VTK(patientInfos)" <rtIonPlanPath.isEmpty()){ + readRT = new RTPlan; + readRT->fillRTPlan(patientInfos->rtIonPlanPath.toLatin1().data() ); + m_rtIsocenter = new double[3]; + if (readRT->NumberOfBeams > 0){ + { + const auto& iso = readRT->Beams.at(0)->IsocenterPosition; + m_rtIsocenter[0] = iso[0]; + m_rtIsocenter[1] = iso[1]; + m_rtIsocenter[2] = iso[2]; + } + if (readRT->PatientOrientation.rfind("HFS", 0) == 0) + m_patientOrientation = SUPINE; + else if (readRT->PatientOrientation.rfind("HFP", 0) == 0) + m_patientOrientation = PRONE; + else m_patientOrientation = NOTDEFINED; + + emit loadedRTIso(m_rtIsocenter); + //for (int ii=0;iiNumberOfBeams; ii++){ + // cout<< readRT->Beams[ii]->IsocenterPosition[0]<<" "; + // cout<< readRT->Beams[ii]->IsocenterPosition[1]<<" "; + // cout<< readRT->Beams[ii]->IsocenterPosition[2]<<" "<NumberOfBeams <Beams.at(0)->IsocenterPosition[0] <Beams.at(2)->IsocenterPosition[0]<Beams.at(0)->IsocenterPosition[1] <Beams.at(2)->IsocenterPosition[1]<Beams.at(0)->IsocenterPosition[2] <Beams.at(2)->IsocenterPosition[2]<NumberOfBeams > 2 && + (readRT->Beams.at(0)->IsocenterPosition[0] != readRT->Beams.at(2)->IsocenterPosition[0] || + readRT->Beams.at(0)->IsocenterPosition[1] != readRT->Beams.at(2)->IsocenterPosition[1] || + readRT->Beams.at(0)->IsocenterPosition[2] != readRT->Beams.at(2)->IsocenterPosition[2]) + ) + virtualIso=true; + else + virtualIso=false; + //cout << "virtual Iso: "<loadDICOM(patientInfos->CTfiles); + this->connectToVTK(); +// this->changeRef(GOTSREF); + /* use DCM as default */ + this->changeRef(DCMREF); + //trueOffset_rot_prev=trueOffset_rot; + + + //this->load2VTK(patientInfos); + } else { + //DO NOTHING. THE folderisempty signal was already emitted. + } + cout<< " gLoadPatient::load _ END" <SetDirection( /*imageDir*/directionToWCS ); + myImage->SetOrigin( trueOffset_rot ); + myImage->Update(); + + in->SetInput(myImage); + this->connectToVTK(); + this->actualizeOut(); + + /*calculate deltas for marker representation update*/ + if(initialized){ + emit referenceChange( + trueOffset_rot_prev[0]-trueOffset_rot[0], + trueOffset_rot_prev[1]-trueOffset_rot[1], + trueOffset_rot_prev[2]-trueOffset_rot[2]); + trueOffset_rot_prev=trueOffset_rot; + } else { + trueOffset_rot_prev=trueOffset_rot; + initialized=true; + } + +} + +void gLoadPatient::loadDICOM(std::vector CTfilenames){ + + myImage = myImageType::New(); + rDICOM = itk::ImageSeriesReader::New(); + iGDCMimage = itk::GDCMImageIO::New(); + myDICOMseries = itk::GDCMSeriesFileNames::New(); + + rDICOM->SetImageIO(iGDCMimage); + rDICOM->SetFileNames(CTfilenames); + // rDICOM->SetReverseOrder(true); + try{ + rDICOM->Update(); + } + catch (itk::ExceptionObject &ex){ + std::cout << ex << std::endl; + return; // error! + } + + myImage=rDICOM->GetOutput(); + imageDir = myImage->GetDirection( ); + origin = myImage->GetOrigin( ); + sizeOfImage = myImage->GetLargestPossibleRegion().GetSize(); + +} + +void gLoadPatient::connectToVTK(){ + + + out = vtkSmartPointer::New(); + + in = itk::VTKImageExport ::New(); + in->SetInput(myImage); + + out->SetUpdateInformationCallback(in->GetUpdateInformationCallback()); + out->SetPipelineModifiedCallback(in->GetPipelineModifiedCallback()); + out->SetWholeExtentCallback(in->GetWholeExtentCallback()); + out->SetSpacingCallback(in->GetSpacingCallback()); + out->SetOriginCallback(in->GetOriginCallback()); + out->SetScalarTypeCallback(in->GetScalarTypeCallback()); + out->SetNumberOfComponentsCallback(in->GetNumberOfComponentsCallback()); + out->SetPropagateUpdateExtentCallback(in->GetPropagateUpdateExtentCallback()); + out->SetUpdateDataCallback(in->GetUpdateDataCallback()); + out->SetDataExtentCallback(in->GetDataExtentCallback()); + out->SetBufferPointerCallback(in->GetBufferPointerCallback()); + out->SetCallbackUserData(in->GetCallbackUserData()); + +} + +void gLoadPatient::actualizeOut(){ + + //in->Update(); + out->Update(); + //vol3D = vtkSmartPointer ::New(); + //vol3D->DeepCopy(out->GetOutput()); + //vol3D->Update(); + vol3D = out->GetOutput(); + cout<GetSpacing()[0] <<" "<GetSpacing()[1] <<" "<GetSpacing()[2] <clearInfo() " <clearInfo(); + + std::cout<<"parsing dir: "<c_str()).fileName().split(".").last() != QString("raw") ) + patientInfos->filenames.push_back( it->c_str() ); + } + patientInfos->filenames.size() == 0 ? result = PARSER_FOLDER_EMPTY : result = NOERRORS; + } else { + result=PARSER_FOLDER_NOTEXISTING; + }; + + cout << " patientInfos->filenames.size() "<filenames.size() <filenames.size()-1);i>-1;i--) + { + //cout << gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) <SetFileName (patientInfos->filenames.at(i).c_str()); + + if( !fileReader->Read() ) { + cout<< "Error reading file: "<< patientInfos->filenames.at(i).data() <filenames.erase(patientInfos->filenames.begin()+i); + continue; + } + + //msStructRTIonPlan.SetFromFile( fileReader->GetFile() ); + //if( msStructRTIonPlan == gdcm::MediaStorage::RTIonPlanStorage ) + if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTPLAN ) + { + if(!patientInfos->rtIonPlanPath.isEmpty()) { +// result=PARSER_RTPLAN_NOTUNIQUE; + continue; + } else { + const gdcm::File &file = fileReader->GetFile(); + const gdcm::DataSet &ds = file.GetDataSet(); + //PATIENT NAME + strcpy( patientInfos->PatientName,gGetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds)); + // // // PATIENT ID For ex: DICOM (0010,0020) = 1933197 + strcpy( patientInfos->PatientID , gGetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds)); + // // // PATIENT AGE For ex: DICOM (0010,1010) = 031Y + strcpy( patientInfos->PatientAge , gGetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds)) ; + // // // PATIENT SEX For ex: DICOM (0010,0040) = M + strcpy( patientInfos->PatientSex, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds) ); + // // // PATIENT BIRTHDATE For ex: DICOM (0010,0030) = 19680427 + strcpy( patientInfos->PatientBirthDate, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds) ); + // // // SERIES NUMBER For ex: DICOM (0020,0011) = 902 + strcpy( patientInfos->SeriesNumber, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds) ); + // // // SERIES DESCRIPTION For ex: DICOM (0008,103e) = SCOUT + strcpy( patientInfos->SeriesDescription , gGetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds) ); + // // // STUDY ID For ex: DICOM (0020,0010) = 37481 + strcpy( patientInfos->StudyID, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds) ); + // // // STUDY DESCRIPTION For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL + strcpy( patientInfos->StudyDescription, gGetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds) ); + + const gdcm::DataElement &gSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180)); + //LOOK FOR PATIENT ORIENTATION + gdcm::SmartPointer sqiPS = gSetupSequence.GetValueAsSQ(); + const gdcm::DataSet& gPatSetupNest = sqiPS->GetItem(1).GetNestedDataSet(); + //SET PATIENT ORIENTATION STRING + strcpy(patientInfos->PatientOrientation, gGetStringValueFromTag(gdcm::Tag(0x0018, 0x5100),gPatSetupNest)); + + + + patientInfos->rtIonPlanPath=QString(patientInfos->filenames.at(i).c_str()); + cout<< "RTPlan import success" <filenames.erase(patientInfos->filenames.begin()+i); + delete fileReader; + continue; + } + } + + // msStructRTStruct.SetFromFile( fileReader->GetFile() ); + // if( msStructRTStruct == gdcm::MediaStorage::RTStructureSetStorage ) { + if( gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) == RTSTRUCT ){ + if(!patientInfos->rtStructurePath.isEmpty()) { + patientInfos->rtStructurePath.clear(); +// result=PARSER_RTSTRUCT_NOTUNIQUE; + continue; + } else { + patientInfos->rtStructurePath=QString(patientInfos->filenames.at(i).c_str()); + cout<< "RTStruct import success" <filenames.erase(patientInfos->filenames.begin()+i); + delete fileReader; + continue; + } + } + delete fileReader; + } + + + //OK + //if(result == NOERRORS && patientInfos->rtIonPlanPath.isEmpty() ) + // result= PARSER_RTPLAN_MISSING; + //if(result == NOERRORS && patientInfos->rtStructurePath.isEmpty()) + // result=PARSER_RTSTRUCT_MISSING; + + s.SetComputeZSpacing( true ); + s.SetZSpacingTolerance( 1e-2 ); + + if(result==NOERRORS) + if(!s.Sort( patientInfos->filenames ) ) { + result=PARSER_CT_FAILED_SORTING; + } else { + s.GetFilenames().size() == 0 ? result = PARSER_CT_FILES_MISSING : result=NOERRORS; + } + + if(result == NOERRORS){ + patientInfos->CTfiles=s.GetFilenames (); + //cout<< "CT files sorting succeeded" <