Merge branch 'codeRev' into 'master'
Code rev See merge request gfattori/glocalize!1
@@ -1,132 +1,164 @@
|
||||
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 OpenGL OpenGLWidgets)
|
||||
|
||||
# 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
|
||||
GUISupportQt
|
||||
)
|
||||
|
||||
# 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}
|
||||
)
|
||||
|
||||
# Do NOT define QT_NO_KEYWORDS here: this project uses Qt's 'signals/slots/emit'
|
||||
# keywords in headers, and disabling them breaks moc.
|
||||
|
||||
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::OpenGL
|
||||
Qt6::OpenGLWidgets
|
||||
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 9.x + --as-needed: ensure GUISupportQt is explicitly linked when using QVTKOpenGLNativeWidget
|
||||
if(TARGET VTK::GUISupportQt)
|
||||
target_link_libraries(${TRG} PRIVATE VTK::GUISupportQt)
|
||||
endif()
|
||||
|
||||
|
||||
# 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()
|
||||
|
||||
@@ -1,26 +1,118 @@
|
||||
#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)
|
||||
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 = " <<SupportType<<endl;
|
||||
cout<<" |_ SupportId = "<<SupportId<<endl;
|
||||
cout<<" |_ GantryAngle = "<<GantryAngle<<endl;
|
||||
cout<<" |_ IsocenterPosition = "<<IsocenterPosition[0]<<
|
||||
IsocenterPosition[1]<<" "<<
|
||||
IsocenterPosition[2]<<endl;
|
||||
cout<<" |_ IsocenterPosition = "<<IsocenterPosition[0]<<" "
|
||||
<<IsocenterPosition[1]<<" "
|
||||
<<IsocenterPosition[2]<<endl;
|
||||
cout<<" |_ TableYawAngle = "<<TableYawAngle<<endl;
|
||||
cout<<" |_ TablePitchAngle = "<<TablePitchAngle<<endl;
|
||||
cout<<" |_ TableRollAngle = "<<TableRollAngle<<endl;
|
||||
@@ -100,60 +185,36 @@ void IonBeamProperties::PrintSelf(){
|
||||
|
||||
/*-----*/
|
||||
//CLASS gIonBEAMProperties
|
||||
RTPlan::~RTPlan(){
|
||||
if(NumberOfBeams > 0)
|
||||
for(int ii=0;ii<NumberOfBeams;ii++)
|
||||
delete Beams[ii];
|
||||
delete [] Beams;
|
||||
delete [] PatientName;
|
||||
delete [] PatientID;
|
||||
delete [] PatientSex;
|
||||
delete [] PatientAge;
|
||||
delete [] PatientBirthDate;
|
||||
delete [] SeriesNumber;
|
||||
delete [] SeriesDescription;
|
||||
delete [] StudyID;
|
||||
delete [] StudyDescription;
|
||||
delete [] Modality;
|
||||
delete [] IsocenterPosition;
|
||||
delete [] VolumeCenter;
|
||||
delete [] BeamName;
|
||||
delete [] SupportType;
|
||||
delete [] PatientOrientation;
|
||||
}
|
||||
|
||||
RTPlan::RTPlan(){
|
||||
NumberOfBeams=0;
|
||||
PatientName = new char [MAXSTRINGLENGHT];
|
||||
PatientID = new char [MAXSTRINGLENGHT];
|
||||
PatientSex = new char [MAXSTRINGLENGHT];
|
||||
PatientAge = new char [MAXSTRINGLENGHT];
|
||||
PatientBirthDate = new char [MAXSTRINGLENGHT];
|
||||
RTPlan::RTPlan()
|
||||
{
|
||||
NumberOfBeams = 0;
|
||||
PatientName.clear();
|
||||
PatientID.clear();
|
||||
PatientSex.clear();
|
||||
PatientAge.clear();
|
||||
PatientBirthDate.clear();
|
||||
|
||||
SeriesNumber = new char [MAXSTRINGLENGHT];
|
||||
SeriesDescription = new char [MAXSTRINGLENGHT];
|
||||
StudyID = new char [MAXSTRINGLENGHT];
|
||||
StudyDescription = new char [MAXSTRINGLENGHT];
|
||||
Modality = new char [MAXSTRINGLENGHT];
|
||||
SeriesNumber.clear();
|
||||
SeriesDescription.clear();
|
||||
StudyID.clear();
|
||||
StudyDescription.clear();
|
||||
Modality.clear();
|
||||
|
||||
IsocenterPosition = new double[3];
|
||||
std::fill(IsocenterPosition,(IsocenterPosition+3),BADVALUE);
|
||||
VolumeCenter= new double[3];
|
||||
std::fill(VolumeCenter,(VolumeCenter+3),BADVALUE);
|
||||
IsocenterPosition = {BADVALUE, BADVALUE, BADVALUE};
|
||||
VolumeCenter = {BADVALUE, BADVALUE, BADVALUE};
|
||||
|
||||
BeamNumber = BADVALUE;
|
||||
BeamName = new char [MAXSTRINGLENGHT];
|
||||
TableRollAngle = BADVALUE;
|
||||
TableYawAngle= BADVALUE;
|
||||
TablePitchAngle= BADVALUE;
|
||||
TableLatDispl= BADVALUE;
|
||||
TableVertDispl= BADVALUE;
|
||||
TableLongDispl= BADVALUE;
|
||||
SupportType = new char [MAXSTRINGLENGHT];
|
||||
SupportId = new char [MAXSTRINGLENGHT];
|
||||
PatientOrientation = new char [MAXSTRINGLENGHT];
|
||||
|
||||
}
|
||||
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;
|
||||
@@ -185,11 +246,13 @@ RTPlan::~RTPlan(){
|
||||
cout<<"PatientOrientation = "<<PatientOrientation<<endl;
|
||||
|
||||
if(NumberOfBeams > 0)
|
||||
for(int ii=0; ii<NumberOfBeams;ii++)
|
||||
Beams[ii]->PrintSelf();
|
||||
for(const auto& b : Beams)
|
||||
if(b) b->PrintSelf();
|
||||
}
|
||||
|
||||
bool RTPlan::fillRTPlan( char *filertionplan){
|
||||
bool RTPlan::fillRTPlan(const char *filertionplan){
|
||||
|
||||
LastError.clear();
|
||||
|
||||
cout<<"reading filename: "<<filertionplan<<endl;
|
||||
|
||||
@@ -197,42 +260,45 @@ RTPlan::~RTPlan(){
|
||||
gdcm::Reader R;
|
||||
R.SetFileName(filertionplan);
|
||||
if(!R.Read())
|
||||
{ cout<<"ERROR: cannot read filertionplan."<<endl;
|
||||
}
|
||||
{
|
||||
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
|
||||
strcpy( PatientName,gGetStringValueFromTag( gdcm::Tag(0x0010,0x0010), ds));
|
||||
PatientName = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0010), ds);
|
||||
|
||||
// // // PATIENT ID For ex: DICOM (0010,0020) = 1933197
|
||||
strcpy(PatientID , gGetStringValueFromTag( gdcm::Tag(0x0010,0x0020), ds));
|
||||
PatientID = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0020), ds);
|
||||
// //
|
||||
// // // PATIENT AGE For ex: DICOM (0010,1010) = 031Y
|
||||
strcpy(PatientAge , gGetStringValueFromTag( gdcm::Tag(0x0010,0x1010), ds)) ;
|
||||
PatientAge = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x1010), ds);
|
||||
// //
|
||||
// // // PATIENT SEX For ex: DICOM (0010,0040) = M
|
||||
strcpy(PatientSex, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0040), ds) );
|
||||
PatientSex = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0040), ds);
|
||||
// //
|
||||
// // // PATIENT BIRTHDATE For ex: DICOM (0010,0030) = 19680427
|
||||
strcpy(PatientBirthDate, gGetStringValueFromTag( gdcm::Tag(0x0010,0x0030), ds) );
|
||||
PatientBirthDate = gGetStringValueFromTagStr(gdcm::Tag(0x0010,0x0030), ds);
|
||||
// //
|
||||
// // // SERIES NUMBER For ex: DICOM (0020,0011) = 902
|
||||
strcpy(SeriesNumber, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0011), ds) );
|
||||
SeriesNumber = gGetStringValueFromTagStr(gdcm::Tag(0x0020,0x0011), ds);
|
||||
// //
|
||||
// // // SERIES DESCRIPTION For ex: DICOM (0008,103e) = SCOUT
|
||||
strcpy(SeriesDescription , gGetStringValueFromTag( gdcm::Tag(0x0008,0x103e), ds) );
|
||||
SeriesDescription = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x103e), ds);
|
||||
// //
|
||||
// // // STUDY ID For ex: DICOM (0020,0010) = 37481
|
||||
strcpy(StudyID, gGetStringValueFromTag( gdcm::Tag(0x0020,0x0010), ds) );
|
||||
StudyID = gGetStringValueFromTagStr(gdcm::Tag(0x0020,0x0010), ds);
|
||||
// //
|
||||
// // // STUDY DESCRIPTION For ex: DICOM (0008,1030) = BRAIN/C-SP/FACIAL
|
||||
strcpy(StudyDescription, gGetStringValueFromTag( gdcm::Tag(0x0008,0x1030), ds) );
|
||||
StudyDescription = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x1030), ds);
|
||||
// //
|
||||
// // // STUDY MODALITY For ex: DICOM (0008,0060)= CT
|
||||
strcpy(Modality, gGetStringValueFromTag( gdcm::Tag(0x0008,0x0060), ds) );
|
||||
Modality = gGetStringValueFromTagStr(gdcm::Tag(0x0008,0x0060), ds);
|
||||
|
||||
|
||||
//TREATMENT GEOMETRY
|
||||
@@ -249,71 +315,91 @@ RTPlan::~RTPlan(){
|
||||
|
||||
//QUI HFP vs HFS
|
||||
//v04 Build29: LOOK FOR SETUP SEQUENCE TO SEARHC FOR PATINET ORIENTATION
|
||||
const gdcm::DataElement &gSetupSequence=ds.GetDataElement(gdcm::Tag(0x300a,0x0180));
|
||||
//LOOK FOR PATIENT ORIENTATION
|
||||
gdcm::SmartPointer<gdcm::SequenceOfItems> 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<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())
|
||||
{
|
||||
cout<<"usteria" <<endl;//throw(gException("CRITICAL: Beam sequence not found in RTION Plan file"));
|
||||
LastError = "Beam sequence not found in RT Plan file";
|
||||
cout<<"usteria" <<endl;
|
||||
return false;
|
||||
}
|
||||
NumberOfBeams=sqi->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<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<NumberOfBeams;i++)
|
||||
{ const gdcm::Item & item = sqi->GetItem(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>();
|
||||
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<gdcm::SequenceOfItems> 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<float>(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<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
|
||||
{ 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<int>(Beams.size());
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
#include <gdcmScanner.h>
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// 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<double, 3> 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<double, 3> IsocenterPosition;
|
||||
std::array<double, 3> 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<std::unique_ptr<IonBeamProperties>> 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
|
||||
@@ -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" <<endl;
|
||||
}
|
||||
|
||||
|
||||
void gLoadPatient::load(QString p_loadDir){
|
||||
|
||||
this->parse(p_loadDir);
|
||||
|
||||
if(patientInfos->CTfiles .size()!=0){
|
||||
cout<< "this->load2VTK(patientInfos)" <<endl;
|
||||
|
||||
if(readRT!=0){
|
||||
delete readRT;
|
||||
readRT = 0;
|
||||
}
|
||||
if(m_rtIsocenter!=0){
|
||||
delete m_rtIsocenter;
|
||||
m_rtIsocenter = 0;
|
||||
}
|
||||
|
||||
if(!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;ii<readRT->NumberOfBeams; ii++){
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[0]<<" ";
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[1]<<" ";
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[2]<<" "<<endl;
|
||||
//}
|
||||
//cout<< "nbeams: "<<readRT->NumberOfBeams <<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams[0]->IsocenterPosition[0] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams[2]->IsocenterPosition[0]<<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams[0]->IsocenterPosition[1] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams[2]->IsocenterPosition[1]<<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams[0]->IsocenterPosition[2] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams[2]->IsocenterPosition[2]<<endl;
|
||||
|
||||
/*check for virtual iso, adapted from GB, gOTS v04Build34*/
|
||||
if(readRT->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: "<<virtualIso << endl;
|
||||
emit virtualIsoTested(virtualIso);
|
||||
|
||||
|
||||
} else {
|
||||
cout<<"Number of Beams = 0 in RTIonPlan, FAIL" <<endl;
|
||||
delete m_rtIsocenter;
|
||||
delete readRT;
|
||||
readRT = 0;
|
||||
m_rtIsocenter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cout<< "gLoadPatient::load2VTK _ 2 " <<endl;
|
||||
|
||||
|
||||
|
||||
this->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" <<endl;
|
||||
}
|
||||
|
||||
void gLoadPatient::changeRef(int selectedRef){
|
||||
|
||||
switch (selectedRef){
|
||||
case DCMREF:
|
||||
trueOffset=origin;
|
||||
break;
|
||||
case RTREF:
|
||||
trueOffset=origin;
|
||||
if(m_patientOrientation == SUPINE) {
|
||||
cout<< " ***** Patient is SUPINE" <<endl;
|
||||
trueOffset[0]-= m_rtIsocenter[0];
|
||||
trueOffset[1]-= m_rtIsocenter[1];
|
||||
trueOffset[2]-= m_rtIsocenter[2];
|
||||
} else if (m_patientOrientation == PRONE) {
|
||||
|
||||
cout<< " ***** Patient is PRONE" <<endl;
|
||||
/* adapted from CThandler project*/
|
||||
trueOffset[0] = 0.0;
|
||||
trueOffset[1] = 0.0;
|
||||
trueOffset[2] = 0.0;
|
||||
cout<<" ***** Reset trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
trueOffset[0] += -origin[0] ;
|
||||
trueOffset[1] += -origin[1];
|
||||
trueOffset[2] += origin[2] ;
|
||||
cout<<" ***** Correct for CT isocenter trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
trueOffset[0] += +m_rtIsocenter[0];
|
||||
trueOffset[1] += +m_rtIsocenter[1];
|
||||
trueOffset[2] +=- m_rtIsocenter[2];
|
||||
cout<<" ***** Correct for rtIso and volume bounds trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
} else if (m_patientOrientation == NOTDEFINED) {
|
||||
cout<< "!!! Patient is NOT PRONE OR SUPINE! VERY VERY CRITICAL SITUATION !!!" <<endl;
|
||||
}
|
||||
break;
|
||||
case GOTSREF:
|
||||
trueOffset[0] = 0.0;
|
||||
trueOffset[1] = 0.0;
|
||||
trueOffset[2] = 0.0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
directionToWCS.SetIdentity( );
|
||||
directionToWCS[0][0]=1;
|
||||
directionToWCS[1][0]=0;
|
||||
directionToWCS[2][0]=0;
|
||||
directionToWCS[0][1]=0;
|
||||
directionToWCS[1][1]=1;
|
||||
directionToWCS[2][1]=0;
|
||||
directionToWCS[0][2]=0;
|
||||
directionToWCS[1][2]=0;
|
||||
directionToWCS[2][2]=1;
|
||||
|
||||
imageDir *= directionToWCS;
|
||||
myImageType::PointType trueOffset_rot=trueOffset;
|
||||
|
||||
trueOffset_rot[0]= directionToWCS[0][0]* trueOffset[0]+directionToWCS[0][1]* trueOffset[1] + directionToWCS[0][2]* trueOffset[2];
|
||||
trueOffset_rot[1]= directionToWCS[1][0]* trueOffset[0]+directionToWCS[1][1]* trueOffset[1] + directionToWCS[1][2]* trueOffset[2];
|
||||
trueOffset_rot[2]= directionToWCS[2][0]* trueOffset[0]+directionToWCS[2][1]* trueOffset[1] + directionToWCS[2][2]* trueOffset[2];
|
||||
|
||||
/*vedi se è giusto ma prob lo è */
|
||||
myImage->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<std::string> CTfilenames){
|
||||
|
||||
myImage = myImageType::New();
|
||||
rDICOM = itk::ImageSeriesReader<myImageType>::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<vtkImageImport>::New();
|
||||
|
||||
in = itk::VTKImageExport <myImageType>::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 <vtkImageData>::New();
|
||||
//vol3D->DeepCopy(out->GetOutput());
|
||||
//vol3D->Update();
|
||||
vol3D = out->GetOutput();
|
||||
cout<<vol3D->GetSpacing()[0] <<" "<<vol3D->GetSpacing()[1] <<" "<<vol3D->GetSpacing()[2] <<endl;
|
||||
cout<<"fatto update" <<endl;
|
||||
emit loadEnd(vol3D);
|
||||
}
|
||||
|
||||
|
||||
void gLoadPatient::parse(QString p_loadDir){
|
||||
loadDir=p_loadDir;
|
||||
|
||||
std::cout<< " ______________________________ " <<endl;
|
||||
std::cout<< " __ gLoadPatient::load __ " <<endl;
|
||||
|
||||
int result= NOERRORS;
|
||||
gdcm::Reader* fileReader;
|
||||
gdcm::MediaStorage msStructRTStruct;
|
||||
gdcm::MediaStorage msStructRTIonPlan;
|
||||
gdcm::Directory d;
|
||||
gdcm::IPPSorter s;
|
||||
std::cout<< " __ wrkDirParser::exec_parse __ patientInfos->clearInfo() " <<endl;
|
||||
patientInfos->clearInfo();
|
||||
|
||||
std::cout<<"parsing dir: "<<p_loadDir.toUtf8().constData()<<std::endl;
|
||||
|
||||
if( gdcm::System::FileIsDirectory( p_loadDir.toUtf8().constData() ) )
|
||||
{
|
||||
d.Load(p_loadDir.toUtf8().constData(), false);
|
||||
gdcm::Directory::FilenamesType const &files = d.GetFilenames();
|
||||
for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it )
|
||||
{
|
||||
if(QFileInfo (it->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() "<<endl;
|
||||
cout<< patientInfos->filenames.size() <<endl;
|
||||
|
||||
if(result == NOERRORS)
|
||||
for(int i=(patientInfos->filenames.size()-1);i>-1;i--)
|
||||
{
|
||||
//cout << gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) <<endl;
|
||||
fileReader = new gdcm::Reader;
|
||||
fileReader->SetFileName (patientInfos->filenames.at(i).c_str());
|
||||
|
||||
if( !fileReader->Read() ) {
|
||||
cout<< "Error reading file: "<< patientInfos->filenames.at(i).data() <<endl;
|
||||
delete fileReader;
|
||||
patientInfos->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<gdcm::SequenceOfItems> 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" <<endl;
|
||||
result=NOERRORS;
|
||||
patientInfos->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" <<endl;
|
||||
result=NOERRORS;
|
||||
patientInfos->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" <<endl;
|
||||
emit statusInfo("CT files sorting succeeded");
|
||||
} else {
|
||||
|
||||
switch(result){
|
||||
|
||||
case PARSER_FOLDER_EMPTY:
|
||||
cout<< "Empty folder. Parse failed" <<endl;
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_FOLDER_NOTEXISTING:
|
||||
emit statusInfo("NonExisting folder. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_RTPLAN_NOTUNIQUE:
|
||||
emit statusInfo("RtIonPlan not unique. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_RTSTRUCT_NOTUNIQUE:
|
||||
emit statusInfo("RtStructure not unique. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_CT_FAILED_SORTING:
|
||||
emit statusInfo("Failed to sort CT files");
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_CT_FILES_MISSING:
|
||||
emit statusInfo("CT file Missing");
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_RTPLAN_MISSING:
|
||||
emit statusInfo("RtIonPlan missing");
|
||||
break;
|
||||
|
||||
case PARSER_RTSTRUCT_MISSING:
|
||||
emit statusInfo("rtStructure missing");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
emit parse_result(result,patientInfos);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#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" <<endl;
|
||||
}
|
||||
|
||||
|
||||
void gLoadPatient::load(QString p_loadDir){
|
||||
|
||||
this->parse(p_loadDir);
|
||||
|
||||
if(patientInfos->CTfiles .size()!=0){
|
||||
cout<< "this->load2VTK(patientInfos)" <<endl;
|
||||
|
||||
if(readRT!=0){
|
||||
delete readRT;
|
||||
readRT = 0;
|
||||
}
|
||||
if(m_rtIsocenter!=0){
|
||||
delete m_rtIsocenter;
|
||||
m_rtIsocenter = 0;
|
||||
}
|
||||
|
||||
if(!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;ii<readRT->NumberOfBeams; ii++){
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[0]<<" ";
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[1]<<" ";
|
||||
// cout<< readRT->Beams[ii]->IsocenterPosition[2]<<" "<<endl;
|
||||
//}
|
||||
//cout<< "nbeams: "<<readRT->NumberOfBeams <<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[0] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[0]<<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[1] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[1]<<endl;
|
||||
//cout<< "iso0: "<<readRT->Beams.at(0)->IsocenterPosition[2] <<endl;
|
||||
//cout<< "iso2: "<<readRT->Beams.at(2)->IsocenterPosition[2]<<endl;
|
||||
|
||||
/*check for virtual iso, adapted from GB, gOTS v04Build34*/
|
||||
if(readRT->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: "<<virtualIso << endl;
|
||||
emit virtualIsoTested(virtualIso);
|
||||
|
||||
|
||||
} else {
|
||||
cout<<"Number of Beams = 0 in RTIonPlan, FAIL" <<endl;
|
||||
delete m_rtIsocenter;
|
||||
delete readRT;
|
||||
readRT = 0;
|
||||
m_rtIsocenter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cout<< "gLoadPatient::load2VTK _ 2 " <<endl;
|
||||
|
||||
|
||||
|
||||
this->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" <<endl;
|
||||
}
|
||||
|
||||
void gLoadPatient::changeRef(int selectedRef){
|
||||
|
||||
switch (selectedRef){
|
||||
case DCMREF:
|
||||
trueOffset=origin;
|
||||
break;
|
||||
case RTREF:
|
||||
trueOffset=origin;
|
||||
if(m_patientOrientation == SUPINE) {
|
||||
cout<< " ***** Patient is SUPINE" <<endl;
|
||||
trueOffset[0]-= m_rtIsocenter[0];
|
||||
trueOffset[1]-= m_rtIsocenter[1];
|
||||
trueOffset[2]-= m_rtIsocenter[2];
|
||||
} else if (m_patientOrientation == PRONE) {
|
||||
|
||||
cout<< " ***** Patient is PRONE" <<endl;
|
||||
/* adapted from CThandler project*/
|
||||
trueOffset[0] = 0.0;
|
||||
trueOffset[1] = 0.0;
|
||||
trueOffset[2] = 0.0;
|
||||
cout<<" ***** Reset trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
trueOffset[0] += -origin[0] ;
|
||||
trueOffset[1] += -origin[1];
|
||||
trueOffset[2] += origin[2] ;
|
||||
cout<<" ***** Correct for CT isocenter trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
trueOffset[0] += +m_rtIsocenter[0];
|
||||
trueOffset[1] += +m_rtIsocenter[1];
|
||||
trueOffset[2] +=- m_rtIsocenter[2];
|
||||
cout<<" ***** Correct for rtIso and volume bounds trueOffset: "<<trueOffset[0]<<" "<<trueOffset[1]<<" "<<trueOffset[2]<<endl;
|
||||
|
||||
} else if (m_patientOrientation == NOTDEFINED) {
|
||||
cout<< "!!! Patient is NOT PRONE OR SUPINE! VERY VERY CRITICAL SITUATION !!!" <<endl;
|
||||
}
|
||||
break;
|
||||
case GOTSREF:
|
||||
trueOffset[0] = 0.0;
|
||||
trueOffset[1] = 0.0;
|
||||
trueOffset[2] = 0.0;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
directionToWCS.SetIdentity( );
|
||||
directionToWCS[0][0]=1;
|
||||
directionToWCS[1][0]=0;
|
||||
directionToWCS[2][0]=0;
|
||||
directionToWCS[0][1]=0;
|
||||
directionToWCS[1][1]=1;
|
||||
directionToWCS[2][1]=0;
|
||||
directionToWCS[0][2]=0;
|
||||
directionToWCS[1][2]=0;
|
||||
directionToWCS[2][2]=1;
|
||||
|
||||
imageDir *= directionToWCS;
|
||||
myImageType::PointType trueOffset_rot=trueOffset;
|
||||
|
||||
trueOffset_rot[0]= directionToWCS[0][0]* trueOffset[0]+directionToWCS[0][1]* trueOffset[1] + directionToWCS[0][2]* trueOffset[2];
|
||||
trueOffset_rot[1]= directionToWCS[1][0]* trueOffset[0]+directionToWCS[1][1]* trueOffset[1] + directionToWCS[1][2]* trueOffset[2];
|
||||
trueOffset_rot[2]= directionToWCS[2][0]* trueOffset[0]+directionToWCS[2][1]* trueOffset[1] + directionToWCS[2][2]* trueOffset[2];
|
||||
|
||||
/*vedi se è giusto ma prob lo è */
|
||||
myImage->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<std::string> CTfilenames){
|
||||
|
||||
myImage = myImageType::New();
|
||||
rDICOM = itk::ImageSeriesReader<myImageType>::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<vtkImageImport>::New();
|
||||
|
||||
in = itk::VTKImageExport <myImageType>::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 <vtkImageData>::New();
|
||||
//vol3D->DeepCopy(out->GetOutput());
|
||||
//vol3D->Update();
|
||||
vol3D = out->GetOutput();
|
||||
cout<<vol3D->GetSpacing()[0] <<" "<<vol3D->GetSpacing()[1] <<" "<<vol3D->GetSpacing()[2] <<endl;
|
||||
cout<<"fatto update" <<endl;
|
||||
emit loadEnd(vol3D);
|
||||
}
|
||||
|
||||
|
||||
void gLoadPatient::parse(QString p_loadDir){
|
||||
loadDir=p_loadDir;
|
||||
|
||||
std::cout<< " ______________________________ " <<endl;
|
||||
std::cout<< " __ gLoadPatient::load __ " <<endl;
|
||||
|
||||
int result= NOERRORS;
|
||||
gdcm::Reader* fileReader;
|
||||
gdcm::MediaStorage msStructRTStruct;
|
||||
gdcm::MediaStorage msStructRTIonPlan;
|
||||
gdcm::Directory d;
|
||||
gdcm::IPPSorter s;
|
||||
std::cout<< " __ wrkDirParser::exec_parse __ patientInfos->clearInfo() " <<endl;
|
||||
patientInfos->clearInfo();
|
||||
|
||||
std::cout<<"parsing dir: "<<p_loadDir.toUtf8().constData()<<std::endl;
|
||||
|
||||
if( gdcm::System::FileIsDirectory( p_loadDir.toUtf8().constData() ) )
|
||||
{
|
||||
d.Load(p_loadDir.toUtf8().constData(), false);
|
||||
gdcm::Directory::FilenamesType const &files = d.GetFilenames();
|
||||
for( gdcm::Directory::FilenamesType::const_iterator it = files.begin(); it != files.end(); ++it )
|
||||
{
|
||||
if(QFileInfo (it->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() "<<endl;
|
||||
cout<< patientInfos->filenames.size() <<endl;
|
||||
|
||||
if(result == NOERRORS)
|
||||
for(int i=(patientInfos->filenames.size()-1);i>-1;i--)
|
||||
{
|
||||
//cout << gCheckDICOMModalityToInt(patientInfos->filenames.at(i).c_str()) <<endl;
|
||||
fileReader = new gdcm::Reader;
|
||||
fileReader->SetFileName (patientInfos->filenames.at(i).c_str());
|
||||
|
||||
if( !fileReader->Read() ) {
|
||||
cout<< "Error reading file: "<< patientInfos->filenames.at(i).data() <<endl;
|
||||
delete fileReader;
|
||||
patientInfos->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<gdcm::SequenceOfItems> 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" <<endl;
|
||||
result=NOERRORS;
|
||||
patientInfos->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" <<endl;
|
||||
result=NOERRORS;
|
||||
patientInfos->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" <<endl;
|
||||
emit statusInfo("CT files sorting succeeded");
|
||||
} else {
|
||||
|
||||
switch(result){
|
||||
|
||||
case PARSER_FOLDER_EMPTY:
|
||||
cout<< "Empty folder. Parse failed" <<endl;
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_FOLDER_NOTEXISTING:
|
||||
emit statusInfo("NonExisting folder. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_RTPLAN_NOTUNIQUE:
|
||||
emit statusInfo("RtIonPlan not unique. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_RTSTRUCT_NOTUNIQUE:
|
||||
emit statusInfo("RtStructure not unique. Parse failed");
|
||||
break;
|
||||
|
||||
case PARSER_CT_FAILED_SORTING:
|
||||
emit statusInfo("Failed to sort CT files");
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_CT_FILES_MISSING:
|
||||
emit statusInfo("CT file Missing");
|
||||
emit folderIsEmpty();
|
||||
break;
|
||||
|
||||
case PARSER_RTPLAN_MISSING:
|
||||
emit statusInfo("RtIonPlan missing");
|
||||
break;
|
||||
|
||||
case PARSER_RTSTRUCT_MISSING:
|
||||
emit statusInfo("rtStructure missing");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
emit parse_result(result,patientInfos);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
#include "gRen.h"
|
||||
#include <vtkOpenGLGPUVolumeRayCastMapper.h>
|
||||
#include <vtkGPUVolumeRayCastMapper.h>
|
||||
|
||||
|
||||
gRen::gRen(QVTKOpenGLNativeWidget *m_qvtk){
|
||||
@@ -8,12 +8,9 @@ gRen::gRen(QVTKOpenGLNativeWidget *m_qvtk){
|
||||
qvtk= m_qvtk;
|
||||
nmarker=0;
|
||||
|
||||
markerSources = 0;
|
||||
markerMappers = 0;
|
||||
markerActors = 0;
|
||||
|
||||
|
||||
|
||||
markerSources.clear();
|
||||
markerMappers.clear();
|
||||
markerActors.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,20 +133,20 @@ void gRen::loadVolume(vtkImageData* volCT){
|
||||
|
||||
void gRen::createRenderers(){
|
||||
|
||||
ren1 = vtkRenderer::New();
|
||||
ren1 = vtkSmartPointer<vtkRenderer>::New();
|
||||
ren1->SetBackground(0.13, 0.25, 0.32);
|
||||
qvtk->renderWindow()->AddRenderer(ren1);
|
||||
|
||||
ren1->AddActor(assi);
|
||||
ren1->AddActor( outlineActor);
|
||||
|
||||
boxWidget_NEW = vtkBoxWidget::New();
|
||||
boxWidget_NEW = vtkSmartPointer<vtkBoxWidget>::New();
|
||||
boxWidget_NEW->SetInteractor(qvtk->interactor());
|
||||
boxWidget_NEW->SetPlaceFactor(1.0);
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
boxCallback_NEW->rcm=volumeMapper;
|
||||
boxCallback_NEW->rcm=volumeMapper.GetPointer();
|
||||
boxWidget_NEW->AddObserver(vtkCommand::InteractionEvent, boxCallback_NEW);
|
||||
|
||||
return;
|
||||
@@ -163,23 +160,23 @@ void gRen::buildRenderPipe(){
|
||||
|
||||
qDebug()<<"buildRenderPipe: outlineMapper";
|
||||
|
||||
vtkPolyDataMapper* outlineMapper = vtkPolyDataMapper::New();
|
||||
vtkNew<vtkPolyDataMapper> outlineMapper;
|
||||
outlineMapper->SetInputConnection(outline->GetOutputPort());
|
||||
|
||||
outlineActor = vtkSmartPointer <vtkActor> ::New();
|
||||
outlineActor->SetMapper( outlineMapper);
|
||||
outlineActor->SetMapper(outlineMapper);
|
||||
|
||||
qDebug()<<"buildRenderPipe: picker";
|
||||
|
||||
vtkCellPicker* picker = vtkCellPicker::New();
|
||||
vtkNew<vtkCellPicker> picker;
|
||||
picker->SetTolerance(0.005);
|
||||
|
||||
vtkProperty* ipwProp = vtkProperty::New();
|
||||
vtkNew<vtkProperty> ipwProp;
|
||||
//// //assign default props to the ipw's texture plane actor
|
||||
|
||||
qDebug()<<"buildRenderPipe: planeX";
|
||||
|
||||
planeWidgetX = vtkImagePlaneWidget::New();
|
||||
planeWidgetX = vtkSmartPointer<vtkImagePlaneWidget>::New();
|
||||
planeWidgetX->SetInteractor( qvtk->interactor());
|
||||
planeWidgetX->SetKeyPressActivationValue('x');
|
||||
planeWidgetX->SetPicker(picker);
|
||||
@@ -195,7 +192,7 @@ void gRen::buildRenderPipe(){
|
||||
|
||||
qDebug()<<"buildRenderPipe: planeY";
|
||||
|
||||
planeWidgetY = vtkImagePlaneWidget::New();
|
||||
planeWidgetY = vtkSmartPointer<vtkImagePlaneWidget>::New();
|
||||
planeWidgetY->SetInteractor( qvtk->interactor());
|
||||
planeWidgetY->SetKeyPressActivationValue('y');
|
||||
planeWidgetY->SetPicker(picker);
|
||||
@@ -210,7 +207,7 @@ void gRen::buildRenderPipe(){
|
||||
|
||||
qDebug()<<"buildRenderPipe: planeZ";
|
||||
|
||||
planeWidgetZ = vtkImagePlaneWidget::New();
|
||||
planeWidgetZ = vtkSmartPointer<vtkImagePlaneWidget>::New();
|
||||
planeWidgetZ->SetInteractor( qvtk->interactor());
|
||||
planeWidgetZ->SetKeyPressActivationValue('z');
|
||||
planeWidgetZ->SetPicker(picker);
|
||||
@@ -225,7 +222,7 @@ void gRen::buildRenderPipe(){
|
||||
qDebug()<<"buildRenderPipe: assi";
|
||||
|
||||
|
||||
assi= vtkAxesActor::New();
|
||||
assi = vtkSmartPointer<vtkAxesActor>::New();
|
||||
assi->SetOrigin(0,0,0);
|
||||
assi->AxisLabelsOff();
|
||||
assi->SetTotalLength(15,15,15);
|
||||
@@ -233,7 +230,7 @@ void gRen::buildRenderPipe(){
|
||||
qDebug()<<"buildRenderPipe: volMapper";
|
||||
|
||||
// Create mapper (as vtkVolumeMapper smart pointer)
|
||||
auto gpuMapper = vtkSmartPointer<vtkOpenGLGPUVolumeRayCastMapper>::New();
|
||||
auto gpuMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
|
||||
gpuMapper->SetBlendModeToComposite();
|
||||
if (!gpuMapper)
|
||||
{
|
||||
@@ -309,7 +306,7 @@ void gRen::buildRenderPipe(){
|
||||
|
||||
qDebug()<<"buildRenderPipe: orthoplanes";
|
||||
|
||||
orthoPlanes = vtkImageOrthoPlanes::New();
|
||||
orthoPlanes = vtkSmartPointer<vtkImageOrthoPlanes>::New();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -318,11 +315,17 @@ void gRen::onSingleMarkerChange(int idx, bool state){
|
||||
|
||||
cout<< "onSingleMarkerChange : "<<idx<<" "<<(state == true? "true":"false")<<endl;
|
||||
|
||||
if(state){
|
||||
markerActors[idx]->GetProperty()->SetColor(0,1,0);
|
||||
} else {
|
||||
markerActors[idx]->GetProperty()->SetColor(1,1,1);
|
||||
}
|
||||
if (idx < 0 || idx >= static_cast<int>(markerActors.size()))
|
||||
return;
|
||||
|
||||
auto &act = markerActors.at(static_cast<size_t>(idx));
|
||||
if (!act)
|
||||
return;
|
||||
|
||||
if(state)
|
||||
act->GetProperty()->SetColor(0,1,0);
|
||||
else
|
||||
act->GetProperty()->SetColor(1,1,1);
|
||||
qvtk->renderWindow()->Render();
|
||||
return;
|
||||
|
||||
@@ -333,26 +336,25 @@ void gRen::renderMarkers(QList<surf> marker_list){
|
||||
|
||||
cout << "renderMarkers" << endl;
|
||||
|
||||
if(markerSources != 0) {
|
||||
for(int ii=0;ii<nmarker;ii++){
|
||||
ren1->RemoveActor(markerActors[ii]);
|
||||
markerActors[ii]->RemoveAllObservers();
|
||||
markerMappers[ii]->RemoveAllObservers();
|
||||
markerSources[ii]->RemoveAllObservers();
|
||||
markerSources[ii]->Delete();
|
||||
markerActors[ii]->Delete();
|
||||
markerMappers[ii]->Delete();
|
||||
}
|
||||
delete [] markerActors;
|
||||
delete [] markerMappers;
|
||||
delete [] markerSources;
|
||||
// Remove previous marker actors/labels
|
||||
for (auto &a : markerActors)
|
||||
{
|
||||
if (a)
|
||||
ren1->RemoveActor(a);
|
||||
}
|
||||
markerActors.clear();
|
||||
markerMappers.clear();
|
||||
markerSources.clear();
|
||||
if (pointLabels)
|
||||
{
|
||||
ren1->RemoveActor(pointLabels);
|
||||
pointLabels = nullptr;
|
||||
}
|
||||
|
||||
nmarker = marker_list.size();
|
||||
markerSources = new vtkSphereSource* [nmarker];
|
||||
markerMappers = new vtkPolyDataMapper* [nmarker];
|
||||
markerActors = new vtkActor* [nmarker];
|
||||
markerSources.reserve(static_cast<size_t>(nmarker));
|
||||
markerMappers.reserve(static_cast<size_t>(nmarker));
|
||||
markerActors.reserve(static_cast<size_t>(nmarker));
|
||||
|
||||
modelPoints = vtkSmartPointer<vtkPoints>::New();
|
||||
modelPoints->Reset();
|
||||
@@ -367,19 +369,22 @@ void gRen::renderMarkers(QList<surf> marker_list){
|
||||
stringData->InsertNextValue(QString::number(i).toLatin1().constData());
|
||||
modelPoints->InsertPoint(i,marker_list.at(i).centroid.x*1000,marker_list.at(i).centroid.y*1000,marker_list.at(i).centroid.z*1000);
|
||||
|
||||
markerSources[i] = vtkSphereSource::New();
|
||||
markerSources[i]->SetCenter(marker_list.at(i).centroid.x*1000,marker_list.at(i).centroid.y*1000,marker_list.at(i).centroid.z*1000);
|
||||
markerSources[i]->SetRadius(10);
|
||||
// markerSources[i]->SetRadius(2);
|
||||
auto src = vtkSmartPointer<vtkSphereSource>::New();
|
||||
src->SetCenter(marker_list.at(i).centroid.x*1000,marker_list.at(i).centroid.y*1000,marker_list.at(i).centroid.z*1000);
|
||||
src->SetRadius(10);
|
||||
|
||||
markerMappers[i]= vtkPolyDataMapper::New();
|
||||
markerMappers[i]->SetInputConnection (markerSources[i]->GetOutputPort());
|
||||
auto map = vtkSmartPointer<vtkPolyDataMapper>::New();
|
||||
map->SetInputConnection(src->GetOutputPort());
|
||||
|
||||
markerActors[i]= vtkActor::New();
|
||||
markerActors[i]->SetMapper(markerMappers[i]);
|
||||
markerActors[i]->GetProperty()->SetRepresentationToWireframe();
|
||||
markerActors[i]->GetProperty()->SetColor(0,1,0);
|
||||
ren1->AddActor(markerActors[i]);
|
||||
auto act = vtkSmartPointer<vtkActor>::New();
|
||||
act->SetMapper(map);
|
||||
act->GetProperty()->SetRepresentationToWireframe();
|
||||
act->GetProperty()->SetColor(0,1,0);
|
||||
ren1->AddActor(act);
|
||||
|
||||
markerSources.push_back(src);
|
||||
markerMappers.push_back(map);
|
||||
markerActors.push_back(act);
|
||||
}
|
||||
|
||||
cout << "modelPoints" << endl;
|
||||
@@ -415,20 +420,17 @@ void gRen::renderMarkers(QList<surf> marker_list){
|
||||
|
||||
void gRen::onReferenceChange(double dx, double dy, double dz){
|
||||
|
||||
if(markerSources == 0)
|
||||
if (markerSources.empty())
|
||||
return;
|
||||
|
||||
for(int i=0;i<nmarker;i++){
|
||||
markerSources[i]->SetCenter(
|
||||
markerSources[i]->GetCenter()[0]-dx,
|
||||
markerSources[i]->GetCenter()[1]-dy,
|
||||
markerSources[i]->GetCenter()[2]-dz);
|
||||
markerSources[i]->Update();
|
||||
auto &src = markerSources.at(static_cast<size_t>(i));
|
||||
const double* c = src->GetCenter();
|
||||
src->SetCenter(c[0]-dx, c[1]-dy, c[2]-dz);
|
||||
src->Update();
|
||||
|
||||
modelPoints->SetPoint(i,
|
||||
modelPoints->GetPoint(i)[0]-dx,
|
||||
modelPoints->GetPoint(i)[1]-dy,
|
||||
modelPoints->GetPoint(i)[2]-dz);
|
||||
const double* p = modelPoints->GetPoint(i);
|
||||
modelPoints->SetPoint(i, p[0]-dx, p[1]-dy, p[2]-dz);
|
||||
}
|
||||
|
||||
modelPoints->Modified();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef _GREN_H_
|
||||
#define _GREN_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <vtkImageData.h>
|
||||
#include <vtkSmartPointer.h>
|
||||
@@ -100,13 +101,17 @@ public:
|
||||
);
|
||||
|
||||
|
||||
/*clip the vol ren*/
|
||||
vtkPlanes *planes = vtkPlanes::New();
|
||||
/* clip the vol ren */
|
||||
// Keep the vtkPlanes object alive for as long as the callback lives.
|
||||
if (!this->Planes)
|
||||
{
|
||||
this->Planes = vtkSmartPointer<vtkPlanes>::New();
|
||||
}
|
||||
// The implicit function vtkPlanes is used in conjunction with the
|
||||
// volume ray cast mapper to limit which portion of the volume is
|
||||
// volume rendered.
|
||||
boxWidget->GetPlanes(planes);
|
||||
this->rcm->SetClippingPlanes(planes);
|
||||
boxWidget->GetPlanes(this->Planes);
|
||||
this->rcm->SetClippingPlanes(this->Planes);
|
||||
}
|
||||
|
||||
void setNominalGeometry(int* extents, double* bounds, double* spacing){
|
||||
@@ -124,6 +129,7 @@ private:
|
||||
double nominalBounds[6];
|
||||
int nominalExtent[6];
|
||||
double VolSpacing[3];
|
||||
vtkSmartPointer<vtkPlanes> Planes;
|
||||
};
|
||||
|
||||
|
||||
@@ -237,19 +243,19 @@ private:
|
||||
vtkSmartPointer<vtkImageData> CTvolume;
|
||||
vtkSmartPointer <vtkOutlineFilter> outline;
|
||||
vtkSmartPointer <vtkActor> outlineActor;
|
||||
vtkImageMapToColors* colorMap_X;
|
||||
vtkImagePlaneWidget* planeWidgetX;
|
||||
vtkImagePlaneWidget* planeWidgetY;
|
||||
vtkImagePlaneWidget* planeWidgetZ;
|
||||
vtkSmartPointer<vtkImageMapToColors> colorMap_X;
|
||||
vtkSmartPointer<vtkImagePlaneWidget> planeWidgetX;
|
||||
vtkSmartPointer<vtkImagePlaneWidget> planeWidgetY;
|
||||
vtkSmartPointer<vtkImagePlaneWidget> planeWidgetZ;
|
||||
QVTKOpenGLNativeWidget* qvtk;
|
||||
// vtkSmartPointer<vtkGenericOpenGLRenderWindow> myrenderWindow;
|
||||
vtkImageOrthoPlanes* orthoPlanes;
|
||||
vtkAxesActor * assi;
|
||||
vtkRenderer* ren1;
|
||||
vtkSmartPointer<vtkImageOrthoPlanes> orthoPlanes;
|
||||
vtkSmartPointer<vtkAxesActor> assi;
|
||||
vtkSmartPointer<vtkRenderer> ren1;
|
||||
|
||||
//vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper;
|
||||
//vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper;
|
||||
vtkSmartPointer<vtkVolumeMapper> volumeMapper;
|
||||
// NOTE: vtkGPUVolumeRayCastMapper is used at runtime, but we keep a
|
||||
// concrete smart pointer for stability and to avoid nullptr issues.
|
||||
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper;
|
||||
|
||||
vtkSmartPointer<vtkColorTransferFunction> color;
|
||||
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity;
|
||||
@@ -260,11 +266,11 @@ private:
|
||||
vtkSmartPointer<vtkBoxCallback> boxCallback ;
|
||||
vtkSmartPointer<vtkMyCallback> boxCallback_NEW;
|
||||
vtkSmartPointer<vtkExtractVOI> extractVOI;
|
||||
vtkBoxWidget *boxWidget_NEW;
|
||||
vtkSmartPointer<vtkBoxWidget> boxWidget_NEW;
|
||||
|
||||
vtkSphereSource** markerSources;
|
||||
vtkPolyDataMapper** markerMappers;
|
||||
vtkActor** markerActors;
|
||||
std::vector<vtkSmartPointer<vtkSphereSource>> markerSources;
|
||||
std::vector<vtkSmartPointer<vtkPolyDataMapper>> markerMappers;
|
||||
std::vector<vtkSmartPointer<vtkActor>> markerActors;
|
||||
vtkSmartPointer<vtkPoints> modelPoints;
|
||||
vtkSmartPointer<vtkActor2D> pointLabels;
|
||||
int nmarker;
|
||||
|
||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |