diff --git a/Modules/DicomRT/CMakeLists.txt b/Modules/DicomRT/CMakeLists.txt index d3e160052c..85059b0992 100644 --- a/Modules/DicomRT/CMakeLists.txt +++ b/Modules/DicomRT/CMakeLists.txt @@ -1,9 +1,10 @@ if(NOT DEFINED DCMTK_dcmrt_LIBRARY OR DCMTK_dcmrt_LIBRARY) mitk_create_module( - DEPENDS MitkSegmentation MitkSceneSerializationBase - PACKAGE_DEPENDS PUBLIC DCMTK + INCLUDE_DIRS DataStructures Rendering + DEPENDS MitkSegmentation MitkSceneSerializationBase MitkLegacyIO + PACKAGE_DEPENDS PUBLIC Qt4 Qt5|Core DCMTK ) add_subdirectory(test) else() message("MITK DicomRT Support disabled because the DCMTK dcmrt library not found") endif() diff --git a/Modules/DicomRT/files.cmake b/Modules/DicomRT/files.cmake index a6f3519f2f..f47a28b1ed 100644 --- a/Modules/DicomRT/files.cmake +++ b/Modules/DicomRT/files.cmake @@ -1,12 +1,18 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") SET(CPP_FILES mitkRTDoseReader.cpp - mitkRTStructureSetReader.cpp mitkRTConstants.cpp mitkIsoDoseLevel.cpp mitkIsoDoseLevelCollections.cpp mitkIsoDoseLevelSetProperty.cpp mitkIsoDoseLevelVectorProperty.cpp + mitkRTStructureSetReader.cpp + mitkDoseImageVtkMapper2D.cpp ) +set(TPP_FILES +) + +set(MOC_H_FILES +) diff --git a/Modules/DicomRT/include/mitkDoseImageVtkMapper2D.h b/Modules/DicomRT/include/mitkDoseImageVtkMapper2D.h new file mode 100644 index 0000000000..5a674252d5 --- /dev/null +++ b/Modules/DicomRT/include/mitkDoseImageVtkMapper2D.h @@ -0,0 +1,313 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKDoseImageVtkMapper2D2D_H_HEADER_INCLUDED +#define MITKDoseImageVtkMapper2D2D_H_HEADER_INCLUDED + +//MITK +#include +#include + +//MITK Rendering +#include "mitkBaseRenderer.h" +#include "mitkVtkMapper.h" +#include "mitkExtractSliceFilter.h" + +//VTK +#include +#include +#include + +class vtkActor; +class vtkPolyDataMapper; +class vtkPlaneSource; +class vtkImageData; +class vtkLookupTable; +class vtkImageExtractComponents; +class vtkImageReslice; +class vtkImageChangeInformation; +class vtkPoints; +class vtkMitkThickSlicesFilter; +class vtkPolyData; +class vtkMitkApplyLevelWindowToRGBFilter; +class vtkMitkLevelWindowFilter; + +namespace mitk { + + /** \brief Mapper to resample and display 2D slices of a 3D image. + * + * The following image gives a brief overview of the mapping and the involved parts. + * + * \image html DoseImageVtkMapper2Darchitecture.png + * + * First, the image is resliced by means of vtkImageReslice. The volume image + * serves as input to the mapper in addition to spatial placement of the slice and a few other + * properties such as thick slices. This code was already present in the old version + * (mitkImageMapperGL2D). + * + * Next, the obtained slice (m_ReslicedImage) is put into a vtkMitkLevelWindowFilter + * and the scalar levelwindow, opacity levelwindow and optional clipping to + * local image bounds are applied + * + * Next, the output of the vtkMitkLevelWindowFilter is used to create a texture + * (m_Texture) and a plane onto which the texture is rendered (m_Plane). For + * mapping purposes, a vtkPolyDataMapper (m_Mapper) is utilized. Orthographic + * projection is applied to create the effect of a 2D image. The mapper and the + * texture are assigned to the actor (m_Actor) which is passed to the VTK rendering + * pipeline via the method GetVtkProp(). + * + * In order to transform the textured plane to the correct position in space, the + * same transformation as used for reslicing is applied to both the camera and the + * vtkActor. All important steps are explained in more detail below. The resulting + * 2D image (by reslicing the underlying 3D input image appropriately) can either + * be directly rendered in a 2D view or just be calculated to be used later by another + * rendering entity, e.g. in texture mapping in a 3D view. + * + * Properties that can be set for images and influence the imageMapper2D are: + * + * - \b "opacity": (FloatProperty) Opacity of the image + * - \b "color": (ColorProperty) Color of the image + * - \b "LookupTable": (mitkLookupTableProperty) If this property is set, + * the default lookuptable will be ignored and the "LookupTable" value + * will be used instead. + * - \b "Image Rendering.Mode": This property decides which mode is used to render images. (E.g. if a lookup table or a transferfunction is applied). Detailed documentation about the modes can be found here: \link mitk::RenderingerModeProperty \endlink + * - \b "Image Rendering.Transfer Function": (mitkTransferFunctionProperty) If this + * property is set, a color transferfunction will be used to color the image. + * - \b "binary": (BoolProperty) is the image a binary image or not + * - \b "outline binary": (BoolProperty) show outline of the image or not + * - \b "texture interpolation": (BoolProperty) texture interpolation of the image + * - \b "reslice interpolation": (VtkResliceInterpolationProperty) reslice interpolation of the image + * - \b "in plane resample extent by geometry": (BoolProperty) Do it or not + * - \b "bounding box": (BoolProperty) Is the Bounding Box of the image shown or not + * - \b "layer": (IntProperty) Layer of the image + * - \b "volume annotation color": (ColorProperty) color of the volume annotation, TODO has to be reimplemented + * - \b "volume annotation unit": (StringProperty) annotation unit as string (does not implicit convert the unit!) + unit is ml or cm3, TODO has to be reimplemented + + * The default properties are: + + * - \b "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ) + * - \b "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ) + * - \b "binary", mitk::BoolProperty::New( true ), renderer, overwrite ) + * - \b "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ) + * - \b "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ) + * - \b "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ) + * - \b "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ) + * - \b "bounding box", mitk::BoolProperty::New( false ) ) + * - \b "layer", mitk::IntProperty::New(10), renderer, overwrite) + * - \b "Image Rendering.Transfer Function": Default color transfer function for CTs + * - \b "LookupTable": Rainbow color. + + * If the modality-property is set for an image, the mapper uses modality-specific default properties, + * e.g. color maps, if they are defined. + + * \ingroup Mapper + */ + class MITKDICOMRT_EXPORT DoseImageVtkMapper2D : public VtkMapper + { + + public: + /** Standard class typedefs. */ + mitkClassMacro( DoseImageVtkMapper2D,VtkMapper ); + + /** Method for creation through the object factory. */ + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + /** \brief Get the Image to map */ + const mitk::Image *GetInput(void); + + /** \brief Checks whether this mapper needs to update itself and generate + * data. */ + virtual void Update(mitk::BaseRenderer * renderer); + + //### methods of MITK-VTK rendering pipeline + virtual vtkProp* GetVtkProp(mitk::BaseRenderer* renderer); + //### end of methods of MITK-VTK rendering pipeline + + + /** \brief Internal class holding the mapper, actor, etc. for each of the 3 2D render windows */ + /** + * To render transveral, coronal, and sagittal, the mapper is called three times. + * For performance reasons, the corresponding data for each view is saved in the + * internal helper class LocalStorage. This allows rendering n views with just + * 1 mitkMapper using n vtkMapper. + * */ + class MITKCORE_EXPORT LocalStorage : public mitk::Mapper::BaseLocalStorage + { + public: + /** \brief Actor of a 2D render window. */ + vtkSmartPointer m_Actor; + + vtkSmartPointer m_Actors; + /** \brief Mapper of a 2D render window. */ + vtkSmartPointer m_Mapper; + vtkSmartPointer m_VectorComponentExtractor; + /** \brief Current slice of a 2D render window.*/ + vtkSmartPointer m_ReslicedImage; + /** \brief Empty vtkPolyData that is set when rendering geometry does not + * intersect the image geometry. + * \warning This member variable is set to NULL, + * if no image geometry is inside the plane geometry + * of the respective render window. Any user of this + * slice has to check whether it is set to NULL! + */ + vtkSmartPointer m_EmptyPolyData; + /** \brief Plane on which the slice is rendered as texture. */ + vtkSmartPointer m_Plane; + /** \brief The texture which is used to render the current slice. */ + vtkSmartPointer m_Texture; + /** \brief The lookuptables for colors and level window */ + vtkSmartPointer m_DefaultLookupTable; + vtkSmartPointer m_BinaryLookupTable; + vtkSmartPointer m_ColorLookupTable; + /** \brief The actual reslicer (one per renderer) */ + mitk::ExtractSliceFilter::Pointer m_Reslicer; + /** \brief Filter for thick slices */ + vtkSmartPointer m_TSFilter; + /** \brief PolyData object containg all lines/points needed for outlining the contour. + This container is used to save a computed contour for the next rendering execution. + For instance, if you zoom or pann, there is no need to recompute the contour. */ + vtkSmartPointer m_OutlinePolyData; + + /** \brief Timestamp of last update of stored data. */ + itk::TimeStamp m_LastUpdateTime; + + /** \brief mmPerPixel relation between pixel and mm. (World spacing).*/ + mitk::ScalarType* m_mmPerPixel; + + /** \brief This filter is used to apply the level window to Grayvalue and RBG(A) images. */ + vtkSmartPointer m_LevelWindowFilter; + + /** \brief Default constructor of the local storage. */ + LocalStorage(); + /** \brief Default deconstructor of the local storage. */ + ~LocalStorage(); + }; + + /** \brief The LocalStorageHandler holds all (three) LocalStorages for the three 2D render windows. */ + mitk::LocalStorageHandler m_LSH; + + /** \brief Get the LocalStorage corresponding to the current renderer. */ + LocalStorage* GetLocalStorage(mitk::BaseRenderer* renderer); + + /** \brief Set the default properties for general image rendering. */ + static void SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer = NULL, bool overwrite = false); + + /** \brief This method switches between different rendering modes (e.g. use a lookup table or a transfer function). + * Detailed documentation about the modes can be found here: \link mitk::RenderingerModeProperty \endlink + */ + void ApplyRenderingMode(mitk::BaseRenderer *renderer); + + protected: + /** \brief Transforms the actor to the actual position in 3D. + * \param renderer The current renderer corresponding to the render window. + */ + void TransformActor(mitk::BaseRenderer* renderer); + + /** \brief Generates a plane according to the size of the resliced image in milimeters. + * + * \image html texturedPlane.png + * + * In VTK a vtkPlaneSource is defined through three points. The origin and two + * points defining the axes of the plane (see VTK documentation). The origin is + * set to (xMin; yMin; Z), where xMin and yMin are the minimal bounds of the + * resliced image in space. Z is relevant for blending and the layer property. + * The center of the plane (C) is also the center of the view plane (cf. the image above). + * + * \note For the standard MITK view with three 2D render windows showing three + * different slices, three such planes are generated. All these planes are generated + * in the XY-plane (even if they depict a YZ-slice of the volume). + * + */ + void GeneratePlane(mitk::BaseRenderer* renderer, double planeBounds[6]); + + /** \brief Generates a vtkPolyData object containing the outline of a given binary slice. + \param renderer: Pointer to the renderer containing the needed information + \note This code is based on code from the iil library. + */ + vtkSmartPointer CreateOutlinePolyData(mitk::BaseRenderer* renderer); + + /** Default constructor */ + DoseImageVtkMapper2D(); + /** Default deconstructor */ + virtual ~DoseImageVtkMapper2D(); + + /** \brief Does the actual resampling, without rendering the image yet. + * All the data is generated inside this method. The vtkProp (or Actor) + * is filled with content (i.e. the resliced image). + * + * After generation, a 4x4 transformation matrix(t) of the current slice is obtained + * from the vtkResliceImage object via GetReslicesAxis(). This matrix is + * applied to each textured plane (actor->SetUserTransform(t)) to transform everything + * to the actual 3D position (cf. the following image). + * + * \image html cameraPositioning3D.png + * + */ + virtual void GenerateDataForRenderer(mitk::BaseRenderer *renderer); + + /** \brief This method uses the vtkCamera clipping range and the layer property + * to calcualte the depth of the object (e.g. image or contour). The depth is used + * to keep the correct order for the final VTK rendering.*/ + float CalculateLayerDepth(mitk::BaseRenderer* renderer); + + /** \brief This method applies (or modifies) the lookuptable for all types of images. + * \warning To use the lookup table, the property 'Lookup Table' must be set and a 'Image Rendering.Mode' + * which uses the lookup table must be set. + */ + void ApplyLookuptable(mitk::BaseRenderer* renderer); + + /** \brief This method applies a color transfer function. + * Internally, a vtkColorTransferFunction is used. This is usefull for coloring continous + * images (e.g. float) + * \warning To use the color transfer function, the property 'Image Rendering.Transfer Function' must be set and a 'Image Rendering.Mode' which uses the color transfer function must be set. + */ + void ApplyColorTransferFunction(mitk::BaseRenderer* renderer); + + /** + * @brief ApplyLevelWindow Apply the level window for the given renderer. + * \warning To use the level window, the property 'LevelWindow' must be set and a 'Image Rendering.Mode' which uses the level window must be set. + * @param renderer Level window for which renderer? + */ + void ApplyLevelWindow(mitk::BaseRenderer* renderer); + + /** \brief Set the color of the image/polydata */ + void ApplyColor( mitk::BaseRenderer* renderer ); + + /** \brief Set the opacity of the actor. */ + void ApplyOpacity( mitk::BaseRenderer* renderer ); + + /** + * \brief Calculates whether the given rendering geometry intersects the + * given SlicedGeometry3D. + * + * This method checks if the given PlaneGeometry intersects the given + * SlicedGeometry3D. It calculates the distance of the PlaneGeometry to all + * 8 cornerpoints of the SlicedGeometry3D. If all distances have the same + * sign (all positive or all negative) there is no intersection. + * If the distances have different sign, there is an intersection. + **/ + bool RenderingGeometryIntersectsImage( const PlaneGeometry* renderingGeometry, SlicedGeometry3D* imageGeometry ); + + private: + void CreateLevelOutline(mitk::BaseRenderer* renderer, const mitk::IsoDoseLevel* level, float pref, vtkSmartPointer points, vtkSmartPointer lines, vtkSmartPointer colors); + + }; + +} // namespace mitk + +#endif /* MITKDoseImageVtkMapper2D_H_HEADER_INCLUDED_C10E906E */ diff --git a/Modules/DicomRT/include/mitkRTConstants.h b/Modules/DicomRT/include/mitkRTConstants.h index 54c1009e55..e5d1990407 100644 --- a/Modules/DicomRT/include/mitkRTConstants.h +++ b/Modules/DicomRT/include/mitkRTConstants.h @@ -1,87 +1,89 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef _MITK_RT_CONSTANTS_H_ #define _MITK_RT_CONSTANTS_H_ #include #include "MitkDicomRTExports.h" namespace mitk { -struct MITKDICOMRT_EXPORT Constants + +struct MITKDICOMRT_EXPORT RTConstants + { /** * Name of the property that indicates if a data/node is a dose. */ static const std::string DOSE_PROPERTY_NAME; /** * Name of the property that encodes the prescribed dose associated with the data node * If a RTPLAN file exists the value can be extracted from the tag (300A,0026) - Target Prescription Dose in the plan file. */ static const std::string PRESCRIBED_DOSE_PROPERTY_NAME; /** * Name of the property that encodes the reference dose that should be used for relative dose vizualization/evaluation purpose. * It is often the prescribed dose but may differ e.g. when to dose distributions sould be compared using the same reference. */ static const std::string REFERENCE_DOSE_PROPERTY_NAME; /** * Name of the property that encodes the optional string property holding the information from the tag (3004,0004) - Dose Type. * This contains useful information for medical doctors */ static const std::string DOSE_TYPE_PROPERTY_NAME; /** * Name of the property that encodes the optional string property holding the information from the tag (3004,000A) - Dose Summation Type. * This contains useful information for medical doctors */ static const std::string DOSE_SUMMATION_TYPE_PROPERTY_NAME; /** * Name of the property that encodes the number of fractions. * It is for example in DICOM stored in tag (300A,0078) - Number of Fractions Prescribed (from the RTPLAN file if this file exists). * This value could be used to further scale the dose according to dose summation type. * For example a given plan consists of 8 fractions. Scaling the fraction dose by 8 gives the complete planned dose. */ static const std::string DOSE_FRACTION_COUNT_PROPERTY_NAME; /** * Name of the property that encodes if the iso line rendering should be activated for the node. */ static const std::string DOSE_SHOW_ISOLINES_PROPERTY_NAME; /** * Name of the property that encodes if the color wash rendering should be activated for the node. */ static const std::string DOSE_SHOW_COLORWASH_PROPERTY_NAME; /** * Name of the property that encodes if the set of iso levels should be used to visualize the dose distribution. */ static const std::string DOSE_ISO_LEVELS_PROPERTY_NAME; /** * Name of the property that encodes user defined iso values that mark special dose values in the distribution. */ static const std::string DOSE_FREE_ISO_VALUES_PROPERTY_NAME; }; } #endif diff --git a/Modules/DicomRT/include/mitkRTDoseReader.h b/Modules/DicomRT/include/mitkRTDoseReader.h index 2142547ea2..c37a10885b 100644 --- a/Modules/DicomRT/include/mitkRTDoseReader.h +++ b/Modules/DicomRT/include/mitkRTDoseReader.h @@ -1,86 +1,88 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkDicomRTReader_h #define mitkDicomRTReader_h #include #include #include #include #include "dcmtk/dcmrt/drtdose.h" #include #include #include namespace mitk { class MITKDICOMRT_EXPORT RTDoseReader: public itk::Object { public: mitkClassMacroItkParent( RTDoseReader, itk::Object ); itkNewMacro( Self ); template void MultiplayGridScaling( itk::Image< TPixel, VImageDimension>* image, Float32 gridscale); /** * @brief Get the maximum dose value from the dose file * @param dataSet The DcmDataset of the DicomRTDose file * @return The dose value * * Checks all pixel values for the maximum value */ double GetMaxDoseValue(DcmDataset* dataSet); /** * @brief Reads a DcmDataset from a DicomRT dose file * @param dataset DcmDataset-object from DCMTK * @param filename The path with the dose file used for getting the geometry * @return Returns a mitkDataNode::Pointer in which a mitk::Image is stored * * The method reads the PixelData from the DicomRT dose file and scales * them with a factor for getting Gray-values instead of pixel-values. * The Gray-values are stored in a mitkImage with a vtkColorTransferFunc. * Relative values are used for coloring the image. The relative values are * relative to a PrescriptionDose definied in the RT-Plan. If there is no * RT-Plan file PrescriptionDose is set to 80% of the maximum dose. */ mitk::DataNode::Pointer LoadRTDose(const char* filename); /** * Virtual destructor. */ virtual ~RTDoseReader(); protected: + mitk::Image::Pointer scaledDoseImage; + /** * Constructor. */ RTDoseReader(); }; } #endif diff --git a/Modules/DicomRT/src/mitkDoseImageVtkMapper2D.cpp b/Modules/DicomRT/src/mitkDoseImageVtkMapper2D.cpp new file mode 100644 index 0000000000..2e11fed07a --- /dev/null +++ b/Modules/DicomRT/src/mitkDoseImageVtkMapper2D.cpp @@ -0,0 +1,1104 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +//MITK +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mitkImageStatisticsHolder.h" +#include "mitkPlaneClipping.h" + +//MITK Rendering +#include "mitkDoseImageVtkMapper2D.h" + +#include "vtkMitkThickSlicesFilter.h" +#include "vtkMitkLevelWindowFilter.h" +#include "vtkNeverTranslucentTexture.h" + +//VTK +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//ITK +#include + +mitk::DoseImageVtkMapper2D::DoseImageVtkMapper2D() +{ +} + +mitk::DoseImageVtkMapper2D::~DoseImageVtkMapper2D() +{ + //The 3D RW Mapper (PlaneGeometryDataVtkMapper3D) is listening to this event, + //in order to delete the images from the 3D RW. + this->InvokeEvent( itk::DeleteEvent() ); +} + +//set the two points defining the textured plane according to the dimension and spacing +void mitk::DoseImageVtkMapper2D::GeneratePlane(mitk::BaseRenderer* renderer, double planeBounds[6]) +{ + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + + float depth = this->CalculateLayerDepth(renderer); + //Set the origin to (xMin; yMin; depth) of the plane. This is necessary for obtaining the correct + //plane size in crosshair rotation and swivel mode. + localStorage->m_Plane->SetOrigin(planeBounds[0], planeBounds[2], depth); + //These two points define the axes of the plane in combination with the origin. + //Point 1 is the x-axis and point 2 the y-axis. + //Each plane is transformed according to the view (axial, coronal and saggital) afterwards. + localStorage->m_Plane->SetPoint1(planeBounds[1] , planeBounds[2], depth); //P1: (xMax, yMin, depth) + localStorage->m_Plane->SetPoint2(planeBounds[0], planeBounds[3], depth); //P2: (xMin, yMax, depth) +} + +float mitk::DoseImageVtkMapper2D::CalculateLayerDepth(mitk::BaseRenderer* renderer) +{ + //get the clipping range to check how deep into z direction we can render images + double maxRange = renderer->GetVtkRenderer()->GetActiveCamera()->GetClippingRange()[1]; + + //Due to a VTK bug, we cannot use the whole clipping range. /100 is empirically determined + float depth = -maxRange*0.01; // divide by 100 + int layer = 0; + GetDataNode()->GetIntProperty( "layer", layer, renderer); + //add the layer property for each image to render images with a higher layer on top of the others + depth += layer*10; //*10: keep some room for each image (e.g. for QBalls in between) + if(depth > 0.0f) { + depth = 0.0f; + MITK_WARN << "Layer value exceeds clipping range. Set to minimum instead."; + } + return depth; +} + +const mitk::Image* mitk::DoseImageVtkMapper2D::GetInput( void ) +{ + return static_cast< const mitk::Image * >( GetDataNode()->GetData() ); +} + +vtkProp* mitk::DoseImageVtkMapper2D::GetVtkProp(mitk::BaseRenderer* renderer) +{ + //return the actor corresponding to the renderer + return m_LSH.GetLocalStorage(renderer)->m_Actors; +} + +void mitk::DoseImageVtkMapper2D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) +{ + + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + + mitk::Image *input = const_cast< mitk::Image * >( this->GetInput() ); + mitk::DataNode* datanode = this->GetDataNode(); + + if ( input == NULL || input->IsInitialized() == false ) + { + return; + } + + //check if there is a valid worldGeometry + const PlaneGeometry *worldGeometry = renderer->GetCurrentWorldPlaneGeometry(); + if( ( worldGeometry == NULL ) || ( !worldGeometry->IsValid() ) || ( !worldGeometry->HasReferenceGeometry() )) + { + return; + } + + input->Update(); + + // early out if there is no intersection of the current rendering geometry + // and the geometry of the image that is to be rendered. + if ( !RenderingGeometryIntersectsImage( worldGeometry, input->GetSlicedGeometry() ) ) + { + // set image to NULL, to clear the texture in 3D, because + // the latest image is used there if the plane is out of the geometry + // see bug-13275 + localStorage->m_ReslicedImage = NULL; + localStorage->m_Mapper->SetInputData( localStorage->m_EmptyPolyData ); + return; + } + + //set main input for ExtractSliceFilter + localStorage->m_Reslicer->SetInput(input); + localStorage->m_Reslicer->SetWorldGeometry(worldGeometry); + localStorage->m_Reslicer->SetTimeStep( this->GetTimestep() ); + + //set the transformation of the image to adapt reslice axis + localStorage->m_Reslicer->SetResliceTransformByGeometry( input->GetTimeGeometry()->GetGeometryForTimeStep( this->GetTimestep() ) ); + + //is the geometry of the slice based on the input image or the worldgeometry? + bool inPlaneResampleExtentByGeometry = false; + datanode->GetBoolProperty("in plane resample extent by geometry", inPlaneResampleExtentByGeometry, renderer); + localStorage->m_Reslicer->SetInPlaneResampleExtentByGeometry(inPlaneResampleExtentByGeometry); + + // Initialize the interpolation mode for resampling; switch to nearest + // neighbor if the input image is too small. + if ( (input->GetDimension() >= 3) && (input->GetDimension(2) > 1) ) + { + VtkResliceInterpolationProperty *resliceInterpolationProperty; + datanode->GetProperty( + resliceInterpolationProperty, "reslice interpolation" ); + + int interpolationMode = VTK_RESLICE_NEAREST; + if ( resliceInterpolationProperty != NULL ) + { + interpolationMode = resliceInterpolationProperty->GetInterpolation(); + } + + switch ( interpolationMode ) + { + case VTK_RESLICE_NEAREST: + localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); + break; + case VTK_RESLICE_LINEAR: + localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_LINEAR); + break; + case VTK_RESLICE_CUBIC: + localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_CUBIC); + break; + } + } + else + { + localStorage->m_Reslicer->SetInterpolationMode(ExtractSliceFilter::RESLICE_NEAREST); + } + + //set the vtk output property to true, makes sure that no unneeded mitk image convertion + //is done. + localStorage->m_Reslicer->SetVtkOutputRequest(true); + + //Thickslicing + int thickSlicesMode = 0; + int thickSlicesNum = 1; + // Thick slices parameters + if( input->GetPixelType().GetNumberOfComponents() == 1 ) // for now only single component are allowed + { + DataNode *dn=renderer->GetCurrentWorldPlaneGeometryNode(); + if(dn) + { + ResliceMethodProperty *resliceMethodEnumProperty=0; + + if( dn->GetProperty( resliceMethodEnumProperty, "reslice.thickslices" ) && resliceMethodEnumProperty ) + thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); + + IntProperty *intProperty=0; + if( dn->GetProperty( intProperty, "reslice.thickslices.num" ) && intProperty ) + { + thickSlicesNum = intProperty->GetValue(); + if(thickSlicesNum < 1) thickSlicesNum=1; + if(thickSlicesNum > 10) thickSlicesNum=10; + } + } + else + { + MITK_WARN << "no associated widget plane data tree node found"; + } + } + + const PlaneGeometry *planeGeometry = dynamic_cast< const PlaneGeometry * >( worldGeometry ); + + if(thickSlicesMode > 0) + { + double dataZSpacing = 1.0; + + Vector3D normInIndex, normal; + + if ( planeGeometry != NULL ){ + normal = planeGeometry->GetNormal(); + }else{ + const mitk::AbstractTransformGeometry* abstractGeometry = dynamic_cast< const AbstractTransformGeometry * >(worldGeometry); + if(abstractGeometry != NULL) + normal = abstractGeometry->GetPlane()->GetNormal(); + else + return; //no fitting geometry set + } + normal.Normalize(); + + input->GetTimeGeometry()->GetGeometryForTimeStep( this->GetTimestep() )->WorldToIndex( normal, normInIndex ); + + dataZSpacing = 1.0 / normInIndex.GetNorm(); + + localStorage->m_Reslicer->SetOutputDimensionality( 3 ); + localStorage->m_Reslicer->SetOutputSpacingZDirection(dataZSpacing); + localStorage->m_Reslicer->SetOutputExtentZDirection( -thickSlicesNum, 0+thickSlicesNum ); + + // Do the reslicing. Modified() is called to make sure that the reslicer is + // executed even though the input geometry information did not change; this + // is necessary when the input /em data, but not the /em geometry changes. + localStorage->m_TSFilter->SetThickSliceMode( thickSlicesMode-1 ); + localStorage->m_TSFilter->SetInputData( localStorage->m_Reslicer->GetVtkOutput() ); + + //vtkFilter=>mitkFilter=>vtkFilter update mechanism will fail without calling manually + localStorage->m_Reslicer->Modified(); + localStorage->m_Reslicer->Update(); + + localStorage->m_TSFilter->Modified(); + localStorage->m_TSFilter->Update(); + localStorage->m_ReslicedImage = localStorage->m_TSFilter->GetOutput(); + } + else + { + //this is needed when thick mode was enable bevore. These variable have to be reset to default values + localStorage->m_Reslicer->SetOutputDimensionality( 2 ); + localStorage->m_Reslicer->SetOutputSpacingZDirection(1.0); + localStorage->m_Reslicer->SetOutputExtentZDirection( 0, 0 ); + + + localStorage->m_Reslicer->Modified(); + //start the pipeline with updating the largest possible, needed if the geometry of the input has changed + localStorage->m_Reslicer->UpdateLargestPossibleRegion(); + localStorage->m_ReslicedImage = localStorage->m_Reslicer->GetVtkOutput(); + } + + // Bounds information for reslicing (only reuqired if reference geometry + // is present) + //this used for generating a vtkPLaneSource with the right size + double sliceBounds[6]; + for ( int i = 0; i < 6; ++i ) + { + sliceBounds[i] = 0.0; + } + localStorage->m_Reslicer->GetClippedPlaneBounds(sliceBounds); + + //get the spacing of the slice + localStorage->m_mmPerPixel = localStorage->m_Reslicer->GetOutputSpacing(); + + // calculate minimum bounding rect of IMAGE in texture + { + double textureClippingBounds[6]; + for ( int i = 0; i < 6; ++i ) + { + textureClippingBounds[i] = 0.0; + } + // Calculate the actual bounds of the transformed plane clipped by the + // dataset bounding box; this is required for drawing the texture at the + // correct position during 3D mapping. + mitk::PlaneClipping::CalculateClippedPlaneBounds( input->GetGeometry(), planeGeometry, textureClippingBounds ); + + textureClippingBounds[0] = static_cast< int >( textureClippingBounds[0] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[1] = static_cast< int >( textureClippingBounds[1] / localStorage->m_mmPerPixel[0] + 0.5 ); + textureClippingBounds[2] = static_cast< int >( textureClippingBounds[2] / localStorage->m_mmPerPixel[1] + 0.5 ); + textureClippingBounds[3] = static_cast< int >( textureClippingBounds[3] / localStorage->m_mmPerPixel[1] + 0.5 ); + + //clipping bounds for cutting the image + localStorage->m_LevelWindowFilter->SetClippingBounds(textureClippingBounds); + } + + //get the number of scalar components to distinguish between different image types + int numberOfComponents = localStorage->m_ReslicedImage->GetNumberOfScalarComponents(); + //get the showIsoLines property + bool showIsoLines = false; + datanode->GetBoolProperty( "dose.showIsoLines", showIsoLines, renderer ); + + if(showIsoLines) //contour rendering + { + //generate contours/outlines + localStorage->m_OutlinePolyData = CreateOutlinePolyData(renderer); + + float binaryOutlineWidth(1.0); + if ( datanode->GetFloatProperty( "outline width", binaryOutlineWidth, renderer ) ) + { + if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) + { + float binaryOutlineShadowWidth(1.5); + datanode->GetFloatProperty( "outline shadow width", binaryOutlineShadowWidth, renderer ); + + dynamic_cast(localStorage->m_Actors->GetParts()->GetItemAsObject(0)) + ->GetProperty()->SetLineWidth( binaryOutlineWidth * binaryOutlineShadowWidth ); + } + + localStorage->m_Actor->GetProperty()->SetLineWidth( binaryOutlineWidth ); + } + } + else + { + localStorage->m_ReslicedImage = NULL; + localStorage->m_Mapper->SetInputData( localStorage->m_EmptyPolyData ); + return; + } + + this->ApplyOpacity( renderer ); + this->ApplyRenderingMode(renderer); + + // do not use a VTK lookup table (we do that ourselves in m_LevelWindowFilter) + localStorage->m_Texture->MapColorScalarsThroughLookupTableOff(); + + int displayedComponent = 0; + + if (datanode->GetIntProperty("Image.Displayed Component", displayedComponent, renderer) && numberOfComponents > 1) + { + localStorage->m_VectorComponentExtractor->SetComponents(displayedComponent); + localStorage->m_VectorComponentExtractor->SetInputData(localStorage->m_ReslicedImage); + + localStorage->m_LevelWindowFilter->SetInputConnection(localStorage->m_VectorComponentExtractor->GetOutputPort(0)); + } + else + { + //connect the input with the levelwindow filter + localStorage->m_LevelWindowFilter->SetInputData(localStorage->m_ReslicedImage); + } + + // check for texture interpolation property + bool textureInterpolation = false; + GetDataNode()->GetBoolProperty( "texture interpolation", textureInterpolation, renderer ); + + //set the interpolation modus according to the property + localStorage->m_Texture->SetInterpolate(textureInterpolation); + + // connect the texture with the output of the levelwindow filter + localStorage->m_Texture->SetInputConnection(localStorage->m_LevelWindowFilter->GetOutputPort()); + + this->TransformActor( renderer ); + + vtkActor* contourShadowActor = dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0)); + + if(showIsoLines) //connect the mapper with the polyData which contains the lines + { + //We need the contour for the binary outline property as actor + localStorage->m_Mapper->SetInputData(localStorage->m_OutlinePolyData); + localStorage->m_Actor->SetTexture(NULL); //no texture for contours + + bool binaryOutlineShadow( false ); + datanode->GetBoolProperty( "outline binary shadow", binaryOutlineShadow, renderer ); + + if ( binaryOutlineShadow ) + contourShadowActor->SetVisibility( true ); + else + contourShadowActor->SetVisibility( false ); + } + else + { //Connect the mapper with the input texture. This is the standard case. + //setup the textured plane + this->GeneratePlane( renderer, sliceBounds ); + //set the plane as input for the mapper + localStorage->m_Mapper->SetInputConnection(localStorage->m_Plane->GetOutputPort()); + //set the texture for the actor + + localStorage->m_Actor->SetTexture(localStorage->m_Texture); + contourShadowActor->SetVisibility( false ); + } + + // We have been modified => save this for next Update() + localStorage->m_LastUpdateTime.Modified(); +} + +void mitk::DoseImageVtkMapper2D::ApplyLevelWindow(mitk::BaseRenderer *renderer) +{ + LocalStorage *localStorage = this->GetLocalStorage( renderer ); + + LevelWindow levelWindow; + this->GetDataNode()->GetLevelWindow( levelWindow, renderer, "levelwindow" ); + localStorage->m_LevelWindowFilter->GetLookupTable()->SetRange( levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound() ); + + mitk::LevelWindow opacLevelWindow; + if( this->GetDataNode()->GetLevelWindow( opacLevelWindow, renderer, "opaclevelwindow" ) ) + { + //pass the opaque level window to the filter + localStorage->m_LevelWindowFilter->SetMinOpacity(opacLevelWindow.GetLowerWindowBound()); + localStorage->m_LevelWindowFilter->SetMaxOpacity(opacLevelWindow.GetUpperWindowBound()); + } + else + { + //no opaque level window + localStorage->m_LevelWindowFilter->SetMinOpacity(0.0); + localStorage->m_LevelWindowFilter->SetMaxOpacity(255.0); + } +} + +void mitk::DoseImageVtkMapper2D::ApplyColor( mitk::BaseRenderer* renderer ) +{ + LocalStorage *localStorage = this->GetLocalStorage( renderer ); + + float rgb[3]= { 1.0f, 1.0f, 1.0f }; + + // check for color prop and use it for rendering if it exists + // binary image hovering & binary image selection + bool hover = false; + bool selected = false; + GetDataNode()->GetBoolProperty("binaryimage.ishovering", hover, renderer); + GetDataNode()->GetBoolProperty("selected", selected, renderer); + if(hover && !selected) + { + mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty + ("binaryimage.hoveringcolor", renderer)); + if(colorprop.IsNotNull()) + { + memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); + } + else + { + GetDataNode()->GetColor( rgb, renderer, "color" ); + } + } + if(selected) + { + mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty + ("binaryimage.selectedcolor", renderer)); + if(colorprop.IsNotNull()) { + memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); + } + else + { + GetDataNode()->GetColor(rgb, renderer, "color"); + } + } + if(!hover && !selected) + { + GetDataNode()->GetColor( rgb, renderer, "color" ); + } + + double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK + dynamic_cast (localStorage->m_Actors->GetParts()->GetItemAsObject(0))->GetProperty()->SetColor(rgbConv); + localStorage->m_Actor->GetProperty()->SetColor(rgbConv); + + if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + { + float rgb[3]= { 1.0f, 1.0f, 1.0f }; + mitk::ColorProperty::Pointer colorprop = dynamic_cast(GetDataNode()->GetProperty + ("outline binary shadow color", renderer)); + if(colorprop.IsNotNull()) + { + memcpy(rgb, colorprop->GetColor().GetDataPointer(), 3*sizeof(float)); + } + double rgbConv[3] = {(double)rgb[0], (double)rgb[1], (double)rgb[2]}; //conversion to double for VTK + dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetColor(rgbConv); + } +} + +void mitk::DoseImageVtkMapper2D::ApplyOpacity( mitk::BaseRenderer* renderer ) +{ + LocalStorage* localStorage = this->GetLocalStorage( renderer ); + float opacity = 1.0f; + // check for opacity prop and use it for rendering if it exists + GetDataNode()->GetOpacity( opacity, renderer, "opacity" ); + //set the opacity according to the properties + localStorage->m_Actor->GetProperty()->SetOpacity(opacity); + if ( localStorage->m_Actors->GetParts()->GetNumberOfItems() > 1 ) + { + dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) )->GetProperty()->SetOpacity(opacity); + } +} + +void mitk::DoseImageVtkMapper2D::ApplyRenderingMode( mitk::BaseRenderer* renderer ) +{ + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + + bool binary = false; + this->GetDataNode()->GetBoolProperty( "binary", binary, renderer ); + if(binary) // is it a binary image? + { + //for binary images, we always use our default LuT and map every value to (0,1) + //the opacity of 0 will always be 0.0. We never a apply a LuT/TfF nor a level window. + localStorage->m_LevelWindowFilter->SetLookupTable(localStorage->m_BinaryLookupTable); + } + else + { + //all other image types can make use of the rendering mode + int renderingMode = mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR; + mitk::RenderingModeProperty::Pointer mode = dynamic_cast(this->GetDataNode()->GetProperty( "Image Rendering.Mode", renderer )); + if(mode.IsNotNull()) + { + renderingMode = mode->GetRenderingMode(); + } + switch(renderingMode) + { + case mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_LookupTable_Color"; + this->ApplyLookuptable( renderer ); + this->ApplyLevelWindow( renderer ); + break; + case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_LEVELWINDOW_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LevelWindow_ColorTransferFunction_Color"; + this->ApplyColorTransferFunction( renderer ); + this->ApplyLevelWindow( renderer ); + break; + case mitk::RenderingModeProperty::LOOKUPTABLE_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = LookupTable_Color"; + this->ApplyLookuptable( renderer ); + break; + case mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR: + MITK_DEBUG << "'Image Rendering.Mode' = ColorTransferFunction_Color"; + this->ApplyColorTransferFunction( renderer ); + break; + default: + MITK_ERROR << "No valid 'Image Rendering.Mode' set. Using LOOKUPTABLE_LEVELWINDOW_COLOR instead."; + this->ApplyLookuptable( renderer ); + this->ApplyLevelWindow( renderer ); + break; + } + } + //we apply color for all images (including binaries). + this->ApplyColor( renderer ); +} + +void mitk::DoseImageVtkMapper2D::ApplyLookuptable( mitk::BaseRenderer* renderer ) +{ + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + vtkLookupTable* usedLookupTable = localStorage->m_ColorLookupTable; + + // If lookup table or transferfunction use is requested... + mitk::LookupTableProperty::Pointer lookupTableProp = dynamic_cast(this->GetDataNode()->GetProperty("LookupTable")); + + if( lookupTableProp.IsNotNull() ) // is a lookuptable set? + { + usedLookupTable = lookupTableProp->GetLookupTable()->GetVtkLookupTable(); + } + else + { + //"Image Rendering.Mode was set to use a lookup table but there is no property 'LookupTable'. + //A default (rainbow) lookup table will be used. + //Here have to do nothing. Warning for the user has been removed, due to unwanted console output + //in every interation of the rendering. + } + localStorage->m_LevelWindowFilter->SetLookupTable(usedLookupTable); +} + +void mitk::DoseImageVtkMapper2D::ApplyColorTransferFunction(mitk::BaseRenderer *renderer) +{ + mitk::TransferFunctionProperty::Pointer transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("Image Rendering.Transfer Function",renderer )); + + if( transferFunctionProp.IsNull() ) + { + MITK_ERROR << "'Image Rendering.Mode'' was set to use a color transfer function but there is no property 'Image Rendering.Transfer Function'. Nothing will be done."; + return; + } + LocalStorage* localStorage = m_LSH.GetLocalStorage(renderer); + //pass the transfer function to our level window filter + localStorage->m_LevelWindowFilter->SetLookupTable(transferFunctionProp->GetValue()->GetColorTransferFunction()); +} + +void mitk::DoseImageVtkMapper2D::Update(mitk::BaseRenderer* renderer) +{ + + bool visible = true; + GetDataNode()->GetVisibility(visible, renderer, "visible"); + + if ( !visible ) + { + return; + } + + mitk::Image* data = const_cast( this->GetInput() ); + if ( data == NULL ) + { + return; + } + + // Calculate time step of the input data for the specified renderer (integer value) + this->CalculateTimeStep( renderer ); + + // Check if time step is valid + const TimeGeometry *dataTimeGeometry = data->GetTimeGeometry(); + if ( ( dataTimeGeometry == NULL ) + || ( dataTimeGeometry->CountTimeSteps() == 0 ) + || ( !dataTimeGeometry->IsValidTimeStep( this->GetTimestep() ) ) ) + { + return; + } + + const DataNode *node = this->GetDataNode(); + data->UpdateOutputInformation(); + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + + //check if something important has changed and we need to rerender + if ( (localStorage->m_LastUpdateTime < node->GetMTime()) //was the node modified? + || (localStorage->m_LastUpdateTime < data->GetPipelineMTime()) //Was the data modified? + || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometryUpdateTime()) //was the geometry modified? + || (localStorage->m_LastUpdateTime < renderer->GetCurrentWorldPlaneGeometry()->GetMTime()) + || (localStorage->m_LastUpdateTime < node->GetPropertyList()->GetMTime()) //was a property modified? + || (localStorage->m_LastUpdateTime < node->GetPropertyList(renderer)->GetMTime()) ) + { + this->GenerateDataForRenderer( renderer ); + } + + // since we have checked that nothing important has changed, we can set + // m_LastUpdateTime to the current time + localStorage->m_LastUpdateTime.Modified(); +} + +void mitk::DoseImageVtkMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) +{ + mitk::Image::Pointer image = dynamic_cast(node->GetData()); + + // Properties common for both images and segmentations + node->AddProperty( "depthOffset", mitk::FloatProperty::New( 0.0 ), renderer, overwrite ); + node->AddProperty( "outline binary", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "outline width", mitk::FloatProperty::New( 1.0 ), renderer, overwrite ); + node->AddProperty( "outline binary shadow", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty( "outline binary shadow color", ColorProperty::New(0.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "outline shadow width", mitk::FloatProperty::New( 1.5 ), renderer, overwrite ); + if(image->IsRotated()) node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New(VTK_RESLICE_CUBIC) ); + else node->AddProperty( "reslice interpolation", mitk::VtkResliceInterpolationProperty::New() ); + node->AddProperty( "texture interpolation", mitk::BoolProperty::New( mitk::DataNodeFactory::m_TextureInterpolationActive ) ); // set to user configurable default value (see global options) + node->AddProperty( "in plane resample extent by geometry", mitk::BoolProperty::New( false ) ); + node->AddProperty( "bounding box", mitk::BoolProperty::New( false ) ); + + mitk::RenderingModeProperty::Pointer renderingModeProperty = mitk::RenderingModeProperty::New(); + node->AddProperty( "Image Rendering.Mode", renderingModeProperty); + + // Set default grayscale look-up table + mitk::LookupTable::Pointer mitkLut = mitk::LookupTable::New(); + mitkLut->SetType(mitk::LookupTable::GRAYSCALE); + mitk::LookupTableProperty::Pointer mitkLutProp = mitk::LookupTableProperty::New(); + mitkLutProp->SetLookupTable(mitkLut); + node->SetProperty("LookupTable", mitkLutProp); + + std::string photometricInterpretation; // DICOM tag telling us how pixel values should be displayed + if ( node->GetStringProperty( "dicom.pixel.PhotometricInterpretation", photometricInterpretation ) ) + { + // modality provided by DICOM or other reader + if ( photometricInterpretation.find("MONOCHROME1") != std::string::npos ) // meaning: display MINIMUM pixels as WHITE + { + // Set inverse grayscale look-up table + mitkLut->SetType(mitk::LookupTable::INVERSE_GRAYSCALE); + mitkLutProp->SetLookupTable(mitkLut); + node->SetProperty("LookupTable", mitkLutProp); + } + // Otherwise do nothing - the default grayscale look-up table has already been set + } + + bool isBinaryImage(false); + if ( ! node->GetBoolProperty("binary", isBinaryImage) ) + { + + // ok, property is not set, use heuristic to determine if this + // is a binary image + mitk::Image::Pointer centralSliceImage; + ScalarType minValue = 0.0; + ScalarType maxValue = 0.0; + ScalarType min2ndValue = 0.0; + ScalarType max2ndValue = 0.0; + mitk::ImageSliceSelector::Pointer sliceSelector = mitk::ImageSliceSelector::New(); + + sliceSelector->SetInput(image); + sliceSelector->SetSliceNr(image->GetDimension(2)/2); + sliceSelector->SetTimeNr(image->GetDimension(3)/2); + sliceSelector->SetChannelNr(image->GetDimension(4)/2); + sliceSelector->Update(); + centralSliceImage = sliceSelector->GetOutput(); + if ( centralSliceImage.IsNotNull() && centralSliceImage->IsInitialized() ) + { + minValue = centralSliceImage->GetStatistics()->GetScalarValueMin(); + maxValue = centralSliceImage->GetStatistics()->GetScalarValueMax(); + min2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMin(); + max2ndValue = centralSliceImage->GetStatistics()->GetScalarValue2ndMax(); + } + if ((maxValue == min2ndValue && minValue == max2ndValue) || minValue == maxValue) + { + // centralSlice is strange, lets look at all data + minValue = image->GetStatistics()->GetScalarValueMin(); + maxValue = image->GetStatistics()->GetScalarValueMaxNoRecompute(); + min2ndValue = image->GetStatistics()->GetScalarValue2ndMinNoRecompute(); + max2ndValue = image->GetStatistics()->GetScalarValue2ndMaxNoRecompute(); + } + isBinaryImage = ( maxValue == min2ndValue && minValue == max2ndValue ); + } + + // some more properties specific for a binary... + if (isBinaryImage) + { + node->AddProperty( "opacity", mitk::FloatProperty::New(0.3f), renderer, overwrite ); + node->AddProperty( "color", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "binaryimage.selectedcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "binaryimage.selectedannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "binaryimage.hoveringcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "binaryimage.hoveringannotationcolor", ColorProperty::New(1.0,0.0,0.0), renderer, overwrite ); + node->AddProperty( "binary", mitk::BoolProperty::New( true ), renderer, overwrite ); + node->AddProperty("layer", mitk::IntProperty::New(10), renderer, overwrite); + } + else //...or image type object + { + node->AddProperty( "opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite ); + node->AddProperty( "color", ColorProperty::New(1.0,1.0,1.0), renderer, overwrite ); + node->AddProperty( "binary", mitk::BoolProperty::New( false ), renderer, overwrite ); + node->AddProperty("layer", mitk::IntProperty::New(0), renderer, overwrite); + + std::string className = image->GetNameOfClass(); + + if (className != "TensorImage" && className != "QBallImage") + { + PixelType pixelType = image->GetPixelType(); + size_t numComponents = pixelType.GetNumberOfComponents(); + + if ((pixelType.GetPixelTypeAsString() == "vector" && numComponents > 1) || numComponents == 2 || numComponents > 4) + node->AddProperty("Image.Displayed Component", mitk::IntProperty::New(0), renderer, overwrite); + } + } + + if(image.IsNotNull() && image->IsInitialized()) + { + if((overwrite) || (node->GetProperty("levelwindow", renderer)==NULL)) + { + /* initialize level/window from DICOM tags */ + std::string sLevel; + std::string sWindow; + if ( image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowCenter", sLevel ) + && image->GetPropertyList()->GetStringProperty( "dicom.voilut.WindowWidth", sWindow ) ) + { + float level = atof( sLevel.c_str() ); + float window = atof( sWindow.c_str() ); + + mitk::LevelWindow contrast; + std::string sSmallestPixelValueInSeries; + std::string sLargestPixelValueInSeries; + + if ( image->GetPropertyList()->GetStringProperty( "dicom.series.SmallestPixelValueInSeries", sSmallestPixelValueInSeries ) + && image->GetPropertyList()->GetStringProperty( "dicom.series.LargestPixelValueInSeries", sLargestPixelValueInSeries ) ) + { + float smallestPixelValueInSeries = atof( sSmallestPixelValueInSeries.c_str() ); + float largestPixelValueInSeries = atof( sLargestPixelValueInSeries.c_str() ); + contrast.SetRangeMinMax( smallestPixelValueInSeries-1, largestPixelValueInSeries+1 ); // why not a little buffer? + // might remedy some l/w widget challenges + } + else + { + contrast.SetAuto( static_cast(node->GetData()), false, true ); // we need this as a fallback + } + + contrast.SetLevelWindow( level, window, true ); + node->SetProperty( "levelwindow", LevelWindowProperty::New( contrast ), renderer ); + } + } + if(((overwrite) || (node->GetProperty("opaclevelwindow", renderer)==NULL)) + && (image->GetPixelType().GetPixelType() == itk::ImageIOBase::RGBA) + && (image->GetPixelType().GetComponentType() == itk::ImageIOBase::UCHAR) ) + { + mitk::LevelWindow opaclevwin; + opaclevwin.SetRangeMinMax(0,255); + opaclevwin.SetWindowBounds(0,255); + mitk::LevelWindowProperty::Pointer prop = mitk::LevelWindowProperty::New(opaclevwin); + node->SetProperty( "opaclevelwindow", prop, renderer ); + } + } + Superclass::SetDefaultProperties(node, renderer, overwrite); +} + +mitk::DoseImageVtkMapper2D::LocalStorage* mitk::DoseImageVtkMapper2D::GetLocalStorage(mitk::BaseRenderer* renderer) +{ + return m_LSH.GetLocalStorage(renderer); +} + + +vtkSmartPointer mitk::DoseImageVtkMapper2D::CreateOutlinePolyData(mitk::BaseRenderer* renderer ) +{ + vtkSmartPointer points = vtkSmartPointer::New(); //the points to draw + vtkSmartPointer lines = vtkSmartPointer::New(); //the lines to connect the points + vtkSmartPointer colors = vtkSmartPointer::New(); + colors->SetNumberOfComponents(3); + colors->SetName("Colors"); + + float pref; + this->GetDataNode()->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),pref); + + mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = dynamic_cast(GetDataNode()->GetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str())); + mitk::IsoDoseLevelSet::Pointer isoDoseLevelSet = propIsoSet->GetValue(); + + for(mitk::IsoDoseLevelSet::ConstIterator doseIT = isoDoseLevelSet->Begin(); doseIT!=isoDoseLevelSet->End();++doseIT) + { + if(doseIT->GetVisibleIsoLine()) + { + this->CreateLevelOutline(renderer, &(doseIT.Value()), pref, points, lines, colors); + }//end of if visible dose value + }//end of loop over all does values + + mitk::IsoDoseLevelVectorProperty::Pointer propfreeIsoVec = dynamic_cast(GetDataNode()->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); + mitk::IsoDoseLevelVector::Pointer frereIsoDoseLevelVec = propfreeIsoVec->GetValue(); + + for(mitk::IsoDoseLevelVector::ConstIterator freeDoseIT = frereIsoDoseLevelVec->Begin(); freeDoseIT!=frereIsoDoseLevelVec->End();++freeDoseIT) + { + if(freeDoseIT->Value()->GetVisibleIsoLine()) + { + this->CreateLevelOutline(renderer, freeDoseIT->Value(), pref, points, lines, colors); + }//end of if visible dose value + }//end of loop over all does values + + // Create a polydata to store everything in + vtkSmartPointer polyData = vtkSmartPointer::New(); + // Add the points to the dataset + polyData->SetPoints(points); + // Add the lines to the dataset + polyData->SetLines(lines); + polyData->GetCellData()->SetScalars(colors); + return polyData; +} + +void mitk::DoseImageVtkMapper2D::CreateLevelOutline(mitk::BaseRenderer* renderer, const mitk::IsoDoseLevel* level, float pref, vtkSmartPointer points, vtkSmartPointer lines, vtkSmartPointer colors) +{ + LocalStorage* localStorage = this->GetLocalStorage(renderer); + + //get the min and max index values of each direction + int* extent = localStorage->m_ReslicedImage->GetExtent(); + int xMin = extent[0]; + int xMax = extent[1]; + int yMin = extent[2]; + int yMax = extent[3]; + + int* dims = localStorage->m_ReslicedImage->GetDimensions(); //dimensions of the image + int line = dims[0]; //how many pixels per line? + //get the depth for each contour + float depth = CalculateLayerDepth(renderer); + + double doseValue = level->GetDoseValue()*pref; + mitk::IsoDoseLevel::ColorType isoColor = level->GetColor(); + unsigned char colorLine[3] = {static_cast(isoColor.GetRed()*255), + static_cast(isoColor.GetGreen()*255), + static_cast(isoColor.GetBlue()*255)}; + + int x = xMin; //pixel index x + int y = yMin; //pixel index y + float* currentPixel; + + // We take the pointer to the first pixel of the image + currentPixel = static_cast(localStorage->m_ReslicedImage->GetScalarPointer() ); + + while (y <= yMax) + { + //if the current pixel value is set to something + if ((currentPixel) && (*currentPixel >= doseValue)) + { + //check in which direction a line is necessary + //a line is added if the neighbor of the current pixel has the value 0 + //and if the pixel is located at the edge of the image + + //if vvvvv not the first line vvvvv + if (y > yMin && *(currentPixel-line) < doseValue) + { //x direction - bottom edge of the pixel + //add the 2 points + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + //add the line between both points + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv not the last line vvvvv + if (y < yMax && *(currentPixel+line) < doseValue) + { //x direction - top edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv not the first pixel vvvvv + if ( (x > xMin || y > yMin) && *(currentPixel-1) < doseValue) + { //y direction - left edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv not the last pixel vvvvv + if ( (y < yMax || (x < xMax) ) && *(currentPixel+1) < doseValue) + { //y direction - right edge of the pixel + vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + /* now consider pixels at the edge of the image */ + + //if vvvvv left edge of image vvvvv + if (x == xMin) + { //draw left edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv right edge of image vvvvv + if (x == xMax) + { //draw right edge of the pixel + vtkIdType p1 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv bottom edge of image vvvvv + if (y == yMin) + { //draw bottom edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], y*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + + //if vvvvv top edge of image vvvvv + if (y == yMax) + { //draw top edge of the pixel + vtkIdType p1 = points->InsertNextPoint(x*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + vtkIdType p2 = points->InsertNextPoint((x+1)*localStorage->m_mmPerPixel[0], (y+1)*localStorage->m_mmPerPixel[1], depth); + lines->InsertNextCell(2); + lines->InsertCellPoint(p1); + lines->InsertCellPoint(p2); + colors->InsertNextTupleValue(colorLine); + } + }//end if currentpixel is set + + x++; + + if (x > xMax) + { //reached end of line + x = xMin; + y++; + } + + // Increase the pointer-position to the next pixel. + // This is safe, as the while-loop and the x-reset logic above makes + // sure we do not exceed the bounds of the image + currentPixel++; + }//end of while +} + +void mitk::DoseImageVtkMapper2D::TransformActor(mitk::BaseRenderer* renderer) +{ + LocalStorage *localStorage = m_LSH.GetLocalStorage(renderer); + //get the transformation matrix of the reslicer in order to render the slice as axial, coronal or saggital + vtkSmartPointer trans = vtkSmartPointer::New(); + vtkSmartPointer matrix = localStorage->m_Reslicer->GetResliceAxes(); + trans->SetMatrix(matrix); + //transform the plane/contour (the actual actor) to the corresponding view (axial, coronal or saggital) + localStorage->m_Actor->SetUserTransform(trans); + //transform the origin to center based coordinates, because MITK is center based. + localStorage->m_Actor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); + + if ( localStorage->m_Actors->GetNumberOfPaths() > 1 ) + { + vtkActor* secondaryActor = dynamic_cast( localStorage->m_Actors->GetParts()->GetItemAsObject(0) ); + secondaryActor->SetUserTransform(trans); + secondaryActor->SetPosition( -0.5*localStorage->m_mmPerPixel[0], -0.5*localStorage->m_mmPerPixel[1], 0.0); + } +} + +bool mitk::DoseImageVtkMapper2D::RenderingGeometryIntersectsImage( const PlaneGeometry* renderingGeometry, SlicedGeometry3D* imageGeometry ) +{ + // if either one of the two geometries is NULL we return true + // for safety reasons + if ( renderingGeometry == NULL || imageGeometry == NULL ) + return true; + + // get the distance for the first cornerpoint + ScalarType initialDistance = renderingGeometry->SignedDistance( imageGeometry->GetCornerPoint( 0 ) ); + for( int i=1; i<8; i++ ) + { + mitk::Point3D cornerPoint = imageGeometry->GetCornerPoint( i ); + + // get the distance to the other cornerpoints + ScalarType distance = renderingGeometry->SignedDistance( cornerPoint ); + + // if it has not the same signing as the distance of the first point + if ( initialDistance * distance < 0 ) + { + // we have an intersection and return true + return true; + } + } + + // all distances have the same sign, no intersection and we return false + return false; +} + +mitk::DoseImageVtkMapper2D::LocalStorage::~LocalStorage() +{ +} + +mitk::DoseImageVtkMapper2D::LocalStorage::LocalStorage() +: m_VectorComponentExtractor(vtkSmartPointer::New()) +{ + + m_LevelWindowFilter = vtkSmartPointer::New(); + + //Do as much actions as possible in here to avoid double executions. + m_Plane = vtkSmartPointer::New(); + m_Texture = vtkSmartPointer::New().GetPointer(); + m_DefaultLookupTable = vtkSmartPointer::New(); + m_BinaryLookupTable = vtkSmartPointer::New(); + m_ColorLookupTable = vtkSmartPointer::New(); + m_Mapper = vtkSmartPointer::New(); + m_Actor = vtkSmartPointer::New(); + m_Actors = vtkSmartPointer::New(); + m_Reslicer = mitk::ExtractSliceFilter::New(); + m_TSFilter = vtkSmartPointer::New(); + m_OutlinePolyData = vtkSmartPointer::New(); + m_ReslicedImage = vtkSmartPointer::New(); + m_EmptyPolyData = vtkSmartPointer::New(); + + //the following actions are always the same and thus can be performed + //in the constructor for each image (i.e. the image-corresponding local storage) + m_TSFilter->ReleaseDataFlagOn(); + + mitk::LookupTable::Pointer mitkLUT = mitk::LookupTable::New(); + //built a default lookuptable + mitkLUT->SetType(mitk::LookupTable::GRAYSCALE); + m_DefaultLookupTable = mitkLUT->GetVtkLookupTable(); + + mitkLUT->SetType(mitk::LookupTable::LEGACY_BINARY); + m_BinaryLookupTable = mitkLUT->GetVtkLookupTable(); + + mitkLUT->SetType(mitk::LookupTable::LEGACY_RAINBOW_COLOR); + m_ColorLookupTable = mitkLUT->GetVtkLookupTable(); + + //do not repeat the texture (the image) + m_Texture->RepeatOff(); + + //set the mapper for the actor + m_Actor->SetMapper( m_Mapper ); + + vtkSmartPointer outlineShadowActor = vtkSmartPointer::New(); + outlineShadowActor->SetMapper( m_Mapper ); + + m_Actors->AddPart( outlineShadowActor ); + m_Actors->AddPart( m_Actor ); +} diff --git a/Modules/DicomRT/src/mitkRTConstants.cpp b/Modules/DicomRT/src/mitkRTConstants.cpp index 1dfd7b57d0..cfa34e44fd 100644 --- a/Modules/DicomRT/src/mitkRTConstants.cpp +++ b/Modules/DicomRT/src/mitkRTConstants.cpp @@ -1,28 +1,28 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRTConstants.h" -const std::string mitk::Constants::DOSE_PROPERTY_NAME = "dose"; -const std::string mitk::Constants::PRESCRIBED_DOSE_PROPERTY_NAME = "dose.PrescribedDose"; -const std::string mitk::Constants::REFERENCE_DOSE_PROPERTY_NAME = "dose.ReferenceDose"; -const std::string mitk::Constants::DOSE_TYPE_PROPERTY_NAME = "dose.type"; -const std::string mitk::Constants::DOSE_SUMMATION_TYPE_PROPERTY_NAME = "dose.summationType"; -const std::string mitk::Constants::DOSE_FRACTION_COUNT_PROPERTY_NAME = "dose.fractionCount"; -const std::string mitk::Constants::DOSE_SHOW_ISOLINES_PROPERTY_NAME = "dose.showIsoLines"; -const std::string mitk::Constants::DOSE_SHOW_COLORWASH_PROPERTY_NAME = "dose.showColorWash"; -const std::string mitk::Constants::DOSE_ISO_LEVELS_PROPERTY_NAME = "dose.isoLevels"; -const std::string mitk::Constants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME = "dose.freeIsoValues"; +const std::string mitk::RTConstants::DOSE_PROPERTY_NAME = "dose"; +const std::string mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME = "dose.PrescribedDose"; +const std::string mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME = "dose.ReferenceDose"; +const std::string mitk::RTConstants::DOSE_TYPE_PROPERTY_NAME = "dose.type"; +const std::string mitk::RTConstants::DOSE_SUMMATION_TYPE_PROPERTY_NAME = "dose.summationType"; +const std::string mitk::RTConstants::DOSE_FRACTION_COUNT_PROPERTY_NAME = "dose.fractionCount"; +const std::string mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME = "dose.showIsoLines"; +const std::string mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME = "dose.showColorWash"; +const std::string mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME = "dose.isoLevels"; +const std::string mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME = "dose.freeIsoValues"; diff --git a/Modules/DicomRT/src/mitkRTDoseReader.cpp b/Modules/DicomRT/src/mitkRTDoseReader.cpp index aacfc367d3..10aaa9d86b 100644 --- a/Modules/DicomRT/src/mitkRTDoseReader.cpp +++ b/Modules/DicomRT/src/mitkRTDoseReader.cpp @@ -1,144 +1,157 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRTDoseReader.h" #include #include #include +#include #include #include +#include +#include #include namespace mitk { RTDoseReader::RTDoseReader(){} RTDoseReader::~RTDoseReader(){} mitk::DataNode::Pointer RTDoseReader:: LoadRTDose(const char* filename) { DcmFileFormat fileformat; OFCondition outp = fileformat.loadFile(filename, EXS_Unknown); if(outp.bad()) { MITK_ERROR << "Cant read the file" << std::endl; } DcmDataset *dataset = fileformat.getDataset(); std::string name = filename; itk::FilenamesContainer file; file.push_back(name); mitk::DicomSeriesReader* reader = new mitk::DicomSeriesReader; mitk::DataNode::Pointer originalNode = reader->LoadDicomSeries(file,false); if(originalNode.IsNull()) { MITK_ERROR << "Error reading the dcm file" << std::endl; return 0; } mitk::Image::Pointer originalImage = dynamic_cast(originalNode->GetData()); DRTDoseIOD doseObject; OFCondition result = doseObject.read(*dataset); if(result.bad()) { MITK_ERROR << "Error reading the Dataset" << std::endl; return 0; } OFString gridScaling; Float32 gridscale; doseObject.getDoseGridScaling(gridScaling); gridscale = OFStandard::atof(gridScaling.c_str()); AccessByItk_1(originalImage, MultiplayGridScaling, gridscale); double prescripeDose = this->GetMaxDoseValue(dataset); originalNode->SetName("RT Dose"); - originalNode->SetFloatProperty(mitk::Constants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(),prescripeDose); - originalNode->SetFloatProperty(mitk::Constants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), 40); - originalNode->SetBoolProperty(mitk::Constants::DOSE_PROPERTY_NAME.c_str(),true); + originalNode->SetData(this->scaledDoseImage); + originalNode->SetFloatProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(),prescripeDose); + originalNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), 40); + originalNode->SetBoolProperty(mitk::RTConstants::DOSE_PROPERTY_NAME.c_str(),true); return originalNode; } template void RTDoseReader::MultiplayGridScaling(itk::Image* image, Float32 gridscale) { + typedef itk::Image OutputImageType; typedef itk::Image InputImageType; - itk::ImageRegionIterator it(image, - image->GetRequestedRegion()); - for(it=it.Begin(); !it.IsAtEnd(); ++it) - { - it.Set(it.Get()*gridscale); - } + + typedef itk::CastImageFilter CastFilterType; + typedef itk::ShiftScaleImageFilter ScaleFilterType; + typename CastFilterType::Pointer castFilter = CastFilterType::New(); + typename ScaleFilterType::Pointer scaleFilter = ScaleFilterType::New(); + + castFilter->SetInput(image); + scaleFilter->SetInput(castFilter->GetOutput()); + scaleFilter->SetScale(gridscale); + scaleFilter->Update(); + typename OutputImageType::Pointer scaledOutput = scaleFilter->GetOutput(); + this->scaledDoseImage = mitk::Image::New(); + + mitk::CastToMitkImage(scaledOutput, this->scaledDoseImage); } double RTDoseReader::GetMaxDoseValue(DcmDataset* dataSet) { DRTDoseIOD doseObject; OFCondition result = doseObject.read(*dataSet); if(result.bad()) { MITK_ERROR << "Error reading the RT Dose dataset" << std::endl; return 0; } Uint16 rows, columns, frames; OFString nrframes, gridScaling; const Uint16 *pixelData = NULL; Float32 gridscale; Uint16 &rows_ref = rows; Uint16 &columns_ref = columns; doseObject.getRows(rows_ref); doseObject.getColumns(columns_ref); doseObject.getNumberOfFrames(nrframes); doseObject.getDoseGridScaling(gridScaling); frames = atoi(nrframes.c_str()); gridscale = OFStandard::atof(gridScaling.c_str()); dataSet->findAndGetUint16Array(DCM_PixelData, pixelData, 0); int size = columns*rows*frames; double highest = 0; for(int i=0; ihighest) { highest = pixelData[i] * gridscale; } } return highest; } } diff --git a/Modules/DicomRT/src/mitkRTStructureSetReader.cpp b/Modules/DicomRT/src/mitkRTStructureSetReader.cpp index cda808bfc9..020afe6985 100644 --- a/Modules/DicomRT/src/mitkRTStructureSetReader.cpp +++ b/Modules/DicomRT/src/mitkRTStructureSetReader.cpp @@ -1,248 +1,239 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRTStructureSetReader.h" #include #include namespace mitk { RTStructureSetReader::RTStructureSetReader(){} RTStructureSetReader::~RTStructureSetReader(){} RTStructureSetReader::RoiEntry::RoiEntry() { Number = 0; DisplayColor[0]=1.0; DisplayColor[1]=0.0; DisplayColor[2]=0.0; ContourModelSet=mitk::ContourModelSet::New(); } RTStructureSetReader::RoiEntry::RoiEntry(const RoiEntry &src) { Number=src.Number; Name=src.Name; Description=src.Description; DisplayColor[0]=src.DisplayColor[0]; DisplayColor[1]=src.DisplayColor[1]; DisplayColor[2]=src.DisplayColor[2]; ContourModelSet=mitk::ContourModelSet::New(); SetPolyData(src.ContourModelSet); } RTStructureSetReader::RoiEntry::~RoiEntry(){} RTStructureSetReader::RoiEntry& RTStructureSetReader:: RoiEntry::operator =(const RoiEntry &src) { Number=src.Number; Name=src.Name; Description=src.Description; DisplayColor[0]=src.DisplayColor[0]; DisplayColor[1]=src.DisplayColor[1]; DisplayColor[2]=src.DisplayColor[2]; SetPolyData(src.ContourModelSet); return (*this); } void RTStructureSetReader::RoiEntry:: SetPolyData(mitk::ContourModelSet::Pointer roiPolyData) { if (roiPolyData == this->ContourModelSet) return; this->ContourModelSet = roiPolyData; } size_t RTStructureSetReader::GetNumberOfROIs() { return this->ROISequenceVector.size(); } RTStructureSetReader::RoiEntry* RTStructureSetReader:: FindRoiByNumber(unsigned int roiNum) { for(unsigned int i=0; iROISequenceVector.size(); ++i) { if(this->ROISequenceVector[i].Number == roiNum) return &this->ROISequenceVector[i]; } return NULL; } RTStructureSetReader::ContourModelSetNodes RTStructureSetReader:: ReadStructureSet(const char* filepath) { DcmFileFormat file; OFCondition output = file.loadFile(filepath, EXS_Unknown); if(output.bad()) { MITK_ERROR << "Cant read the file" << std::endl; } DcmDataset *dataset = file.getDataset(); DRTStructureSetIOD structureSetObject; OFCondition outp = structureSetObject.read(*dataset); if(!outp.good()) { MITK_ERROR << "Error reading the file" << std::endl; RTStructureSetReader::ContourModelSetNodes x; return x; } DRTStructureSetROISequence &roiSequence = structureSetObject.getStructureSetROISequence(); if(!roiSequence.gotoFirstItem().good()) { MITK_ERROR << "Error reading the structure sequence" << std::endl; RTStructureSetReader::ContourModelSetNodes x; return x; } do{ DRTStructureSetROISequence::Item ¤tSequence = roiSequence.getCurrentItem(); if(!currentSequence.isValid()) { continue; } OFString roiName; OFString roiDescription; Sint32 roiNumber; RoiEntry roi; currentSequence.getROIName(roiName); currentSequence.getROIDescription(roiDescription); currentSequence.getROINumber(roiNumber); roi.Name = roiName.c_str(); roi.Description = roiDescription.c_str(); roi.Number = roiNumber; this->ROISequenceVector.push_back(roi); } while(roiSequence.gotoNextItem().good()); Sint32 refRoiNumber; DRTROIContourSequence &roiContourSeqObject = structureSetObject.getROIContourSequence(); if(!roiContourSeqObject.gotoFirstItem().good()) { MITK_ERROR << "Error reading the contour sequence" << std::endl; RTStructureSetReader::ContourModelSetNodes x; return x; } do { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); DRTROIContourSequence::Item ¤tRoiObject = roiContourSeqObject.getCurrentItem(); if(!currentRoiObject.isValid()) { continue; } currentRoiObject.getReferencedROINumber(refRoiNumber); DRTContourSequence &contourSeqObject = currentRoiObject.getContourSequence(); if(contourSeqObject.gotoFirstItem().good()) { do { DRTContourSequence::Item &contourItem = contourSeqObject.getCurrentItem(); if(!contourItem.isValid()) { continue; } OFString contourNumber; OFString numberOfPoints; OFVector contourData_LPS; mitk::ContourModel::Pointer contourSequence = mitk::ContourModel::New(); contourItem.getContourNumber(contourNumber); contourItem.getNumberOfContourPoints(numberOfPoints); contourItem.getContourData(contourData_LPS); for(unsigned int i=0; iAddVertex(point); } contourSequence->Close(); contourSet->AddContourModel(contourSequence); } while(contourSeqObject.gotoNextItem().good()); } else { MITK_ERROR << "Error reading contourSeqObject" << std::endl; } RoiEntry* refROI = this->FindRoiByNumber(refRoiNumber); if(refROI==NULL) { MITK_ERROR << "Can not find references ROI" << std::endl; continue; } Sint32 roiColor; for(int j=0;j<3;j++) { currentRoiObject.getROIDisplayColor(roiColor, j); refROI->DisplayColor[j] = roiColor/255.0; } refROI->ContourModelSet = contourSet; contourSet->SetProperty("name", mitk::StringProperty::New(refROI->Name)); contourSet->SetProperty("contour.color", mitk::ColorProperty::New( refROI->DisplayColor[0], refROI->DisplayColor[1], refROI->DisplayColor[2])); - } while(roiContourSeqObject.gotoNextItem().good()); std::deque nodes; for(unsigned int i=0; iSetData(ROISequenceVector.at(i).ContourModelSet); - node->SetProperty("name", - ROISequenceVector.at(i).ContourModelSet->GetProperty("name")); - node->SetProperty("color", - ROISequenceVector.at(i).ContourModelSet->GetProperty("contour.color")); - node->SetProperty("contour.color", - ROISequenceVector.at(i).ContourModelSet->GetProperty("contour.color")); - - /*The StructureSets should only be visible in the axial-view and the - 3D-view because in the other views they are just points and lines*/ - node->SetVisibility(true, mitk::BaseRenderer::GetInstance - ( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); - node->SetVisibility(false, mitk::BaseRenderer::GetInstance - ( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); - node->SetVisibility(false, mitk::BaseRenderer::GetInstance - ( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); - node->SetVisibility(true, mitk::BaseRenderer::GetInstance - ( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + node->SetProperty("name", ROISequenceVector.at(i).ContourModelSet->GetProperty("name")); + node->SetProperty("color",ROISequenceVector.at(i).ContourModelSet->GetProperty("contour.color")); + node->SetProperty("contour.color",ROISequenceVector.at(i).ContourModelSet->GetProperty("contour.color")); + node->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); + node->SetVisibility(true, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); + node->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget2"))); + node->SetVisibility(false, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget3"))); + node->SetVisibility(true, mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget4"))); + nodes.push_back(node); } return nodes; } } diff --git a/Modules/DicomRT/test/mitkRTStructureSetReaderTest.cpp b/Modules/DicomRT/test/mitkRTStructureSetReaderTest.cpp index 548d6d6845..0b6f39c90b 100644 --- a/Modules/DicomRT/test/mitkRTStructureSetReaderTest.cpp +++ b/Modules/DicomRT/test/mitkRTStructureSetReaderTest.cpp @@ -1,158 +1,158 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include #include "mitkRTStructureSetReader.h" #include #include class mitkRTStructureSetReaderTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkRTStructureSetReaderTestSuite); // MITK_TEST(TestBody); MITK_TEST(TestStructureSets); CPPUNIT_TEST_SUITE_END(); private: mitk::RTStructureSetReader::Pointer m_rtStructureReader; public: void setUp() override { m_rtStructureReader = mitk::RTStructureSetReader::New(); CPPUNIT_ASSERT_MESSAGE("Failed to initialize RTStructureSetReader", m_rtStructureReader.IsNotNull()); } void TestStructureSets() { std::deque contourModelVectorCorrect; std::deque contourModelVectorCorrectSequ; std::deque contourModelVectorTest; std::deque contourModelVectorTestDel; LoadData(contourModelVectorCorrect); contourModelVectorTest = m_rtStructureReader->ReadStructureSet(GetTestDataFilePath("RT/StructureSet/RS.dcm").c_str()); //Deleting all empty contourmodelsets - empty contourmodelsets cant be //saved so we have reference for the comparison for(unsigned int i=0; i(contourModelVectorTest.at(i)->GetData())->GetSize()>0){ contourModelVectorTestDel.push_back(dynamic_cast(contourModelVectorTest.at(i)->GetData())); } } //Loop for ordering the loaded contourmodelsets(contourModelVectorCorrect) for(unsigned int i=0; iGetProperty("name"); for(unsigned int j=0; jGetProperty("name"); if(tmp->GetValueAsString().compare(name->GetValueAsString()) == 0) contourModelVectorCorrectSequ.push_back(contourModelVectorCorrect.at(j)); } } //Testing wheather the two deques are equal bool equal = true; for(unsigned int i=0;iGetSize()!=c2->GetSize()) { MITK_INFO << "Number of ContourModelSets different" << std::endl; return false; } else { for(int i=0;iGetSize();++i) { mitk::ContourModel::Pointer cm1 = c1->GetContourModelAt(i); mitk::ContourModel::Pointer cm2 = c2->GetContourModelAt(i); if(cm1->GetNumberOfVertices()!=cm2->GetNumberOfVertices()) { MITK_INFO << "Number of Vertices different" << std::endl; return false; } else { float ep = 0.001; for(int j=0;jGetNumberOfVertices();++j) { mitk::Point3D p1 = cm1->GetVertexAt(i)->Coordinates; mitk::Point3D p2 = cm2->GetVertexAt(i)->Coordinates; - if(abs(p1[0]-p2[0]) > ep || abs(p1[0]-p2[0]) > ep || abs(p1[0]-p2[0]) > ep) + if(fabs(p1[0]-p2[0]) > ep || fabs(p1[0]-p2[0]) > ep || fabs(p1[0]-p2[0]) > ep) { return false; } } } } } return true; } void LoadData(std::deque &r) { std::vector > readerOutput; readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/BODY.cnt_set")); mitk::ContourModelSet::Pointer cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("BODY")); r.push_back(cnt_set); readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/Bladder.cnt_set")); cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("Bladder")); r.push_back(cnt_set); readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/Femoral Head Lt.cnt_set")); cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("Femoral Head Lt")); r.push_back(cnt_set); readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/Femoral Head RT.cnt_set")); cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("Femoral Head RT")); r.push_back(cnt_set); readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/PTV.cnt_set")); cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("PTV")); r.push_back(cnt_set); readerOutput = mitk::IOUtil::Load(GetTestDataFilePath("RT/StructureSet/Rectum.cnt_set")); cnt_set = dynamic_cast(readerOutput.at(0).GetPointer()); cnt_set->SetProperty("name", mitk::StringProperty::New("Rectum")); r.push_back(cnt_set); } }; MITK_TEST_SUITE_REGISTRATION(mitkRTStructureSetReader) diff --git a/Modules/DicomUI/src/QmitkDicomExternalDataWidget.cpp b/Modules/DicomUI/src/QmitkDicomExternalDataWidget.cpp index 6b7942d8b9..f4d5dae155 100644 --- a/Modules/DicomUI/src/QmitkDicomExternalDataWidget.cpp +++ b/Modules/DicomUI/src/QmitkDicomExternalDataWidget.cpp @@ -1,210 +1,215 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Qmitk #include "QmitkDicomExternalDataWidget.h" #include // CTK #include // Qt #include #include const std::string QmitkDicomExternalDataWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomExternalDataWidget"; QmitkDicomExternalDataWidget::QmitkDicomExternalDataWidget(QWidget *parent) : QWidget(parent) , m_Controls (nullptr) { Initialize(); CreateQtPartControl(this); } QmitkDicomExternalDataWidget::~QmitkDicomExternalDataWidget() { } void QmitkDicomExternalDataWidget::CreateQtPartControl( QWidget *parent ) { // build up qt Widget, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkDicomExternalDataWidgetControls; m_Controls->setupUi( parent ); m_Controls->viewExternalDataButton->setVisible(true); m_Controls->ctkDICOMBrowser->setTableOrientation(Qt::Vertical); m_Controls->ctkDICOMBrowser->setDICOMDatabase(m_ExternalDatabase); this->SetupImportDialog(); this->SetupProgressDialog(parent); //connect Buttons connect(m_Controls->downloadButton, SIGNAL(clicked()),this,SLOT(OnDownloadButtonClicked())); connect(m_Controls->viewExternalDataButton, SIGNAL(clicked()),this,SLOT(OnViewButtonClicked())); connect(m_Controls->directoryButton, SIGNAL(clicked()), this, SLOT(OnScanDirectory())); connect(m_Controls->ctkDICOMBrowser, SIGNAL(seriesSelectionChanged(const QStringList&)), this, SLOT(OnSeriesSelectionChanged(const QStringList&))); connect(m_Controls->ctkDICOMBrowser, SIGNAL(seriesDoubleClicked(const QModelIndex&)), this, SLOT(OnViewButtonClicked())); connect(m_ProgressDialog, SIGNAL(canceled()), m_ExternalIndexer, SLOT(cancel())); connect(m_ExternalIndexer, SIGNAL(indexingComplete()),this, SLOT(OnFinishedImport())); connect(m_ExternalIndexer, SIGNAL(indexingFilePath(const QString&)), m_ProgressDialogLabel, SLOT(setText(const QString&))); connect(m_ExternalIndexer, SIGNAL(progress(int)), m_ProgressDialog, SLOT(setValue(int))); } } void QmitkDicomExternalDataWidget::Initialize() { m_ExternalDatabase = new ctkDICOMDatabase(this); try{ m_ExternalDatabase->openDatabase(QString(":memory:"),QString( "EXTERNAL-DB")); }catch(std::exception e){ MITK_ERROR <<"Database error: "<< m_ExternalDatabase->lastError().toStdString(); m_ExternalDatabase->closeDatabase(); return; } m_ExternalIndexer = new ctkDICOMIndexer(this); } void QmitkDicomExternalDataWidget::OnFinishedImport() { m_ProgressDialog->setValue(m_ProgressDialog->maximum()); } void QmitkDicomExternalDataWidget::OnDownloadButtonClicked() { QStringList filesToDownload = GetFileNamesFromIndex(); if (filesToDownload.size() == 0) { QMessageBox info; info.setText("You have to select an entry in the dicom browser for import."); info.exec(); return; } emit SignalStartDicomImport(GetFileNamesFromIndex()); } void QmitkDicomExternalDataWidget::OnViewButtonClicked() { QStringList uids = m_Controls->ctkDICOMBrowser->currentSeriesSelection(); QString uid; foreach (uid, uids) { QStringList filesForSeries = m_ExternalDatabase->filesForSeries(uid); QHash eventProperty; eventProperty.insert("FilesForSeries", filesForSeries); + if(!filesForSeries.isEmpty()) + { + QString modality = m_ExternalDatabase->fileValue(filesForSeries.at(0),"0008,0060"); + eventProperty.insert("Modality", modality); + } emit SignalDicomToDataManager(eventProperty); } } QStringList QmitkDicomExternalDataWidget::GetFileNamesFromIndex() { QStringList filePaths; QString uid; QStringList seriesUIDs = m_Controls->ctkDICOMBrowser->currentSeriesSelection(); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } if (!filePaths.empty()) return filePaths; QStringList studyUIDs = m_Controls->ctkDICOMBrowser->currentStudiesSelection(); foreach (uid, studyUIDs) { seriesUIDs = m_ExternalDatabase->seriesForStudy(uid); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } } if (!filePaths.empty()) return filePaths; QStringList patientsUIDs = m_Controls->ctkDICOMBrowser->currentPatientsSelection(); foreach (uid, patientsUIDs) { studyUIDs = m_ExternalDatabase->studiesForPatient(uid); foreach (uid, studyUIDs) { seriesUIDs = m_ExternalDatabase->seriesForStudy(uid); foreach (uid, seriesUIDs) { filePaths.append(m_ExternalDatabase->filesForSeries(uid)); } } } return filePaths; } void QmitkDicomExternalDataWidget::OnStartDicomImport(const QString& directory) { m_ImportDialog->close(); m_ProgressDialog->show(); m_LastImportDirectory = directory; m_ExternalIndexer->addDirectory(*m_ExternalDatabase,m_LastImportDirectory); } void QmitkDicomExternalDataWidget::OnSeriesSelectionChanged(const QStringList& s) { m_Controls->viewExternalDataButton->setEnabled( (s.size() != 0) ); } void QmitkDicomExternalDataWidget::SetupImportDialog() { //Initialize import widget m_ImportDialog = new ctkFileDialog(this); // Since copy on import is not working at the moment // this feature is diabled // QCheckBox* importCheckbox = new QCheckBox("Copy on import", m_ImportDialog); // m_ImportDialog->setBottomWidget(importCheckbox); m_ImportDialog->setFileMode(QFileDialog::Directory); m_ImportDialog->setLabelText(QFileDialog::Accept,"Import"); m_ImportDialog->setWindowTitle("Import DICOM files from directory ..."); m_ImportDialog->setWindowModality(Qt::ApplicationModal); connect(m_ImportDialog, SIGNAL(fileSelected(QString)),this,SLOT(OnStartDicomImport(QString))); } void QmitkDicomExternalDataWidget::SetupProgressDialog(QWidget* parent) { m_ProgressDialog = new QProgressDialog("DICOM Import", "Cancel", 0, 100, parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint); m_ProgressDialogLabel = new QLabel("Initialization...", m_ProgressDialog); m_ProgressDialog->setLabel(m_ProgressDialogLabel); m_ProgressDialog->setWindowModality(Qt::ApplicationModal); m_ProgressDialog->setMinimumDuration(0); } void QmitkDicomExternalDataWidget::OnScanDirectory() { m_ImportDialog->show(); } diff --git a/Modules/DicomUI/src/QmitkDicomLocalStorageWidget.cpp b/Modules/DicomUI/src/QmitkDicomLocalStorageWidget.cpp index 71eb51af13..46c4d339cb 100644 --- a/Modules/DicomUI/src/QmitkDicomLocalStorageWidget.cpp +++ b/Modules/DicomUI/src/QmitkDicomLocalStorageWidget.cpp @@ -1,249 +1,254 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Qmitk #include "QmitkDicomLocalStorageWidget.h" //#include // Qt #include #include #include #include const std::string QmitkDicomLocalStorageWidget::Widget_ID = "org.mitk.Widgets.QmitkDicomLocalStorageWidget"; QmitkDicomLocalStorageWidget::QmitkDicomLocalStorageWidget(QWidget *parent) : QWidget(parent) , m_Controls(nullptr) , m_LocalIndexer(new ctkDICOMIndexer(parent)) { CreateQtPartControl(this); } QmitkDicomLocalStorageWidget::~QmitkDicomLocalStorageWidget() { m_LocalDatabase->closeDatabase(); } void QmitkDicomLocalStorageWidget::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { m_Controls = new Ui::QmitkDicomLocalStorageWidgetControls; m_Controls->setupUi( parent ); this->SetupProgressDialog(this); connect(m_Controls->deleteButton,SIGNAL(clicked()),this,SLOT(OnDeleteButtonClicked())); connect(m_Controls->viewInternalDataButton, SIGNAL(clicked()), this , SLOT(OnViewButtonClicked())); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList&)), this, SLOT(OnSeriesSelectionChanged(const QStringList&))); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesSelectionChanged(const QStringList&)), this, SLOT(OnSeriesSelectionChanged(const QStringList&))); connect(m_Controls->ctkDicomBrowser, SIGNAL(seriesDoubleClicked(const QModelIndex&)), this, SLOT(OnViewButtonClicked())); connect(m_LocalIndexer, SIGNAL(indexingComplete()),this, SLOT(OnFinishedImport())); connect(m_LocalIndexer, SIGNAL(indexingComplete()),this, SIGNAL(SignalFinishedImport())); connect(m_LocalIndexer, SIGNAL(indexingComplete()),this, SLOT(OnFinishedImport())); connect(m_LocalIndexer, SIGNAL(indexingFilePath(const QString&)), m_ProgressDialogLabel, SLOT(setText(const QString&))); connect(m_LocalIndexer, SIGNAL(progress(int)), m_ProgressDialog, SLOT(setValue(int))); connect(m_ProgressDialog, SIGNAL(canceled()), m_LocalIndexer, SLOT(cancel())); m_Controls->ctkDicomBrowser->setTableOrientation(Qt::Vertical); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QString& dicomData) { if(m_LocalDatabase->isOpen()) { m_LocalIndexer->addDirectory(*m_LocalDatabase,dicomData,m_LocalDatabase->databaseDirectory()); } } void QmitkDicomLocalStorageWidget::OnStartDicomImport(const QStringList& dicomData) { if(m_LocalDatabase->isOpen()) { m_ProgressDialog->show(); m_LocalIndexer->addListOfFiles(*m_LocalDatabase,dicomData,m_LocalDatabase->databaseDirectory()); } } void QmitkDicomLocalStorageWidget::OnFinishedImport() { m_ProgressDialog->setValue(m_ProgressDialog->maximum()); } void QmitkDicomLocalStorageWidget::OnDeleteButtonClicked() { if (!this->DeletePatients()) { if (!this->DeleteStudies()) { this->DeleteSeries(); } } m_Controls->ctkDicomBrowser->updateTableViews(); } bool QmitkDicomLocalStorageWidget::DeletePatients() { auto selectedPatientUIDs = m_Controls->ctkDicomBrowser->currentPatientsSelection(); if (!selectedPatientUIDs.empty()) { QStringList studyUIDs; for (const auto& patientUID : selectedPatientUIDs) studyUIDs.append(m_LocalDatabase->studiesForPatient(patientUID)); QStringList seriesUIDs; for (const auto& studyUID : studyUIDs) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question( nullptr, "Delete Patients", QString("Do you really want to delete %1 %2, containing %3 series in %4 %5?") .arg(selectedPatientUIDs.count()) .arg(selectedPatientUIDs.count() != 1 ? "patients" : "patient") .arg(seriesUIDs.count()) .arg(studyUIDs.count()) .arg(studyUIDs.count() != 1 ? "studies" : "study"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto& patientUID : selectedPatientUIDs) m_LocalDatabase->removePatient(patientUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteStudies() { auto selectedStudyUIDs = m_Controls->ctkDicomBrowser->currentStudiesSelection(); if (!selectedStudyUIDs.empty()) { QStringList seriesUIDs; for (const auto& studyUID : selectedStudyUIDs) seriesUIDs.append(m_LocalDatabase->seriesForStudy(studyUID)); auto answer = QMessageBox::question( nullptr, "Delete Studies", QString("Do you really want to delete %1 %2, containing %3 series?") .arg(selectedStudyUIDs.count()) .arg(selectedStudyUIDs.count() != 1 ? "studies" : "study") .arg(seriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto& studyUID : selectedStudyUIDs) m_LocalDatabase->removeStudy(studyUID); } return true; } return false; } bool QmitkDicomLocalStorageWidget::DeleteSeries() { auto selectedSeriesUIDs = m_Controls->ctkDicomBrowser->currentSeriesSelection(); if (!selectedSeriesUIDs.empty()) { auto answer = QMessageBox::question( nullptr, "Delete Series", QString("Do you really want to delete %1 series?") .arg(selectedSeriesUIDs.count()), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer == QMessageBox::Yes) { for (const auto& seriesUID : selectedSeriesUIDs) m_LocalDatabase->removeSeries(seriesUID); } return true; } return false; } void QmitkDicomLocalStorageWidget::OnViewButtonClicked() { QStringList uids = m_Controls->ctkDicomBrowser->currentSeriesSelection(); QString uid; foreach (uid, uids) { QStringList filesForSeries = m_LocalDatabase->filesForSeries(uid); QHash eventProperty; eventProperty.insert("FilesForSeries", filesForSeries); + if(!filesForSeries.isEmpty()) + { + QString modality = m_LocalDatabase->fileValue(filesForSeries.at(0),"0008,0060"); + eventProperty.insert("Modality", modality); + } emit SignalDicomToDataManager(eventProperty); } } void QmitkDicomLocalStorageWidget::SetDatabaseDirectory(QString newDatatbaseDirectory) { QDir databaseDirecory = QDir(newDatatbaseDirectory); if(!databaseDirecory.exists()) { databaseDirecory.mkpath(databaseDirecory.absolutePath()); } QString newDatatbaseFile = databaseDirecory.absolutePath() + QString("/ctkDICOM.sql"); this->SetDatabase(newDatatbaseFile); } void QmitkDicomLocalStorageWidget::SetDatabase(QString databaseFile) { m_LocalDatabase = new ctkDICOMDatabase(databaseFile); m_LocalDatabase->setParent(this); m_Controls->ctkDicomBrowser->setDICOMDatabase(m_LocalDatabase); } void QmitkDicomLocalStorageWidget::OnSeriesSelectionChanged(const QStringList &s) { m_Controls->viewInternalDataButton->setEnabled((s.size() != 0)); } void QmitkDicomLocalStorageWidget::SetupProgressDialog(QWidget* parent) { m_ProgressDialog = new QProgressDialog("DICOM Import", "Cancel", 0, 100, parent,Qt::WindowTitleHint | Qt::WindowSystemMenuHint); m_ProgressDialogLabel = new QLabel("Initialization...", m_ProgressDialog); m_ProgressDialog->setLabel(m_ProgressDialogLabel); m_ProgressDialog->setWindowModality(Qt::ApplicationModal); m_ProgressDialog->setMinimumDuration(0); } diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 2678553c13..c78163f473 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,72 +1,73 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(mitk_modules Core AppUtil DCMTesting RDF LegacyIO DataTypesExt Overlays LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMTesting Qt4Qt5TestModule SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction ImageStatistics LegacyAdaptors SceneSerialization GraphAlgorithms Multilabel ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation OpenViewCore QmlItems QtWidgets QtWidgetsExt SegmentationUI DiffusionImaging GPGPU OpenIGTLink IGTBase IGT CameraCalibration RigidRegistration RigidRegistrationUI DeformableRegistration DeformableRegistrationUI OpenCL OpenCVVideoSupport QtOverlays InputDevices ToFHardware ToFProcessing ToFUI US USUI DicomUI Simulation Remeshing Python Persistence OpenIGTLinkUI IGTUI VtkShaders DicomRT + RTUI IOExt XNAT TubeGraph BiophotonicsHardware ) if(MITK_ENABLE_PIC_READER) list(APPEND mitk_modules IpPicSupportIO) endif() diff --git a/Modules/RTUI/CMakeLists.txt b/Modules/RTUI/CMakeLists.txt new file mode 100644 index 0000000000..ceb9e443df --- /dev/null +++ b/Modules/RTUI/CMakeLists.txt @@ -0,0 +1,5 @@ +MITK_CREATE_MODULE( + INCLUDE_DIRS Qmitk Helper + DEPENDS MitkDicomRT MitkQtWidgets MitkQtWidgetsExt + PACKAGE_DEPENDS PUBLIC CTK Qt4 Qt5|Core +) diff --git a/Modules/RTUI/Helper/mitkIsoLevelsGenerator.cpp b/Modules/RTUI/Helper/mitkIsoLevelsGenerator.cpp new file mode 100644 index 0000000000..8496c1cb47 --- /dev/null +++ b/Modules/RTUI/Helper/mitkIsoLevelsGenerator.cpp @@ -0,0 +1,134 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "mitkIsoLevelsGenerator.h" + +mitk::IsoDoseLevelSet::Pointer mitk::GeneratIsoLevels_Virtuos() +{ + mitk::IsoDoseLevelSet::Pointer levelSet = mitk::IsoDoseLevelSet::New(); + + mitk::IsoDoseLevel::ColorType color; + color[0] = 0.0; + color[1] = 0.0; + color[2] = 0.4; + mitk::IsoDoseLevel::Pointer level = mitk::IsoDoseLevel::New(0.01,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.0; + color[1] = 0.2; + color[2] = 0.8; + level = mitk::IsoDoseLevel::New(0.1,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.0; + color[1] = 0.4; + color[2] = 1.0; + level = mitk::IsoDoseLevel::New(0.2,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.0; + color[1] = 0.7; + color[2] = 1.0; + level = mitk::IsoDoseLevel::New(0.3,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.0; + color[1] = 0.7; + color[2] = 0.6; + level = mitk::IsoDoseLevel::New(0.4,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.0; + color[1] = 1.0; + color[2] = 0.3; + level = mitk::IsoDoseLevel::New(0.5,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 1.0; + color[2] = 0.6; + level = mitk::IsoDoseLevel::New(0.6,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 1.0; + color[2] = 0.0; + level = mitk::IsoDoseLevel::New(0.7,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.8; + color[2] = 0.0; + level = mitk::IsoDoseLevel::New(0.8,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.5; + color[2] = 0.0; + level = mitk::IsoDoseLevel::New(0.9,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.4; + color[2] = 0.0; + level = mitk::IsoDoseLevel::New(0.95,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.2; + color[2] = 0.0; + level = mitk::IsoDoseLevel::New(1.0,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.0; + color[2] = 0.3; + level = mitk::IsoDoseLevel::New(1.07,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.0; + color[2] = 0.4; + level = mitk::IsoDoseLevel::New(1.1,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.4; + color[2] = 0.4; + level = mitk::IsoDoseLevel::New(1.2,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 1.0; + color[1] = 0.7; + color[2] = 0.7; + level = mitk::IsoDoseLevel::New(1.3,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.8; + color[1] = 0.6; + color[2] = 0.6; + level = mitk::IsoDoseLevel::New(1.4,color,true,true); + levelSet->SetIsoDoseLevel(level); + + color[0] = 0.65; + color[1] = 0.4; + color[2] = 0.4; + level = mitk::IsoDoseLevel::New(1.5,color,true,true); + levelSet->SetIsoDoseLevel(level); + + return levelSet; +} diff --git a/Modules/RTUI/Helper/mitkIsoLevelsGenerator.h b/Modules/RTUI/Helper/mitkIsoLevelsGenerator.h new file mode 100644 index 0000000000..10517dc7a7 --- /dev/null +++ b/Modules/RTUI/Helper/mitkIsoLevelsGenerator.h @@ -0,0 +1,30 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __ISO_LEVELS_GENERATOR_H +#define __ISO_LEVELS_GENERATOR_H + +#include "mitkIsoDoseLevelCollections.h" + +#include "MitkRTUIExports.h" + +namespace mitk +{ + IsoDoseLevelSet::Pointer MITKRTUI_EXPORT GeneratIsoLevels_Virtuos(); +} + +#endif diff --git a/Modules/RTUI/Helper/mitkRTUIConstants.cpp b/Modules/RTUI/Helper/mitkRTUIConstants.cpp new file mode 100644 index 0000000000..a927b4f7a7 --- /dev/null +++ b/Modules/RTUI/Helper/mitkRTUIConstants.cpp @@ -0,0 +1,46 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkRTUIConstants.h" + +const std::string mitk::RTUIConstants::ROOT_PREFERENCE_NODE_ID = "/RT/UI"; +const std::string mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_AS_DEFAULT_ID = "unkownDoseHandlingStyle"; +const std::string mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE_ID = "unkownDoseHandlingValue"; + + +const std::string mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID = "/RT/UI/doseVis"; +const std::string mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID = "/RT/UI/doseVis/isoPresets"; +const std::string mitk::RTUIConstants::REFERENCE_DOSE_ID = "referenceDose"; +const std::string mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID = "globalReferenceDoseSync"; +const std::string mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID = "doseDisplayAbsolute"; +const std::string mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID = "globalVisibilityIsoLines"; +const std::string mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID = "globalVisibilityColorWash"; +const std::string mitk::RTUIConstants::SELECTED_ISO_PRESET_ID = "selectedIsoPreset"; + +const std::string mitk::RTUIConstants::ISO_LEVEL_DOSE_VALUE_ID = "doseValue"; +const std::string mitk::RTUIConstants::ISO_LEVEL_COLOR_RED_ID = "color_R"; +const std::string mitk::RTUIConstants::ISO_LEVEL_COLOR_GREEN_ID = "color_G"; +const std::string mitk::RTUIConstants::ISO_LEVEL_COLOR_BLUE_ID = "color_B"; +const std::string mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_ISOLINES_ID = "visibleIsoLines"; +const std::string mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_COLORWASH_ID = "visibleColorWash"; + +const mitk::DoseValueAbs mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE = 40.0; + +const std::string mitk::RTCTKEventConstants::TOPIC_ISO_DOSE_LEVEL_PRESETS = "org/mitk/rt/dosevisualization/presets"; +const std::string mitk::RTCTKEventConstants::TOPIC_ISO_DOSE_LEVEL_PRESETS_CHANGED = "org/mitk/rt/dosevisualization/presets/CHANGED"; +const std::string mitk::RTCTKEventConstants::TOPIC_REFERENCE_DOSE = "org/mitk/rt/dosevisualization/referenceDose"; +const std::string mitk::RTCTKEventConstants::TOPIC_REFERENCE_DOSE_CHANGED = "org/mitk/rt/dosevisualization/referenceDose/CHANGED"; +const std::string mitk::RTCTKEventConstants::TOPIC_GLOBAL_VISIBILITY_CHANGED = "org/mitk/rt/dosevisualization/globalVis/CHANGED"; diff --git a/Modules/RTUI/Helper/mitkRTUIConstants.h b/Modules/RTUI/Helper/mitkRTUIConstants.h new file mode 100644 index 0000000000..87fed4df09 --- /dev/null +++ b/Modules/RTUI/Helper/mitkRTUIConstants.h @@ -0,0 +1,84 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef _MITK_RT_UI_CONSTANTS_H_ +#define _MITK_RT_UI_CONSTANTS_H_ + +#include +#include + +#include "MitkRTUIExports.h" + +namespace mitk +{ +struct MITKRTUI_EXPORT RTUIConstants +{ + /** ID/Path of main preference node for RT UI. */ + static const std::string ROOT_PREFERENCE_NODE_ID; + /** Bool that indicates how the prescribed dose should be defined, if unkown. True: UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE should be used as + default dose value in Gy; False: it should be used as fraction of the max dose to determin the prescribed dose.*/ + static const std::string UNKNOWN_PRESCRIBED_DOSE_HANDLING_AS_DEFAULT_ID; + /** Value that is used to determin unknown prescribed doses.*/ + static const std::string UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE_ID; + + /** ID/Path of main preference node where all iso dose level presets are stored (e.g. ROOT_ISO_PRESETS_PREFERENCE_NODE_ID+"/[Preset1]"). */ + static const std::string ROOT_ISO_PRESETS_PREFERENCE_NODE_ID; + /** ID/Path of main preference for dose visualization preferences. */ + static const std::string ROOT_DOSE_VIS_PREFERENCE_NODE_ID; + /** ID for the reference dose stored as preference. */ + static const std::string REFERENCE_DOSE_ID; + /** ID for the preference flag that indicates if the reference dose is synced for all nodes*/ + static const std::string GLOBAL_REFERENCE_DOSE_SYNC_ID; + /** ID for the flag if dose should be displayed as absoulte dose. */ + static const std::string DOSE_DISPLAY_ABSOLUTE_ID; + /** ID for the global visiblity switch for iso line visualization. */ + static const std::string GLOBAL_VISIBILITY_ISOLINES_ID; + /** ID for the global visiblity switch for color wash visualization. */ + static const std::string GLOBAL_VISIBILITY_COLORWASH_ID; + /** ID for the selected iso preset that should be used (value of ROOT_ISO_PRESETS_PREFERENCE_NODE_ID + value of this key can + be used to construct the passed to the selected preset. */ + static const std::string SELECTED_ISO_PRESET_ID; + + /** ID for the relative dose value of an iso dose level. */ + static const std::string ISO_LEVEL_DOSE_VALUE_ID; + /** ID for the color (red component) of an iso dose level. */ + static const std::string ISO_LEVEL_COLOR_RED_ID; + /** ID for the color (green component) of an iso dose level. */ + static const std::string ISO_LEVEL_COLOR_GREEN_ID; + /** ID for the color (blue component) of an iso dose level. */ + static const std::string ISO_LEVEL_COLOR_BLUE_ID; + /** ID for the visiblity switch for iso line visualization. */ + static const std::string ISO_LEVEL_VISIBILITY_ISOLINES_ID; + /** ID for the visiblity switch for color wash visualization. */ + static const std::string ISO_LEVEL_VISIBILITY_COLORWASH_ID; + + /** Default value used as reference_dose_if not defined by application or data node*/ + static const DoseValueAbs DEFAULT_REFERENCE_DOSE_VALUE; +}; + +struct MITKRTUI_EXPORT RTCTKEventConstants +{ + /** ID/Path of main preference node for RT UI. */ + static const std::string TOPIC_REFERENCE_DOSE; + static const std::string TOPIC_REFERENCE_DOSE_CHANGED; + static const std::string TOPIC_ISO_DOSE_LEVEL_PRESETS; + static const std::string TOPIC_ISO_DOSE_LEVEL_PRESETS_CHANGED; + static const std::string TOPIC_GLOBAL_VISIBILITY_CHANGED; +}; + +} + +#endif diff --git a/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.cpp b/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.cpp new file mode 100644 index 0000000000..548b5cde00 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.cpp @@ -0,0 +1,83 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkDoseColorDelegate.h" + +#include +#include +#include +#include +#include +#include + +QmitkDoseColorDelegate::QmitkDoseColorDelegate(QObject * /*parent*/) +{ +} + +void QmitkDoseColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QVariant data = index.data(Qt::EditRole); + + if (data.canConvert()) + { + QColor color = data.value(); + + painter->fillRect(option.rect, color); + } + else + { + QStyledItemDelegate::paint(painter, option, index); + } +} + +bool QmitkDoseColorDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index) +{ + Q_ASSERT(event); + Q_ASSERT(model); + + // make sure that the item is checkable + Qt::ItemFlags flags = model->flags(index); + if (!(flags & Qt::ItemIsEditable) || !(flags & Qt::ItemIsEnabled)) + { + return false; + } + + // make sure that we have the right event type + QMouseEvent* mouseEvent = dynamic_cast(event); + if (!mouseEvent) + { + return false; + } + else + { + if (mouseEvent->type() != QEvent::MouseButtonRelease || mouseEvent->button() != Qt::LeftButton) + { + return false; + } + } + + QColor oldcolor = index.data(Qt::EditRole).value(); + QColor newColor = QColorDialog::getColor(oldcolor, NULL); + + if (newColor.isValid()) + { + return model->setData(index, QVariant(newColor), Qt::EditRole); + } + + return false; +}; diff --git a/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.h b/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.h new file mode 100644 index 0000000000..1cafcc1d48 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseColorDelegate.h @@ -0,0 +1,44 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkDoseColorDelegate_h +#define QmitkDoseColorDelegate_h + + +#include + +#include "MitkRTUIExports.h" + +/** \class QmitkDoseColorDelegate +\brief An item delegate for rendering and editing dose color in a QTableView.*/ +class MITKRTUI_EXPORT QmitkDoseColorDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + /// + /// Creates a new PropertyDelegate. + /// + QmitkDoseColorDelegate(QObject *parent = 0); + + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index); + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; +}; + +#endif diff --git a/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.cpp b/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.cpp new file mode 100644 index 0000000000..34ed4b28eb --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkDoseValueDelegate.h" + +#include +#include +#include +#include + +QmitkDoseValueDelegate::QmitkDoseValueDelegate(QObject * /*parent*/) +{ +} + +void QmitkDoseValueDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option + , const QModelIndex &index) const +{ + QVariant data = index.data(Qt::DisplayRole); + + QStyleOptionViewItemV4 opt = option; + initStyleOption(&opt, index); + + QStyle *style = QApplication::style(); + + + style->drawItemText(painter, opt.rect.adjusted(0,0,-5,0), Qt::AlignRight | Qt::AlignVCenter, opt.palette,true, data.toString()); +} + +QWidget* QmitkDoseValueDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option + , const QModelIndex &index) const +{ + QVariant data = index.data(Qt::EditRole); + QVariant displayData = index.data(Qt::DisplayRole); + QVariant absoluteDose = index.data(Qt::UserRole+1); + + if(data.isValid()) + { + QDoubleSpinBox* spinBox = new QDoubleSpinBox(parent); + spinBox->setDecimals(2); + if (absoluteDose.toBool()) + { + spinBox->setSingleStep(0.5); + spinBox->setSuffix(QString(" Gy")); + } + else + { + spinBox->setSingleStep(1.0); + spinBox->setSuffix(QString(" %")); + } + + spinBox->setMinimum(0.0); + spinBox->setMaximum(9999.0); + + spinBox->installEventFilter( const_cast(this) ); + + return spinBox; + + } + else + return new QLabel(displayData.toString(), parent); + +} + +void QmitkDoseValueDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + QVariant data = index.data(Qt::EditRole); + + if(data.isValid()) + { + + QDoubleSpinBox* spinBox = qobject_cast(editor); + if (spinBox) + { + spinBox->setValue(data.toDouble()); + } + else + { + QStyledItemDelegate::setEditorData(editor, index); + } + } +} + +void QmitkDoseValueDelegate::setModelData(QWidget *editor, QAbstractItemModel* model + , const QModelIndex &index) const +{ + QVariant data = index.data(Qt::EditRole); + + if(data.isValid()) + { + QDoubleSpinBox* spinBox = qobject_cast(editor); + double doubleValue = spinBox->value(); + + QVariant doubleValueVariant(doubleValue); + model->setData(index, doubleValueVariant); + } + else + { + QStyledItemDelegate::setModelData(editor, model, index); + } +} diff --git a/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.h b/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.h new file mode 100644 index 0000000000..3e25a7799d --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseValueDelegate.h @@ -0,0 +1,63 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkDoseValueDelegate_h +#define QmitkDoseValueDelegate_h + + +#include + +#include "MitkRTUIExports.h" + +/** \class QmitkDoseValueDelegate +\brief An item delegate for rendering and editing dose values. +The delegate assumes that the model uses the role Qt::UserRole+1 +to indicate if the returned dose value is an absolute (data(Qt::UserRole+1) == true) +or an relative dose (data(Qt::UserRole+1) == false).*/ +class MITKRTUI_EXPORT QmitkDoseValueDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + /// + /// Creates a new PropertyDelegate. + /// + QmitkDoseValueDelegate(QObject *parent = 0); + + /// + /// Renders a specific property (overwritten from QItemDelegate) + /// + void paint(QPainter *painter, const QStyleOptionViewItem &option + , const QModelIndex &index) const; + + /// + /// Create an editor for a specific property (overwritten from QItemDelegate) + /// + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option + , const QModelIndex &index) const; + + /// + /// Create an editor for a specific property (overwritten from QItemDelegate) + /// + void setEditorData(QWidget *editor, const QModelIndex &index) const; + + /// + /// When the user accepts input this func commits the data to the model (overwritten from QItemDelegate) + /// + void setModelData(QWidget *editor, QAbstractItemModel* model, const QModelIndex &index) const; +}; + +#endif /* QMITKPROPERTIESTABLEMODEL_H_ */ diff --git a/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.cpp b/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.cpp new file mode 100644 index 0000000000..9de4f0b4c8 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.cpp @@ -0,0 +1,94 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "QmitkDoseVisualStyleDelegate.h" + +#include +#include +#include +#include +#include + +static QRect CheckBoxRect(const QStyleOptionViewItem &view_item_style_options) { + QStyleOptionButton check_box_style_option; + QRect check_box_rect = QApplication::style()->subElementRect( + QStyle::SE_CheckBoxIndicator, + &check_box_style_option); + QPoint check_box_point(view_item_style_options.rect.x() + + view_item_style_options.rect.width() / 2 - + check_box_rect.width() / 2, + view_item_style_options.rect.y() + + view_item_style_options.rect.height() / 2 - + check_box_rect.height() / 2); + return QRect(check_box_point, check_box_rect.size()); +} + +QmitkDoseVisualStyleDelegate::QmitkDoseVisualStyleDelegate(QObject * /*parent*/) +{ +} + +void QmitkDoseVisualStyleDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + bool checkValue = index.data(Qt::DisplayRole).toBool(); + + QStyleOptionButton BtnStyle; + BtnStyle.state = QStyle::State_Enabled; + + if(checkValue) + { + BtnStyle.state |= QStyle::State_On; + } + else + { + BtnStyle.state |= QStyle::State_Off; + } + + BtnStyle.direction = QApplication::layoutDirection(); + BtnStyle.rect = CheckBoxRect(option); + QApplication::style()->drawControl(QStyle::CE_CheckBox,&BtnStyle,painter ); +} + +bool QmitkDoseVisualStyleDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index) +{ + Q_ASSERT(event); + Q_ASSERT(model); + + // make sure that the item is checkable + Qt::ItemFlags flags = model->flags(index); + if (!(flags & Qt::ItemIsEditable) || !(flags & Qt::ItemIsEnabled)) + { + return false; + } + + // make sure that we have the right event type + QMouseEvent* mouseEvent = dynamic_cast(event); + if (!mouseEvent) + { + return false; + } + else + { + if (mouseEvent->type() != QEvent::MouseButtonRelease || mouseEvent->button() != Qt::LeftButton) + { + return false; + } + } + + bool newState = !(index.data(Qt::EditRole).toBool()); + + return model->setData(index, QVariant(newState), Qt::EditRole); +}; diff --git a/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.h b/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.h new file mode 100644 index 0000000000..2cd3a558ca --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkDoseVisualStyleDelegate.h @@ -0,0 +1,47 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkDoseVisualStyleDelegate_h +#define QmitkDoseVisualStyleDelegate_h + + +/// Toolkit includes. +#include + +#include "MitkRTUIExports.h" + + +/** \class QmitkDoseVisualStyleDelegate +\brief An item delegate for rendering and editing dose visualization options. +The delegate is used to handle aspects of a isodose level like visualization +of the isodose lines or colorwash display.*/ +class MITKRTUI_EXPORT QmitkDoseVisualStyleDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + + QmitkDoseVisualStyleDelegate(QObject *parent = 0); + + void paint(QPainter *painter, const QStyleOptionViewItem &option + , const QModelIndex &index) const; + + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index); + +}; + +#endif diff --git a/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.cpp b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.cpp new file mode 100644 index 0000000000..0a313dbedd --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.cpp @@ -0,0 +1,145 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkFreeIsoDoseLevelWidget.h" + + +QmitkFreeIsoDoseLevelWidget::QmitkFreeIsoDoseLevelWidget(QWidget*): m_ReferenceDose (40.0), m_InternalUpdate(false) +{ + this->setupUi(this); + + this->colorBtn->setDisplayColorName(false); + this->m_IsoDoseLevel = mitk::IsoDoseLevel::New(); + + connect(this->sbAbsValue, SIGNAL(valueChanged(double)), this, SLOT(OnAbsValueChanged(double))); + connect(this->sbRelValue, SIGNAL(valueChanged(double)), this, SLOT(OnRelValueChanged(double))); + connect(this->doseSlider, SIGNAL(valueChanged(int)), this, SLOT(OnSliderChanged(int))); + connect(this->checkVisibleIso, SIGNAL(clicked(bool)), this, SLOT(OnVisibleClicked(bool))); + connect(this->colorBtn, SIGNAL(colorChanged(QColor)), this, SLOT(OnColorChanged(QColor))); +} + +mitk::DoseValueAbs + QmitkFreeIsoDoseLevelWidget:: + getReferenceDose() const +{ + return this->m_ReferenceDose; +}; + +mitk::IsoDoseLevel* + QmitkFreeIsoDoseLevelWidget:: + getIsoDoseLevel() const +{ + return this->m_IsoDoseLevel; +}; + +void QmitkFreeIsoDoseLevelWidget:: + setReferenceDose(double newReferenceDose) +{ + if (newReferenceDose != m_ReferenceDose) + { + this->m_ReferenceDose = newReferenceDose; + this->update(); + } +}; + +void QmitkFreeIsoDoseLevelWidget:: + setIsoDoseLevel(mitk::IsoDoseLevel* level) +{ + if (level != m_IsoDoseLevel) + { + if(!level) + { + mitkThrow() << "Error. Cannot set iso dose level for widget to NULL pointer."; + } + + this->m_IsoDoseLevel = level; + this->update(); + } +} + +void QmitkFreeIsoDoseLevelWidget:: + OnRelValueChanged(double newValue) +{ + if(!m_InternalUpdate) + { + updateValue(newValue/100.0); + } +}; + +void QmitkFreeIsoDoseLevelWidget:: + OnAbsValueChanged(double newValue) +{ + if(!m_InternalUpdate) + { + updateValue(newValue/this->m_ReferenceDose); + } +}; + +void QmitkFreeIsoDoseLevelWidget:: + OnSliderChanged(int newValue) +{ + if(!m_InternalUpdate) + { + updateValue(newValue/100.0); + } +}; + +void QmitkFreeIsoDoseLevelWidget:: + OnVisibleClicked(bool checked) +{ + this->m_IsoDoseLevel->SetVisibleIsoLine(checked); + emit VisualizationStyleChanged(this->m_IsoDoseLevel); +}; + +void QmitkFreeIsoDoseLevelWidget:: + OnColorChanged(QColor color) +{ + mitk::IsoDoseLevel::ColorType doseColor; + doseColor.SetRed(color.redF()); + doseColor.SetGreen(color.greenF()); + doseColor.SetBlue(color.blueF()); + this->m_IsoDoseLevel->SetColor(doseColor); + emit ColorChanged(this->m_IsoDoseLevel); +}; + +void QmitkFreeIsoDoseLevelWidget:: + updateValue(mitk::DoseValueRel newDose) +{ + m_InternalUpdate = true; + + mitk::DoseValueRel oldValue = this->m_IsoDoseLevel->GetDoseValue(); + this->m_IsoDoseLevel->SetDoseValue(newDose); + this->sbAbsValue->setValue(newDose*this->m_ReferenceDose); + this->sbRelValue->setValue(newDose*100); + this->doseSlider->setValue(newDose*100); + + m_InternalUpdate = false; + + emit ValueChanged(this->m_IsoDoseLevel,oldValue); +}; + +void QmitkFreeIsoDoseLevelWidget:: + update() +{ + updateValue(this->m_IsoDoseLevel->GetDoseValue()); + + this->checkVisibleIso->setChecked(this->m_IsoDoseLevel->GetVisibleIsoLine()); + + QColor color; + color.setRgbF(this->m_IsoDoseLevel->GetColor().GetRed(),this->m_IsoDoseLevel->GetColor().GetGreen(),this->m_IsoDoseLevel->GetColor().GetBlue()); + this->colorBtn->setColor(color); +}; diff --git a/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.h b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.h new file mode 100644 index 0000000000..8d6c175f66 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.h @@ -0,0 +1,78 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef QMITK_FREE_ISO_DOSE_LEVEL_WIDGET_H +#define QMITK_FREE_ISO_DOSE_LEVEL_WIDGET_H + +#include "MitkRTUIExports.h" + +#include "ui_QmitkFreeIsoDoseLevelWidget.h" +#include + +#include "mitkIsoDoseLevel.h" + +/** +* \class QmitkFreeIsoDoseLevelWidget +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITKRTUI_EXPORT QmitkFreeIsoDoseLevelWidget : public QWidget, private Ui::QmitkFreeIsoDoseLevelWidget +{ + Q_OBJECT + +public: + QmitkFreeIsoDoseLevelWidget(QWidget* parent=0); + + mitk::DoseValueAbs getReferenceDose() const; + mitk::IsoDoseLevel* getIsoDoseLevel() const; + +signals: + void ValueChanged(mitk::IsoDoseLevel*, mitk::DoseValueRel oldValue); + void ColorChanged(mitk::IsoDoseLevel*); + void VisualizationStyleChanged(mitk::IsoDoseLevel*); + + public Q_SLOTS: + /** + * \brief Slot that can be used to set the reference dose. + */ + void setReferenceDose(double newReferenceDose); + + /** + * \brief Slot that can be used to set the dose level instance that should be handled by the widget. + */ + void setIsoDoseLevel(mitk::IsoDoseLevel* level); + + void OnRelValueChanged(double newValue); + void OnAbsValueChanged(double newValue); + void OnSliderChanged(int newValue); + void OnVisibleClicked(bool checked); + void OnColorChanged(QColor color); + +protected: + + /** + * \brief Updates the widget according to its current settings. + */ + void update(); + void updateValue(mitk::DoseValueRel newDose); + + mitk::DoseValueAbs m_ReferenceDose; + mitk::IsoDoseLevel::Pointer m_IsoDoseLevel; + bool m_InternalUpdate; + +}; + +#endif // QmitkFreeIsoDoseLevelWidget_H diff --git a/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.ui b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.ui new file mode 100644 index 0000000000..1f168c8044 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkFreeIsoDoseLevelWidget.ui @@ -0,0 +1,201 @@ + + + QmitkFreeIsoDoseLevelWidget + + + + 0 + 0 + 395 + 32 + + + + Form + + + + 2 + + + + + + 0 + 0 + + + + + 40 + 16777215 + + + + Color of the iso dose level + + + + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + 150 + + + Qt::Horizontal + + + false + + + false + + + QSlider::NoTicks + + + 0 + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + % + + + 9999.000000000000000 + + + 0.500000000000000 + + + + + + + = + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + Minimum dose value of this level. + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Gy + + + 9999.000000000000000 + + + 0.500000000000000 + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 50 + 16777215 + + + + Show isoline for this dose level + + + Qt::LeftToRight + + + + + + + :/RTUI/eye_open.png + :/RTUI/eye_open.png + :/RTUI/eye_open.png:/RTUI/eye_open.png + + + + 24 + 16 + + + + false + + + + + + + + ctkColorPickerButton + QPushButton +
ctkColorPickerButton.h
+
+
+ + + + +
diff --git a/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.cpp b/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.cpp new file mode 100644 index 0000000000..18348d2073 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.cpp @@ -0,0 +1,450 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include + +#include "QmitkIsoDoseLevelSetModel.h" +#include "mitkRTUIConstants.h" + +QmitkIsoDoseLevelSetModel:: + QmitkIsoDoseLevelSetModel(QObject *parent) : +QAbstractTableModel(parent), m_referenceDose(mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE), m_showAbsoluteDose(false), m_visibilityEditOnly(false), m_modified(false) +{ + m_DoseSet = mitk::IsoDoseLevelSet::New(); +} + +void + QmitkIsoDoseLevelSetModel:: + setIsoDoseLevelSet(mitk::IsoDoseLevelSet *pSet) +{ + if (pSet) + { + emit beginResetModel(); + + m_DoseSet = pSet; + m_modified = false; + + emit endResetModel(); + } +}; + +int + QmitkIsoDoseLevelSetModel:: + rowCount(const QModelIndex &parent) const +{ + if(parent.isValid()) + { + return 0; + } + + return m_DoseSet->Size(); +} + +int + QmitkIsoDoseLevelSetModel:: + columnCount(const QModelIndex &parent) const +{ + if(parent.isValid()) + return 0; + + return 4; +} + +QVariant + QmitkIsoDoseLevelSetModel:: + data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + QVariant result; + + if(index.row()Size()) + { + const mitk::IsoDoseLevel& level = m_DoseSet->GetIsoDoseLevel(static_cast(index.row())); + + switch(index.column()) + { + case 0: + if(role == Qt::EditRole || role == Qt::DecorationRole) + { + QColor color; + color.setRgbF(level.GetColor().GetRed(),level.GetColor().GetGreen(),level.GetColor().GetBlue()); + result = QVariant(color); + } + else if (role == Qt::ToolTipRole) + { + result = QVariant("Color of the iso dose level."); + } + break; + case 1: + if(role == Qt::DisplayRole) + { + if (this->m_showAbsoluteDose) + { + result = QVariant(QString::number(level.GetDoseValue()*this->m_referenceDose)+QString(" Gy")); + } + else + { + result = QVariant(QString::number(level.GetDoseValue()*100)+QString(" %")); + } + } + else if(role == Qt::EditRole) + { + if (this->m_showAbsoluteDose) + { + result = QVariant(level.GetDoseValue()*this->m_referenceDose); + } + else + { + result = QVariant(level.GetDoseValue()*100); + } + } + else if (role == Qt::ToolTipRole) + { + result = QVariant("Minimum dose value of this level / Value of the iso line."); + } + else if (role == Qt::UserRole+1) + { + result = QVariant(this->m_showAbsoluteDose); + } + break; + case 2: + if(role == Qt::DisplayRole || role == Qt::EditRole) + { + result = QVariant(level.GetVisibleIsoLine()); + } + else if (role == Qt::ToolTipRole) + { + result = QVariant("Show isoline for this dose level."); + } + break; + case 3: + if(role == Qt::DisplayRole || role == Qt::EditRole) + { + result = QVariant(level.GetVisibleColorWash()); + } + else if (role == Qt::ToolTipRole) + { + result = QVariant("Show colorwash for this dose level."); + } + break; + } + } + + return result; +} + +Qt::ItemFlags + QmitkIsoDoseLevelSetModel:: + flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + + if(index.row()Size()) + { + if (index.column() < 4) + { + if ((index.column() > 1) || (index.column() >= 0 && !this->m_visibilityEditOnly)) + { + flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + else if (index.column() >= 0 && this->m_visibilityEditOnly) + { + flags |= Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + } + } + + return flags; +} + +QVariant + QmitkIsoDoseLevelSetModel:: + headerData(int section, Qt::Orientation orientation, int role) const +{ + if( (Qt::DisplayRole == role) && + (Qt::Horizontal == orientation)) + { + if (section==0) + { + return QVariant("Color"); + } + else if (section==1) + { + if (m_showAbsoluteDose) + { + return QVariant("Dose [Gy]"); + } + else + { + return QVariant("Dose [%]"); + } + } + else if (section==2) + { + return QVariant("IsoLines"); + } + else if (section==3) + { + return QVariant("ColorWash"); + } + } + return QVariant(); +} + +bool + QmitkIsoDoseLevelSetModel:: + setData(const QModelIndex &index, const QVariant &value, int role) +{ + if(!index.isValid() || (m_DoseSet->Size() <= index.row()) || (index.column()>3)) + { + return false; + } + + if(Qt::EditRole == role) + { + const mitk::IsoDoseLevel& level = m_DoseSet->GetIsoDoseLevel(static_cast(index.row())); + mitk::IsoDoseLevel::Pointer pNewLevel = level.Clone(); + switch(index.column()) + { + case 0: + { + QColor val = value.value(); + mitk::IsoDoseLevel::ColorType color; + color.SetRed(val.redF()); + color.SetGreen(val.greenF()); + color.SetBlue(val.blueF()); + pNewLevel->SetColor(color); + emit dataChanged(index,index); + break; + } + case 1: + if (this->m_showAbsoluteDose) + { + pNewLevel->SetDoseValue(value.toDouble()/this->m_referenceDose); + } + else + { + pNewLevel->SetDoseValue(value.toDouble()/100.0); + } + emit dataChanged(index,index); + break; + case 2: + pNewLevel->SetVisibleIsoLine(value.toBool()); + emit dataChanged(index,index); + break; + case 3: + pNewLevel->SetVisibleColorWash(value.toBool()); + emit dataChanged(index,index); + break; + } + + emit beginResetModel(); + + m_DoseSet->DeleteIsoDoseLevel(static_cast(index.row())); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + + m_modified = true; + + emit endResetModel(); + + return true; + } + + return false; +}; + +void QmitkIsoDoseLevelSetModel:: + setReferenceDose(double newReferenceDose) +{ + if (newReferenceDose<= 0) + { + mitkThrow() << "Error. Passed prescribed dose is negative or equals 0."; + } + + if (newReferenceDose != m_referenceDose) + { + this->m_referenceDose = newReferenceDose; + if(m_showAbsoluteDose) + { + emit beginResetModel(); + emit endResetModel(); + } + } +}; + +void QmitkIsoDoseLevelSetModel:: + setShowAbsoluteDose(bool showAbsoluteDose) + +{ + if (showAbsoluteDose != m_showAbsoluteDose) + { + emit beginResetModel(); + this->m_showAbsoluteDose = showAbsoluteDose; + emit endResetModel(); + } +}; + +void QmitkIsoDoseLevelSetModel::setVisibilityEditOnly(bool onlyVisibility) +{ + if (onlyVisibility != m_visibilityEditOnly) + { + emit beginResetModel(); + this->m_visibilityEditOnly = onlyVisibility; + emit endResetModel(); + } +}; + +bool + QmitkIsoDoseLevelSetModel:: + getShowAbsoluteDose() const +{ + return this->m_showAbsoluteDose; +}; + +mitk::DoseValueAbs + QmitkIsoDoseLevelSetModel:: + getReferenceDose() const +{ + return this->m_referenceDose; +}; + +bool + QmitkIsoDoseLevelSetModel:: + getVisibilityEditOnly() const +{ + return this->m_visibilityEditOnly; +}; + +void QmitkIsoDoseLevelSetModel::switchVisibilityIsoLines(bool activate) +{ + emit beginResetModel(); + + for (mitk::IsoDoseLevelSet::IsoLevelIndexType pos = 0; pos < m_DoseSet->Size(); ++pos) + { + mitk::IsoDoseLevel::Pointer pNewLevel = m_DoseSet->GetIsoDoseLevel(pos).Clone(); + pNewLevel->SetVisibleIsoLine(activate); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + } + + m_modified = true; + + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::switchVisibilityColorWash(bool activate) +{ + emit beginResetModel(); + + for (mitk::IsoDoseLevelSet::IsoLevelIndexType pos = 0; pos < m_DoseSet->Size(); ++pos) + { + mitk::IsoDoseLevel::Pointer pNewLevel = m_DoseSet->GetIsoDoseLevel(pos).Clone(); + pNewLevel->SetVisibleColorWash(activate); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + } + + m_modified = true; + + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::invertVisibilityIsoLines() +{ + emit beginResetModel(); + + for (mitk::IsoDoseLevelSet::IsoLevelIndexType pos = 0; pos < m_DoseSet->Size(); ++pos) + { + mitk::IsoDoseLevel::Pointer pNewLevel = m_DoseSet->GetIsoDoseLevel(pos).Clone(); + pNewLevel->SetVisibleIsoLine(!pNewLevel->GetVisibleIsoLine()); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + } + + m_modified = true; + + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::invertVisibilityColorWash() +{ + emit beginResetModel(); + + for (mitk::IsoDoseLevelSet::IsoLevelIndexType pos = 0; pos < m_DoseSet->Size(); ++pos) + { + mitk::IsoDoseLevel::Pointer pNewLevel = m_DoseSet->GetIsoDoseLevel(pos).Clone(); + pNewLevel->SetVisibleColorWash(!pNewLevel->GetVisibleColorWash()); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + } + + m_modified = true; + + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::swapVisibility() +{ + emit beginResetModel(); + + for (mitk::IsoDoseLevelSet::IsoLevelIndexType pos = 0; pos < m_DoseSet->Size(); ++pos) + { + mitk::IsoDoseLevel::Pointer pNewLevel = m_DoseSet->GetIsoDoseLevel(pos).Clone(); + bool colorWash = pNewLevel->GetVisibleColorWash(); + pNewLevel->SetVisibleColorWash(pNewLevel->GetVisibleIsoLine()); + pNewLevel->SetVisibleIsoLine(colorWash); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + } + + m_modified = true; + + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::addLevel() +{ + mitk::IsoDoseLevel::DoseValueType doseVal = 0.01; + + if (m_DoseSet->Size()>0) + { + doseVal = m_DoseSet->GetIsoDoseLevel(m_DoseSet->Size()-1).GetDoseValue()+0.01; + } + + mitk::IsoDoseLevel::Pointer pNewLevel = mitk::IsoDoseLevel::New(doseVal, mitk::IsoDoseLevel::ColorType(), true, true); + + emit beginResetModel(); + m_DoseSet->SetIsoDoseLevel(pNewLevel); + m_modified = true; + emit endResetModel(); +} + +void QmitkIsoDoseLevelSetModel::deleteLevel(const QModelIndex &index) +{ + if(!index.isValid() || (m_DoseSet->Size() <= index.row()) || (index.column()>3)) + { + return; + } + + emit beginResetModel(); + m_DoseSet->DeleteIsoDoseLevel(static_cast(index.row())); + m_modified = true; + emit endResetModel(); +} + +bool QmitkIsoDoseLevelSetModel::isModified() +{ + return m_modified; +} diff --git a/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.h b/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.h new file mode 100644 index 0000000000..af7f19c9f5 --- /dev/null +++ b/Modules/RTUI/Qmitk/QmitkIsoDoseLevelSetModel.h @@ -0,0 +1,98 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QmitkIsoDoseLevelSetModel_h +#define QmitkIsoDoseLevelSetModel_h + +#include + +#include "mitkIsoDoseLevelCollections.h" + +#include "MitkRTUIExports.h" + + +/*! +\class QmitkIsoDoseLevelSetModel +Model that handles a iso dose level set and allows viewing and editing of its contents. +Please see special delegates (QmitkDoseColorDelegate, QmitkDoseValueDelegate, QmitkDoseVisualStyleDelegate) to +handle visualization and editing in views that work on this model. +\warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. +*/ +class MITKRTUI_EXPORT QmitkIsoDoseLevelSetModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + QmitkIsoDoseLevelSetModel(QObject *parent = NULL); + virtual ~QmitkIsoDoseLevelSetModel() {}; + + /** Sets the data handled by the model and resets the modified flag*/ + void setIsoDoseLevelSet(mitk::IsoDoseLevelSet *pSet); + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + bool getShowAbsoluteDose() const; + mitk::DoseValueAbs getReferenceDose() const; + + bool getVisibilityEditOnly() const; + + void switchVisibilityIsoLines(bool activate); + void switchVisibilityColorWash(bool activate); + void invertVisibilityIsoLines(); + void invertVisibilityColorWash(); + void swapVisibility(); + + void addLevel(); + void deleteLevel(const QModelIndex &index); + + /**Indicates if the content of the model was modified since the data was set via setIsoDoseLevelSet()*/ + bool isModified(); + + public Q_SLOTS: + /** + * \brief Slot that can be used to set the prescribed dose. + */ + void setReferenceDose(double newReferenceDose); + /** + * \brief Slot that can be used to adjust whether the dose should be displayed in absolute or relative units. + */ + void setShowAbsoluteDose(bool showAbsoluteDose); + + /** + * \brief Slat that can be used to adjust wether the model allows to edit only visibilities (no dose value or color) + */ + void setVisibilityEditOnly(bool onlyVisibility); + +private: + mitk::IsoDoseLevelSet::Pointer m_DoseSet; + + bool m_showAbsoluteDose; + bool m_visibilityEditOnly; + + mitk::DoseValueAbs m_referenceDose; + + /** Indicates if the data of the model was modified, since the model was set. */ + bool m_modified; + +}; + +#endif // QmitkIsoDoseLevelSetModel_h + diff --git a/Modules/RTUI/files.cmake b/Modules/RTUI/files.cmake new file mode 100644 index 0000000000..d49a968f4c --- /dev/null +++ b/Modules/RTUI/files.cmake @@ -0,0 +1,27 @@ +set(CPP_FILES + Qmitk/QmitkFreeIsoDoseLevelWidget.cpp + Qmitk/QmitkIsoDoseLevelSetModel.cpp + Qmitk/QmitkDoseColorDelegate.cpp + Qmitk/QmitkDoseValueDelegate.cpp + Qmitk/QmitkDoseVisualStyleDelegate.cpp + Helper/mitkRTUIConstants.cpp + Helper/mitkIsoLevelsGenerator.cpp +) + +set(UI_FILES + Qmitk/QmitkFreeIsoDoseLevelWidget.ui +) + +set(MOC_H_FILES + Qmitk/QmitkFreeIsoDoseLevelWidget.h + Qmitk/QmitkIsoDoseLevelSetModel.h + Qmitk/QmitkDoseColorDelegate.h + Qmitk/QmitkDoseValueDelegate.h + Qmitk/QmitkDoseVisualStyleDelegate.h +) + +set(QRC_FILES + resources/RTUI.qrc +) + + diff --git a/Modules/RTUI/resources/RTUI.qrc b/Modules/RTUI/resources/RTUI.qrc new file mode 100644 index 0000000000..174c9563ea --- /dev/null +++ b/Modules/RTUI/resources/RTUI.qrc @@ -0,0 +1,8 @@ + + + powerGreen.png + eye_close.png + eye_open.png + powerRed.png + + diff --git a/Modules/RTUI/resources/eye_close.png b/Modules/RTUI/resources/eye_close.png new file mode 100644 index 0000000000..9b82203c2a Binary files /dev/null and b/Modules/RTUI/resources/eye_close.png differ diff --git a/Modules/RTUI/resources/eye_open.png b/Modules/RTUI/resources/eye_open.png new file mode 100644 index 0000000000..a1c2bb9f35 Binary files /dev/null and b/Modules/RTUI/resources/eye_open.png differ diff --git a/Modules/RTUI/resources/powerGreen.png b/Modules/RTUI/resources/powerGreen.png new file mode 100644 index 0000000000..9e8e0903d9 Binary files /dev/null and b/Modules/RTUI/resources/powerGreen.png differ diff --git a/Modules/RTUI/resources/powerRed.png b/Modules/RTUI/resources/powerRed.png new file mode 100644 index 0000000000..bb3f33bef5 Binary files /dev/null and b/Modules/RTUI/resources/powerRed.png differ diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index a463cdaaa1..793febaa12 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,71 +1,72 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:OFF org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.diffusionimaging:OFF org.mitk.simulation:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.diffusionimaging:OFF + org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.dtiatlasapp:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.igtlplugin:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.registration:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.simulation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.spectrocamrecorder:OFF ) diff --git a/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt b/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt index 4295b3197c..a97d8f0a14 100644 --- a/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt +++ b/Plugins/org.mitk.gui.qt.dicom/CMakeLists.txt @@ -1,26 +1,26 @@ project(org_mitk_gui_qt_dicom) find_program(DCMTK_STORESCP NAMES storescp storescp${DCMTK_CMAKE_DEBUG_POSTFIX} storescp${CMAKE_DEBUG_POSTFIX} PATHS "${DCMTK_DIR}/bin" PATH_SUFFIXES Release Debug DOC "Dcmtk storage provider which is used to store dicom files which are transfered over network." NO_DEFAULT_PATH ) mark_as_advanced(DCMTK_STORESCP) if(NOT EXISTS ${DCMTK_STORESCP}) message(WARNING "Couldn't find program storescp without the program query retrieve of the dicom plugin won't work!") else(NOT EXISTS ${DCMTK_STORESCP}) configure_file( org_mitk_gui_qt_dicom_config.h.in org_mitk_gui_qt_dicom_config.h @ONLY) MITK_INSTALL_HELPER_APP(${DCMTK_STORESCP}) mitk_create_plugin( EXPORT_DIRECTIVE DICOM_EXPORT EXPORTED_INCLUDE_SUFFIXES src - MODULE_DEPENDS MitkQtWidgetsExt MitkDicomUI + MODULE_DEPENDS MitkQtWidgetsExt MitkDicomUI MitkDicomRT MitkRTUI ) endif() diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp index 8466fe77cf..38467e18bb 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/DicomEventHandler.cpp @@ -1,98 +1,277 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPluginActivator.h" #include "DicomEventHandler.h" #include #include #include #include #include #include #include #include #include #include #include "mitkImage.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include DicomEventHandler::DicomEventHandler() { } DicomEventHandler::~DicomEventHandler() { } void DicomEventHandler::OnSignalAddSeriesToDataManager(const ctkEvent& ctkEvent) { - QStringList listOfFilesForSeries; - mitk::DicomSeriesReader::StringContainer seriesToLoad; + QStringList listOfFilesForSeries; + mitk::DicomSeriesReader::StringContainer seriesToLoad; + + listOfFilesForSeries = ctkEvent.getProperty("FilesForSeries").toStringList(); + + if (!listOfFilesForSeries.isEmpty()){ - listOfFilesForSeries = ctkEvent.getProperty("FilesForSeries").toStringList(); + //for rt data, if the modality tag isnt defined or is "CT" the image is handled like before + if(ctkEvent.containsProperty("Modality") && + (ctkEvent.getProperty("Modality").toString().compare("RTDOSE",Qt::CaseInsensitive) == 0 || + ctkEvent.getProperty("Modality").toString().compare("RTSTRUCT",Qt::CaseInsensitive) == 0)) + { + QString modality = ctkEvent.getProperty("Modality").toString(); - if (!listOfFilesForSeries.isEmpty()){ + if(modality.compare("RTDOSE",Qt::CaseInsensitive) == 0) + { + mitk::RTDoseReader::Pointer doseReader = mitk::RTDoseReader::New(); - QStringListIterator it(listOfFilesForSeries); + mitk::DataNode::Pointer doseImageNode = mitk::DataNode::New(); + mitk::DataNode::Pointer doseOutlineNode = mitk::DataNode::New(); - while (it.hasNext()) + doseImageNode = doseReader->LoadRTDose(listOfFilesForSeries.at(0).toStdString().c_str()); + doseOutlineNode->SetData(doseImageNode->GetData()); + if(doseImageNode.IsNotNull() && doseOutlineNode->GetData() != NULL) { - seriesToLoad.push_back(it.next().toStdString()); - } + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str()); + + typedef QStringList NamesType; + NamesType names = prefNode->ChildrenNames(); + + std::map presetMap; + + for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) + { + berry::IPreferences::Pointer aPresetNode = prefNode->Node(*pos); + + if (aPresetNode.IsNull()) + { + mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: "<< (*pos).toStdString(); + } + + mitk::IsoDoseLevelSet::Pointer levelSet = mitk::IsoDoseLevelSet::New(); + + NamesType levelNames = aPresetNode->ChildrenNames(); + for (NamesType::const_iterator levelName = levelNames.begin(); levelName != levelNames.end(); ++levelName) + { + berry::IPreferences::Pointer levelNode = aPresetNode->Node(*levelName); + if (aPresetNode.IsNull()) + { + mitkThrow() << "Error in preference interface. Cannot find level node under given preset name. Name: "<< (*pos).toStdString() <<"; Level id: "<< (*levelName).toStdString(); + } + + mitk::IsoDoseLevel::Pointer isoLevel = mitk::IsoDoseLevel::New(); + + isoLevel->SetDoseValue(levelNode->GetDouble(mitk::RTUIConstants::ISO_LEVEL_DOSE_VALUE_ID.c_str(),0.0)); + mitk::IsoDoseLevel::ColorType color; + color.SetRed(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_RED_ID.c_str(),1.0)); + color.SetGreen(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_GREEN_ID.c_str(),1.0)); + color.SetBlue(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_BLUE_ID.c_str(),1.0)); + isoLevel->SetColor(color); + isoLevel->SetVisibleIsoLine(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_ISOLINES_ID.c_str(),true)); + isoLevel->SetVisibleColorWash(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_COLORWASH_ID.c_str(),true)); + + levelSet->SetIsoDoseLevel(isoLevel); + } + + presetMap.insert(std::make_pair((*pos).toStdString(),levelSet)); + } + + if (presetMap.size() == 0) + { + presetMap.insert(std::make_pair(std::string("Virtuos"), mitk::GeneratIsoLevels_Virtuos())); + } + + double referenceDose = 40.0; + //set some specific colorwash and isoline properties + doseImageNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(), true); + doseOutlineNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(), true); + //Set reference dose property + doseImageNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), referenceDose); + doseOutlineNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), referenceDose); + + berry::IPreferences::Pointer nameNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + QString presetName = nameNode->Get(mitk::RTUIConstants::SELECTED_ISO_PRESET_ID.c_str(),""); + mitk::IsoDoseLevelSet::Pointer isoDoseLevelPreset = presetMap[presetName.toStdString()]; + mitk::IsoDoseLevelSetProperty::Pointer levelSetProp = mitk::IsoDoseLevelSetProperty::New(isoDoseLevelPreset); - mitk::DataNode::Pointer node = mitk::DicomSeriesReader::LoadDicomSeries(seriesToLoad); - if (node.IsNull()) + doseImageNode->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(),levelSetProp); + doseOutlineNode->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(),levelSetProp); + + mitk::IsoDoseLevelVector::Pointer levelVector = mitk::IsoDoseLevelVector::New(); + mitk::IsoDoseLevelVectorProperty::Pointer levelVecProp = mitk::IsoDoseLevelVectorProperty::New(levelVector); + doseImageNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(),levelVecProp); + doseOutlineNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(),levelVecProp); + + //Generating the Colorwash + vtkSmartPointer transferFunction = vtkSmartPointer::New(); + + for(mitk::IsoDoseLevelSet::ConstIterator itIsoDoseLevel = isoDoseLevelPreset->Begin(); itIsoDoseLevel != isoDoseLevelPreset->End(); ++itIsoDoseLevel) + { + float *hsv = new float[3]; + //used for transfer rgb to hsv + vtkSmartPointer cCalc = vtkSmartPointer::New(); + if(itIsoDoseLevel->GetVisibleColorWash()){ + cCalc->RGBToHSV(itIsoDoseLevel->GetColor()[0],itIsoDoseLevel->GetColor()[1],itIsoDoseLevel->GetColor()[2],&hsv[0],&hsv[1],&hsv[2]); + transferFunction->AddHSVPoint(itIsoDoseLevel->GetDoseValue()*referenceDose,hsv[0],hsv[1],hsv[2],1.0,1.0); + } + } + + mitk::TransferFunction::Pointer mitkTransFunc = mitk::TransferFunction::New(); + mitk::TransferFunctionProperty::Pointer mitkTransFuncProp = mitk::TransferFunctionProperty::New(); + mitkTransFunc->SetColorTransferFunction(transferFunction); + mitkTransFuncProp->SetValue(mitkTransFunc); + + mitk::RenderingModeProperty::Pointer renderingModeProp = mitk::RenderingModeProperty::New(); + renderingModeProp->SetValue(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); + + doseImageNode->SetProperty("Image Rendering.Transfer Function", mitkTransFuncProp); + doseImageNode->SetProperty("Image Rendering.Mode", renderingModeProp); + doseImageNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); + + //set the outline properties + doseOutlineNode->SetBoolProperty("outline binary", true); + doseOutlineNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); + doseOutlineNode->SetProperty( "includeInBoundingBox", mitk::BoolProperty::New(false) ); + + ctkServiceReference serviceReference =mitk::PluginActivator::getContext()->getServiceReference(); + mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); + mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); + + dataStorage->Add(doseImageNode); + dataStorage->Add(doseOutlineNode, doseImageNode); + + //set the dose mapper for outline drawing; the colorwash is realized by the imagevtkmapper2D + mitk::DoseImageVtkMapper2D::Pointer contourMapper = mitk::DoseImageVtkMapper2D::New(); + doseOutlineNode->SetMapper(1,contourMapper); + + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); + }//END DOSE + } + else if(modality.compare("RTSTRUCT",Qt::CaseInsensitive) == 0) + { + mitk::RTStructureSetReader::Pointer structreader = mitk::RTStructureSetReader::New(); + std::deque modelVector = structreader->ReadStructureSet(listOfFilesForSeries.at(0).toStdString().c_str()); + + if(modelVector.empty()) { - MITK_ERROR << "Error loading series: " << ctkEvent.getProperty("SeriesName").toString().toStdString() - << " id: " <getServiceReference(); - mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); - mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); - - dataStorage->Add(node); + ctkServiceReference serviceReference =mitk::PluginActivator::getContext()->getServiceReference(); + mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); + mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); - // Initialize the RenderWindow - mitk::TimeGeometry::Pointer geometry = dataStorage->ComputeBoundingGeometry3D(dataStorage->GetAll()); - mitk::RenderingManager::GetInstance()->InitializeViews(geometry); + for(int i=0; iAdd(modelVector.at(i)); + } + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } + } } else { - MITK_INFO << "There are no files for the current series"; + + QStringListIterator it(listOfFilesForSeries); + + while (it.hasNext()) + { + seriesToLoad.push_back(it.next().toStdString()); + } + + + mitk::DataNode::Pointer node = mitk::DicomSeriesReader::LoadDicomSeries(seriesToLoad); + if (node.IsNull()) + { + MITK_ERROR << "Error loading series: " << ctkEvent.getProperty("SeriesName").toString().toStdString() + << " id: " <getServiceReference(); + mitk::IDataStorageService* storageService = mitk::PluginActivator::getContext()->getService(serviceReference); + mitk::DataStorage* dataStorage = storageService->GetDefaultDataStorage().GetPointer()->GetDataStorage(); + + dataStorage->Add(node); + } } + } + else + { + MITK_INFO << "There are no files for the current series"; + } } void DicomEventHandler::OnSignalRemoveSeriesFromStorage(const ctkEvent& /*ctkEvent*/) { } void DicomEventHandler::SubscribeSlots() { - ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); - if (ref) - { - ctkEventAdmin* eventAdmin = mitk::PluginActivator::getContext()->getService(ref); - ctkDictionary properties; - properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/ADD"; - eventAdmin->subscribeSlot(this, SLOT(OnSignalAddSeriesToDataManager(ctkEvent)), properties); - properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/DELETED"; - eventAdmin->subscribeSlot(this, SLOT(OnSignalRemoveSeriesFromStorage(ctkEvent)), properties); - } + ctkServiceReference ref = mitk::PluginActivator::getContext()->getServiceReference(); + if (ref) + { + ctkEventAdmin* eventAdmin = mitk::PluginActivator::getContext()->getService(ref); + ctkDictionary properties; + properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/ADD"; + eventAdmin->subscribeSlot(this, SLOT(OnSignalAddSeriesToDataManager(ctkEvent)), properties); + properties[ctkEventConstants::EVENT_TOPIC] = "org/mitk/gui/qt/dicom/DELETED"; + eventAdmin->subscribeSlot(this, SLOT(OnSignalRemoveSeriesFromStorage(ctkEvent)), properties); + } } diff --git a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomBrowser.cpp b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomBrowser.cpp index 7167a2da44..e7b0486e28 100644 --- a/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomBrowser.cpp +++ b/Plugins/org.mitk.gui.qt.dicom/src/internal/QmitkDicomBrowser.cpp @@ -1,202 +1,206 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Qmitk #include "QmitkDicomBrowser.h" #include "mitkPluginActivator.h" #include "berryIQtPreferencePage.h" #include #include #include #include const std::string QmitkDicomBrowser::EDITOR_ID = "org.mitk.editors.dicombrowser"; const QString QmitkDicomBrowser::TEMP_DICOM_FOLDER_SUFFIX="TmpDicomFolder"; QmitkDicomBrowser::QmitkDicomBrowser() : m_Thread(new QThread()) , m_DicomDirectoryListener(new QmitkDicomDirectoryListener()) , m_StoreSCPLauncher(new QmitkStoreSCPLauncher(&m_Builder)) , m_Publisher(new QmitkDicomDataEventPublisher()) { } QmitkDicomBrowser::~QmitkDicomBrowser() { m_Thread.quit(); m_Thread.wait(1000); delete m_DicomDirectoryListener; delete m_StoreSCPLauncher; delete m_Handler; delete m_Publisher; } void QmitkDicomBrowser::CreateQtPartControl(QWidget *parent ) { m_Controls.setupUi( parent ); m_Controls.StoreSCPStatusLabel->setTextFormat(Qt::RichText); m_Controls.StoreSCPStatusLabel->setText(""); TestHandler(); OnPreferencesChanged(nullptr); CreateTemporaryDirectory(); StartDicomDirectoryListener(); m_Controls.m_ctkDICOMQueryRetrieveWidget->useProgressDialog(false); connect(m_Controls.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int))); connect(m_Controls.externalDataWidget,SIGNAL(SignalStartDicomImport(const QStringList&)), m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&))); connect(m_Controls.externalDataWidget,SIGNAL(SignalDicomToDataManager(const QHash&)), this,SLOT(OnViewButtonAddToDataManager(const QHash&))); connect(m_Controls.internalDataWidget,SIGNAL(SignalFinishedImport()),this, SLOT(OnDicomImportFinished())); connect(m_Controls.internalDataWidget,SIGNAL(SignalDicomToDataManager(const QHash&)), this,SLOT(OnViewButtonAddToDataManager(const QHash&))); } void QmitkDicomBrowser::Init(berry::IEditorSite::Pointer site, berry::IEditorInput::Pointer input) { this->SetSite(site); this->SetInput(input); } void QmitkDicomBrowser::SetFocus() { } berry::IPartListener::Events::Types QmitkDicomBrowser::GetPartEventTypes() const { return Events::CLOSED | Events::HIDDEN | Events::VISIBLE; } void QmitkDicomBrowser::OnTabChanged(int page) { if (page == 2)//Query/Retrieve is selected { QString storagePort = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StoragePort"].toString(); QString storageAET = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StorageAETitle"].toString(); if(!((m_Builder.GetAETitle()->compare(storageAET,Qt::CaseSensitive)==0)&& (m_Builder.GetPort()->compare(storagePort,Qt::CaseSensitive)==0))) { StopStoreSCP(); StartStoreSCP(); } } } void QmitkDicomBrowser::OnDicomImportFinished() { m_Controls.tabWidget->setCurrentIndex(0); } void QmitkDicomBrowser::StartDicomDirectoryListener() { if(!m_Thread.isRunning()) { m_DicomDirectoryListener->SetDicomListenerDirectory(m_TempDirectory); m_DicomDirectoryListener->SetDicomFolderSuffix(TEMP_DICOM_FOLDER_SUFFIX); connect(m_DicomDirectoryListener,SIGNAL(SignalStartDicomImport(const QStringList&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&)),Qt::DirectConnection); //connect(m_Controls.internalDataWidget,SIGNAL(SignalFinishedImport()),m_DicomDirectoryListener,SLOT(OnImportFinished()),Qt::DirectConnection); m_DicomDirectoryListener->moveToThread(&m_Thread); m_Thread.start(); } } void QmitkDicomBrowser::TestHandler() { m_Handler = new DicomEventHandler(); m_Handler->SubscribeSlots(); } void QmitkDicomBrowser::OnViewButtonAddToDataManager(QHash eventProperties) { ctkDictionary properties; // properties["PatientName"] = eventProperties["PatientName"]; // properties["StudyUID"] = eventProperties["StudyUID"]; // properties["StudyName"] = eventProperties["StudyName"]; // properties["SeriesUID"] = eventProperties["SeriesUID"]; // properties["SeriesName"] = eventProperties["SeriesName"]; properties["FilesForSeries"] = eventProperties["FilesForSeries"]; + if(eventProperties.contains("Modality")) + { + properties["Modality"] = eventProperties["Modality"]; + } m_Publisher->PublishSignals(mitk::PluginActivator::getContext()); m_Publisher->AddSeriesToDataManagerEvent(properties); } void QmitkDicomBrowser::StartStoreSCP() { QString storagePort = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StoragePort"].toString(); QString storageAET = m_Controls.m_ctkDICOMQueryRetrieveWidget->getServerParameters()["StorageAETitle"].toString(); m_Builder.AddPort(storagePort)->AddAETitle(storageAET)->AddTransferSyntax()->AddOtherNetworkOptions()->AddMode()->AddOutputDirectory(m_TempDirectory); m_StoreSCPLauncher = new QmitkStoreSCPLauncher(&m_Builder); connect(m_StoreSCPLauncher, SIGNAL(SignalStatusOfStoreSCP(const QString&)), this, SLOT(OnStoreSCPStatusChanged(const QString&))); connect(m_StoreSCPLauncher ,SIGNAL(SignalStartImport(const QStringList&)),m_Controls.internalDataWidget,SLOT(OnStartDicomImport(const QStringList&))); connect(m_StoreSCPLauncher ,SIGNAL(SignalStoreSCPError(const QString&)),m_DicomDirectoryListener,SLOT(OnDicomNetworkError(const QString&)),Qt::DirectConnection); connect(m_StoreSCPLauncher ,SIGNAL(SignalStoreSCPError(const QString&)),this,SLOT(OnDicomNetworkError(const QString&)),Qt::DirectConnection); m_StoreSCPLauncher->StartStoreSCP(); } void QmitkDicomBrowser::OnStoreSCPStatusChanged(const QString& status) { m_Controls.StoreSCPStatusLabel->setText(" "+status); } void QmitkDicomBrowser::OnDicomNetworkError(const QString& status) { m_Controls.StoreSCPStatusLabel->setText(" "+status); } void QmitkDicomBrowser::StopStoreSCP() { delete m_StoreSCPLauncher; } void QmitkDicomBrowser::SetPluginDirectory() { m_PluginDirectory = mitk::PluginActivator::getContext()->getDataFile("").absolutePath(); m_PluginDirectory.append("/database"); } void QmitkDicomBrowser::CreateTemporaryDirectory() { QDir tmp; QString tmpPath = QDir::tempPath(); m_TempDirectory.clear(); m_TempDirectory.append(tmpPath); m_TempDirectory.append(QString("/")); m_TempDirectory.append(TEMP_DICOM_FOLDER_SUFFIX); m_TempDirectory.append(QString(".")); m_TempDirectory.append(QTime::currentTime().toString("hhmmsszzz")); m_TempDirectory.append(QString::number(QCoreApplication::applicationPid())); tmp.mkdir(QDir::toNativeSeparators( m_TempDirectory )); } void QmitkDicomBrowser::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { SetPluginDirectory(); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); m_DatabaseDirectory = prefService->GetSystemPreferences()->Node("/org.mitk.views.dicomreader")->Get("default dicom path", m_PluginDirectory); m_Controls.internalDataWidget->SetDatabaseDirectory(m_DatabaseDirectory); } diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/CMakeLists.txt b/Plugins/org.mitk.gui.qt.dosevisualization/CMakeLists.txt new file mode 100644 index 0000000000..a60f557f37 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_dosevisualization) + +mitk_create_plugin( + EXPORT_DIRECTIVE RTDOSEVISUALIZATION_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgetsExt MitkDicomRT MitkRTUI +) diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/files.cmake b/Plugins/org.mitk.gui.qt.dosevisualization/files.cmake new file mode 100644 index 0000000000..e726795cdc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/files.cmake @@ -0,0 +1,52 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + org_mitk_gui_qt_dosevisualization_Activator.cpp + RTDoseVisualizer.cpp + RTUIPreferencePage.cpp + DoseVisualizationPreferencePage.cpp + mitkDoseVisPreferenceHelper.cpp +) + +set(UI_FILES + src/internal/RTDoseVisualizerControls.ui + src/internal/DoseVisualizationPreferencePageControls.ui + src/internal/RTUIPreferencePageControls.ui +) + +set(MOC_H_FILES + src/internal/org_mitk_gui_qt_dosevisualization_Activator.h + src/internal/RTDoseVisualizer.h + src/internal/RTUIPreferencePage.h + src/internal/DoseVisualizationPreferencePage.h +) + +# list of resource files which can be used by the plug-in +# system without loading the plug-ins shared library, +# for example the icon used in the menu and tabs for the +# plug-in views in the workbench +set(CACHED_RESOURCE_FILES + resources/iso.png + resources/iso2.png + resources/icon4.png + resources/icon5.png + resources/icon7.png + plugin.xml +) + +# list of Qt .qrc files which contain additional resources +# specific to this plugin +set(QRC_FILES + +) + +set(CPP_FILES ) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.dosevisualization/manifest_headers.cmake new file mode 100644 index 0000000000..9492c2783b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "RTDoseVisualization") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ, Software development for Integrated Diagnostic and Therapy") +set(Plugin-ContactAddress "sbr@dkfz-heidelber.de") +set(Require-Plugin org.mitk.gui.qt.common org.commontk.eventadmin) diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/plugin.xml b/Plugins/org.mitk.gui.qt.dosevisualization/plugin.xml new file mode 100644 index 0000000000..26cc3804f3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/plugin.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon4.png b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon4.png new file mode 100644 index 0000000000..07e3d5d412 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon4.png differ diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon5.png b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon5.png new file mode 100644 index 0000000000..a3338ef126 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon5.png differ diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon7.png b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon7.png new file mode 100644 index 0000000000..55f6b4cbf3 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.dosevisualization/resources/icon7.png differ diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso.png b/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso.png new file mode 100644 index 0000000000..7edf418042 Binary files /dev/null and b/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso.png differ diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso2.png b/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso2.png new file mode 100644 index 0000000000..2a73d321db Binary files /dev/null and b/Plugins/org.mitk.gui.qt.dosevisualization/resources/iso2.png differ diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp new file mode 100644 index 0000000000..c0e7e11274 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.cpp @@ -0,0 +1,391 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "DoseVisualizationPreferencePage.h" +#include "mitkRTUIConstants.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "mitkIsoLevelsGenerator.h" + +#include "org_mitk_gui_qt_dosevisualization_Activator.h" + +DoseVisualizationPreferencePage::DoseVisualizationPreferencePage() + : m_MainControl(0), m_Controls(0), m_referenceDoseChanged(false), m_presetMapChanged(false), m_globalVisChanged(false) +{ + +} + +DoseVisualizationPreferencePage::~DoseVisualizationPreferencePage() +{ + delete m_LevelSetModel; + delete m_DoseColorDelegate; + delete m_DoseValueDelegate; + delete m_DoseVisualDelegate; + delete m_Controls; +} + +void DoseVisualizationPreferencePage::Init(berry::IWorkbench::Pointer ) +{ + +} + +void DoseVisualizationPreferencePage::CreateQtControl(QWidget* parent) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + m_DoseVisNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + m_LevelSetModel = new QmitkIsoDoseLevelSetModel(this); + m_DoseColorDelegate = new QmitkDoseColorDelegate(this); + m_DoseValueDelegate = new QmitkDoseValueDelegate(this); + m_DoseVisualDelegate = new QmitkDoseVisualStyleDelegate(this); + + + m_MainControl = new QWidget(parent); + m_Controls = new Ui::DoseVisualizationPreferencePageControls; + m_Controls->setupUi( m_MainControl ); + + + this->m_Controls->isoLevelSetView->setModel(m_LevelSetModel); + this->m_Controls->isoLevelSetView->setItemDelegateForColumn(0,m_DoseColorDelegate); + this->m_Controls->isoLevelSetView->setItemDelegateForColumn(1,m_DoseValueDelegate); + this->m_Controls->isoLevelSetView->setItemDelegateForColumn(2,m_DoseVisualDelegate); + this->m_Controls->isoLevelSetView->setItemDelegateForColumn(3,m_DoseVisualDelegate); + this->m_Controls->isoLevelSetView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(m_Controls->spinReferenceDose, SIGNAL(valueChanged(double)), m_LevelSetModel, SLOT(setReferenceDose(double))); + connect(m_Controls->spinReferenceDose, SIGNAL(valueChanged(double)), this, SLOT(OnReferenceDoseChanged(double))); + connect(m_Controls->checkGlobalSync, SIGNAL(toggled(bool)), m_Controls->spinReferenceDose, SLOT(setEnabled(bool))); + connect(m_Controls->radioAbsDose, SIGNAL(toggled(bool)), m_LevelSetModel, SLOT(setShowAbsoluteDose(bool))); + connect(m_Controls->isoLevelSetView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnShowContextMenuIsoSet(const QPoint&))); + connect(m_Controls->listPresets, SIGNAL(currentItemChanged ( QListWidgetItem *, QListWidgetItem *)), this, SLOT(OnCurrentItemChanged ( QListWidgetItem *, QListWidgetItem *))); + connect(m_Controls->btnAddPreset, SIGNAL(clicked(bool)), this, SLOT(OnAddPresetClicked(bool))); + connect(m_Controls->btnDelPreset, SIGNAL(clicked(bool)), this, SLOT(OnDelPresetClicked(bool))); + connect(m_Controls->btnResetPreset, SIGNAL(clicked(bool)), this, SLOT(OnResetPresetClicked(bool))); + connect(m_Controls->btnDelLevel, SIGNAL(clicked(bool)), this, SLOT(OnDelLevelClicked(bool))); + connect(m_Controls->btnAddLevel, SIGNAL(clicked(bool)), this, SLOT(OnAddLevelClicked(bool))); + connect(m_Controls->checkGlobalVisColorWash, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisChanged(bool))); + connect(m_Controls->checkGlobalVisIsoLine, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisChanged(bool))); + + this->Update(); +} + +QWidget* DoseVisualizationPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +bool DoseVisualizationPreferencePage::PerformOk() +{ + m_DoseVisNode->PutBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(),m_Controls->radioAbsDose->isChecked()); + m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(),m_Controls->checkGlobalVisColorWash->isChecked()); + m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(),m_Controls->checkGlobalVisIsoLine->isChecked()); + m_DoseVisNode->PutDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(),m_Controls->spinReferenceDose->value()); + m_DoseVisNode->PutBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), m_Controls->checkGlobalSync->isChecked()); + + mitk::StorePresetsMap(this->m_Presets); + + if (this->m_Presets.find(this->m_selectedPresetName)==this->m_Presets.end()) + { //the preset currently selected in the application is not available any more. Change it to a valid one. + mitk::SetSelectedPresetName(this->m_Presets.begin()->first); + } + + if (this->m_LevelSetModel->isModified()) + { + this->m_presetMapChanged = true; + } + + if (m_referenceDoseChanged) + { + mitk::SignalReferenceDoseChange(m_Controls->checkGlobalSync->isChecked(), m_Controls->spinReferenceDose->value(), mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); + } + + if (m_presetMapChanged) + { + mitk::SignalPresetMapChange(mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); + } + + if(m_globalVisChanged) + { + mitk::SignalGlobalVisChange(m_Controls->checkGlobalSync->isChecked(), m_Controls->checkGlobalVisIsoLine->isChecked(), m_Controls->checkGlobalVisColorWash->isChecked(), mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()); + } + + return true; +} + +void DoseVisualizationPreferencePage::PerformCancel() +{ +} + +void DoseVisualizationPreferencePage::Update() +{ + m_Controls->checkGlobalVisColorWash->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(), true)); + m_Controls->checkGlobalVisIsoLine->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(), true)); + m_Controls->radioAbsDose->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), true)); + m_Controls->radioRelDose->setChecked(!(m_DoseVisNode->GetBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), false))); + m_Controls->spinReferenceDose->setValue(m_DoseVisNode->GetDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE)); + m_Controls->checkGlobalSync->setChecked(m_DoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), true)); + + m_referenceDoseChanged = false; + m_presetMapChanged = false; + m_globalVisChanged = false; + + + this->m_Presets = mitk::LoadPresetsMap(); + if(m_Presets.empty()) + return; + this->m_selectedPresetName = mitk::GetSelectedPresetName(); + UpdatePresetsWidgets(); +} + + +mitk::IsoDoseLevelSet* DoseVisualizationPreferencePage::GetSelectedIsoLevelSet() +{ + QListWidgetItem* selectedItem = m_Controls->listPresets->currentItem(); + + mitk::IsoDoseLevelSet::Pointer result; + + if (selectedItem) + { + result = m_Presets[selectedItem->text().toStdString()]; + } + + return result; +} + +void DoseVisualizationPreferencePage::UpdateLevelSetWidgets() +{ + this->m_Controls->btnAddLevel->setEnabled(this->GetSelectedIsoLevelSet()!=NULL); + + QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); + this->m_Controls->btnDelLevel->setEnabled(this->GetSelectedIsoLevelSet()!=NULL && selectedIndex.isValid()); +} + +void DoseVisualizationPreferencePage::UpdatePresetsWidgets() +{ + m_Controls->listPresets->clear(); + + QListWidgetItem* selectedItem = NULL; + for (PresetMapType::iterator pos = m_Presets.begin(); pos != m_Presets.end(); ++pos) + { + QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(pos->first)); + if (!selectedItem) + { + selectedItem = item; + } + + m_Controls->listPresets->addItem(item); + } + + if (selectedItem) + { + m_Controls->listPresets->setCurrentItem(selectedItem); + } + + if (this->m_LevelSetModel->isModified()) + { + this->m_presetMapChanged = true; + } + + this->m_LevelSetModel->setIsoDoseLevelSet(this->GetSelectedIsoLevelSet()); + + m_Controls->btnDelPreset->setEnabled((m_Controls->listPresets->currentItem() != NULL) && (m_Controls->listPresets->count()>1)); +} + +void DoseVisualizationPreferencePage::OnCurrentItemChanged ( QListWidgetItem * currentItem, QListWidgetItem * previousItem) +{ + this->m_LevelSetModel->setIsoDoseLevelSet(this->GetSelectedIsoLevelSet()); +} + +void DoseVisualizationPreferencePage::OnShowContextMenuIsoSet(const QPoint& pos) +{ + QPoint globalPos = m_Controls->isoLevelSetView->viewport()->mapToGlobal(pos); + + QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); + + QMenu viewMenu; + QAction* addLevelAct = viewMenu.addAction("Add new level"); + QAction* delLevelAct = viewMenu.addAction("Delete selected level"); + delLevelAct->setEnabled(selectedIndex.isValid()); + viewMenu.addSeparator(); + QAction* invertIsoLineAct = viewMenu.addAction("Invert iso line visibility"); + QAction* activateIsoLineAct = viewMenu.addAction("Activate all iso lines"); + QAction* deactivateIsoLineAct = viewMenu.addAction("Deactivate all iso lines"); + viewMenu.addSeparator(); + QAction* invertColorWashAct = viewMenu.addAction("Invert color wash visibility"); + QAction* activateColorWashAct = viewMenu.addAction("Activate all color wash levels"); + QAction* deactivateColorWashAct = viewMenu.addAction("Deactivate all color wash levels"); + viewMenu.addSeparator(); + QAction* swapAct = viewMenu.addAction("Swap iso line/color wash visibility"); + + QAction* selectedItem = viewMenu.exec(globalPos); + if (selectedItem == invertIsoLineAct) + { + this->m_LevelSetModel->invertVisibilityIsoLines(); + } + else if (selectedItem == activateIsoLineAct) + { + this->m_LevelSetModel->switchVisibilityIsoLines(true); + } + else if (selectedItem == deactivateIsoLineAct) + { + this->m_LevelSetModel->switchVisibilityIsoLines(false); + } + else if (selectedItem == invertColorWashAct) + { + this->m_LevelSetModel->invertVisibilityColorWash(); + } + else if (selectedItem == activateColorWashAct) + { + this->m_LevelSetModel->switchVisibilityColorWash(true); + } + else if (selectedItem == deactivateColorWashAct) + { + this->m_LevelSetModel->switchVisibilityColorWash(false); + } + else if (selectedItem == swapAct) + { + this->m_LevelSetModel->swapVisibility(); + } + else if (selectedItem == addLevelAct) + { + this->m_LevelSetModel->addLevel(); + } + else if (selectedItem == delLevelAct) + { + this->m_LevelSetModel->deleteLevel(selectedIndex); + } +} + +void DoseVisualizationPreferencePage::OnAddPresetClicked(bool checked) +{ + bool done = false; + QString name = tr("new_preset"); + while (!done) + { + bool ok; + name = QInputDialog::getText(m_MainControl, tr("Define name of new preset."), tr("Preset name:"), QLineEdit::Normal, name, &ok); + + if (!ok) + { + return; //cancled by user; + } + + bool uniqueName = m_Presets.find(name.toStdString()) == m_Presets.end(); + if (!uniqueName) + { + QMessageBox box; + box.setText(tr("New preset name is not unique. Please, choose another one.")); + box.exec(); + } + + bool validName = name.indexOf(tr("/")) ==-1; + if (!validName) + { + QMessageBox box; + box.setText(tr("New preset name is not valid. Please don't use \"/\".")); + box.exec(); + } + + done = uniqueName && validName; + } + + mitk::IsoDoseLevelSet::Pointer newSet = mitk::GeneratIsoLevels_Virtuos(); + m_Presets.insert(std::make_pair(name.toStdString(),newSet)); + + m_presetMapChanged = true; + + UpdatePresetsWidgets(); +} + +void DoseVisualizationPreferencePage::OnDelPresetClicked(bool checked) +{ + QListWidgetItem* selectedItem = m_Controls->listPresets->currentItem(); + + if (selectedItem) + { + if (m_Controls->listPresets->count() > 1) + { + m_Presets.erase(selectedItem->text().toStdString()); + + m_presetMapChanged = true; + this->UpdatePresetsWidgets(); + } + } +} + + +void DoseVisualizationPreferencePage::OnResetPresetClicked(bool checked) +{ + QMessageBox box; + box.setText("Do you want to reset the presets?"); + box.setInformativeText("If you reset the presets. All user defined presets will be removed and the default presets will be loaded."); + box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + box.setDefaultButton(QMessageBox::No); + int ret = box.exec(); + + if (ret == QMessageBox::Yes) + { + mitk::IsoDoseLevelSet::Pointer newSet = mitk::GeneratIsoLevels_Virtuos(); + m_Presets.clear(); + m_Presets.insert(std::make_pair("Virtuos",newSet)); + + m_presetMapChanged = true; + + UpdatePresetsWidgets(); + } +} + + +void DoseVisualizationPreferencePage::OnAddLevelClicked(bool checked) +{ + this->m_LevelSetModel->addLevel(); +} + +void DoseVisualizationPreferencePage::OnDelLevelClicked(bool checked) +{ + QModelIndex selectedIndex = m_Controls->isoLevelSetView->currentIndex(); + + if (!selectedIndex.isValid()) + { + selectedIndex = m_Controls->isoLevelSetView->indexAt(QPoint(1,1)); + } + + this->m_LevelSetModel->deleteLevel(selectedIndex); +} + +void DoseVisualizationPreferencePage::OnReferenceDoseChanged(double dose) +{ + this->m_referenceDoseChanged = true; +} + +void DoseVisualizationPreferencePage::OnGlobalVisChanged(bool vis) +{ + this->m_globalVisChanged = true; +} diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.h new file mode 100644 index 0000000000..60489483e8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePage.h @@ -0,0 +1,125 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __DOSE_VISUALIZATION_PREFERENCE_PAGE_H +#define __DOSE_VISUALIZATION_PREFERENCE_PAGE_H + +#include "berryIQtPreferencePage.h" +#include "berryIPreferences.h" + +#include "ui_DoseVisualizationPreferencePageControls.h" + +#include +#include "mitkDoseVisPreferenceHelper.h" + +/*forward declarations*/ +class QmitkIsoDoseLevelSetModel; +class QmitkDoseColorDelegate; +class QmitkDoseValueDelegate; +class QmitkDoseVisualStyleDelegate; + +class QWidget; + +/** +* \class DoseVisualizationPreferencePage +* \brief Preference page for RT Dose visualization +*/ +class DoseVisualizationPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + DoseVisualizationPreferencePage(); + ~DoseVisualizationPreferencePage(); + + /** + * \brief Called by framework to initialize this preference page, but currently does nothing. + * \param workbench The workbench. + */ + void Init(berry::IWorkbench::Pointer workbench); + + /** + * \brief Called by framework to create the GUI, and connect signals and slots. + * \param widget The Qt widget that acts as parent to all GUI components, as this class itself is not derived from QWidget. + */ + void CreateQtControl(QWidget* widget); + + /** + * \brief Required by framework to get hold of the GUI. + * \return QWidget* the top most QWidget for the GUI. + */ + QWidget* GetQtControl() const; + + /** + * \see IPreferencePage::PerformOk + */ + virtual bool PerformOk(); + + /** + * \see IPreferencePage::PerformCancel + */ + virtual void PerformCancel(); + + /** + * \see IPreferencePage::Update + */ + virtual void Update(); + + public slots: + + void OnCurrentItemChanged ( QListWidgetItem * currentItem, QListWidgetItem * previousItem); + void OnShowContextMenuIsoSet(const QPoint& pos); + void OnAddPresetClicked(bool checked); + void OnDelPresetClicked(bool checked); + void OnResetPresetClicked(bool checked); + void OnAddLevelClicked(bool checked); + void OnDelLevelClicked(bool checked); + void OnReferenceDoseChanged(double dose); + void OnGlobalVisChanged(bool vis); + +protected: + + /** Method updates the presets widgets according to the internal members*/ + void UpdatePresetsWidgets(); + /** Method actualizes the level set model and edit buttons according to the currently selected item in the presets list view*/ + void UpdateLevelSetWidgets(); + + /** Method returns the iso dose level set selected in the preset lists. May return NULL if no preset is selected.*/ + mitk::IsoDoseLevelSet* GetSelectedIsoLevelSet(); + + QWidget *m_MainControl; + Ui::DoseVisualizationPreferencePageControls* m_Controls; + + berry::IPreferences::Pointer m_DoseVisNode; + + typedef mitk::PresetMapType PresetMapType; + PresetMapType m_Presets; + std::string m_selectedPresetName; + + bool m_referenceDoseChanged; + bool m_presetMapChanged; + bool m_globalVisChanged; + + QmitkIsoDoseLevelSetModel* m_LevelSetModel; + QmitkDoseColorDelegate* m_DoseColorDelegate; + QmitkDoseValueDelegate* m_DoseValueDelegate; + QmitkDoseVisualStyleDelegate* m_DoseVisualDelegate; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePageControls.ui b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePageControls.ui new file mode 100644 index 0000000000..ffbdbcad21 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/DoseVisualizationPreferencePageControls.ui @@ -0,0 +1,307 @@ + + + DoseVisualizationPreferencePageControls + + + + 0 + 0 + 714 + 651 + + + + + 0 + 0 + + + + QmitkTemplate + + + + 5 + + + 5 + + + + + Global viszualization settings: + + + + + + + 0 + 0 + + + + + 105 + 0 + + + + Qt::NoFocus + + + Reference dose [Gy]: + + + + + + + + 0 + 0 + + + + + 65 + 0 + + + + Dose display: + + + + + + + + + relative [%] + + + true + + + + + + + absolute [Gy] + + + + + + + + + Global visibility: + + + + + + + + + Isolines + + + + :/RTUI/eye_open.png + + + + + 24 + 16 + + + + + + + + Colorwash + + + + :/RTUI/eye_open.png + + + + + 24 + 16 + + + + + + + + + + + + + + + + + + 1 + + + 0.100000000000000 + + + 9999.000000000000000 + + + + + + + global sync + + + + + + + + + + + + Iso dose level presets: + + + + 5 + + + 5 + + + + + + 16777215 + 100 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add + + + + + + + Remove + + + + + + + Reset + + + + + + + + + Preset editor: + + + + + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + 30 + 20 + + + + 75 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add level + + + + + + + Remove level + + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp new file mode 100644 index 0000000000..31d3e5ba12 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.cpp @@ -0,0 +1,698 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// Qt +#include +#include + +// Blueberry +#include +#include + +// MITK +#include + +#include +#include + +// Qmitk +#include "RTDoseVisualizer.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "org_mitk_gui_qt_dosevisualization_Activator.h" + +#include +#include +#include + +#include "QmitkRenderWindow.h" + +#include "vtkDecimatePro.h" + +const std::string RTDoseVisualizer::VIEW_ID = "org.mitk.views.rt.dosevisualization"; + +RTDoseVisualizer::RTDoseVisualizer() +{ + m_selectedNode = NULL; + m_selectedPresetName = ""; + m_internalUpdate = false; + m_PrescribedDose_Data = 0.0; + m_freeIsoValuesCount = 0; +} + +RTDoseVisualizer::~RTDoseVisualizer() +{ + delete m_LevelSetModel; + delete m_DoseColorDelegate; + delete m_DoseValueDelegate; + delete m_DoseVisualDelegate; +} + +void RTDoseVisualizer::SetFocus(){} + +void RTDoseVisualizer::CreateQtPartControl( QWidget *parent ) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi( parent ); + + m_LevelSetModel = new QmitkIsoDoseLevelSetModel(this); + m_LevelSetModel->setVisibilityEditOnly(true); + m_DoseColorDelegate = new QmitkDoseColorDelegate(this); + m_DoseValueDelegate = new QmitkDoseValueDelegate(this); + m_DoseVisualDelegate = new QmitkDoseVisualStyleDelegate(this); + + + this->UpdateByPreferences(); + this->ActualizeIsoLevelsForAllDoseDataNodes(); + this->ActualizeReferenceDoseForAllDoseDataNodes(); + this->ActualizeDisplayStyleForAllDoseDataNodes(); + + this->m_Controls.isoLevelSetView->setModel(m_LevelSetModel); + this->m_Controls.isoLevelSetView->setItemDelegateForColumn(0,m_DoseColorDelegate); + this->m_Controls.isoLevelSetView->setItemDelegateForColumn(1,m_DoseValueDelegate); + this->m_Controls.isoLevelSetView->setItemDelegateForColumn(2,m_DoseVisualDelegate); + this->m_Controls.isoLevelSetView->setItemDelegateForColumn(3,m_DoseVisualDelegate); + this->m_Controls.isoLevelSetView->setContextMenuPolicy(Qt::CustomContextMenu); + + this->m_Controls.btnRemoveFreeValue->setDisabled(true); + + connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), this, SLOT(OnReferenceDoseChanged(double))); + connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), m_LevelSetModel, SLOT(setReferenceDose(double))); + connect(m_Controls.radioAbsDose, SIGNAL(toggled(bool)), m_LevelSetModel, SLOT(setShowAbsoluteDose(bool))); + connect(m_Controls.radioAbsDose, SIGNAL(toggled(bool)), this, SLOT(OnAbsDoseToggled(bool))); + connect(m_Controls.btnAddFreeValue, SIGNAL(clicked()), this, SLOT(OnAddFreeValueClicked())); + connect(m_Controls.btnRemoveFreeValue, SIGNAL(clicked()), this, SLOT(OnRemoveFreeValueClicked())); + connect(m_Controls.checkGlobalVisColorWash, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisColorWashToggled(bool))); + connect(m_Controls.checkGlobalVisIsoLine, SIGNAL(toggled(bool)), this, SLOT(OnGlobalVisIsoLineToggled(bool))); + connect(m_Controls.isoLevelSetView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(OnShowContextMenuIsoSet(const QPoint&))); + connect(m_Controls.comboPresets, SIGNAL(currentIndexChanged ( const QString&)), this, SLOT(OnCurrentPresetChanged(const QString&))); + connect(m_Controls.btnUsePrescribedDose, SIGNAL(clicked()), this, SLOT(OnUsePrescribedDoseClicked())); + connect(m_Controls.isoLevelSetView->model(), SIGNAL( modelReset()), this, SLOT(OnDataChangedInIsoLevelSetView())); + + ctkServiceReference ref = mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()->getServiceReference(); + + ctkDictionary propsForSlot; + if (ref) + { + ctkEventAdmin* eventAdmin = mitk::org_mitk_gui_qt_dosevisualization_Activator::GetContext()->getService(ref); + + propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_ISO_DOSE_LEVEL_PRESETS_CHANGED.c_str(); + eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventPresetsChanged(ctkEvent)), propsForSlot); + + propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_REFERENCE_DOSE_CHANGED.c_str(); + eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventReferenceDoseChanged(ctkEvent)), propsForSlot); + + propsForSlot[ctkEventConstants::EVENT_TOPIC] = mitk::RTCTKEventConstants::TOPIC_GLOBAL_VISIBILITY_CHANGED.c_str(); + eventAdmin->subscribeSlot(this, SLOT(OnHandleCTKEventGlobalVisChanged(ctkEvent)), propsForSlot); + } + + this->UpdateBySelectedNode(); +} + +void RTDoseVisualizer::OnReferenceDoseChanged(double value) +{ + if (! m_internalUpdate) + { + mitk::DoseValueAbs referenceDose = 0.0; + bool globalSync = mitk::GetReferenceDoseValue(referenceDose); + + if (globalSync) + { + mitk::SetReferenceDoseValue(globalSync, value); + this->ActualizeReferenceDoseForAllDoseDataNodes(); + } + else + { + if (this->m_selectedNode.IsNotNull()) + { + this->m_selectedNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + isoDoseNode->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); + } + } + if (this->m_selectedNode.IsNotNull()) + { + this->UpdateColorWashTransferFunction(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } +} + +void RTDoseVisualizer::OnAddFreeValueClicked() +{ + QColor newColor; + //Use HSV schema of QColor to calculate a different color depending on the + //number of already existing free iso lines. + newColor.setHsv((m_freeIsoValuesCount*85)%360,255,255); + mitk::IsoDoseLevel::ColorType mColor; + mColor[0]=newColor.redF(); + mColor[1]=newColor.greenF(); + mColor[2]=newColor.blueF(); + + mitk::IsoDoseLevelVector::Pointer freeIsoDoseVector; + mitk::IsoDoseLevelVectorProperty::Pointer propIsoVector; + + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + propIsoVector = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); + + freeIsoDoseVector = propIsoVector->GetValue(); + if (freeIsoDoseVector.IsNull()) + mitk::IsoDoseLevelVector::Pointer freeIsoDoseVector = mitk::IsoDoseLevelVector::New(); + + mitk::IsoDoseLevel::Pointer newLevel = mitk::IsoDoseLevel::New(0.5,mColor,true,false); + freeIsoDoseVector->InsertElement(m_freeIsoValuesCount,newLevel); + propIsoVector = mitk::IsoDoseLevelVectorProperty::New(freeIsoDoseVector); + + isoDoseNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(),propIsoVector); + + m_freeIsoValuesCount++; + this->m_Controls.btnRemoveFreeValue->setEnabled(true); + //Update Widget + this->UpdateFreeIsoValues(); + //Update Rendering + this->ActualizeFreeIsoLine(); +} + +void RTDoseVisualizer::OnRemoveFreeValueClicked() +{ + int index = this->m_Controls.listFreeValues->currentRow(); + if (index > m_freeIsoValuesCount || index < 0) + return; + + mitk::IsoDoseLevelVectorProperty::Pointer propfreeIsoVec; + + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + propfreeIsoVec = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); + + mitk::IsoDoseLevelVector::Pointer freeIsoDoseLevelVec = propfreeIsoVec->GetValue(); + if(freeIsoDoseLevelVec->IndexExists(index)) + { + //freeIsoDoseLevelVec->DeleteIndex(index); + freeIsoDoseLevelVec->erase(freeIsoDoseLevelVec->begin()+index); + --m_freeIsoValuesCount; + if(m_freeIsoValuesCount == 0) + this->m_Controls.btnRemoveFreeValue->setEnabled(true); + this->UpdateFreeIsoValues(); + this->ActualizeFreeIsoLine(); + } + +} + +void RTDoseVisualizer::OnUsePrescribedDoseClicked() +{ + m_Controls.spinReferenceDose->setValue(this->m_PrescribedDose_Data); +} + +void RTDoseVisualizer::OnDataChangedInIsoLevelSetView() +{ + //colorwash visibility changed, update the colorwash + this->UpdateColorWashTransferFunction(); + + if(m_selectedNode.IsNotNull()) + { + //Hack: This is a dirty hack to reinit the isodose contour node. Only if the node (or property) has changed the rendering process register the RequestUpdateAll + //Only way to render the isoline by changes without a global reinit + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + isoDoseNode->Modified(); + + // Reinit if visibility of colorwash or isodoselevel changed + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + +void RTDoseVisualizer::OnShowContextMenuIsoSet(const QPoint& pos) +{ + QPoint globalPos = m_Controls.isoLevelSetView->viewport()->mapToGlobal(pos); + + QMenu viewMenu; + QAction* invertIsoLineAct = viewMenu.addAction("Invert iso line visibility"); + QAction* activateIsoLineAct = viewMenu.addAction("Activate all iso lines"); + QAction* deactivateIsoLineAct = viewMenu.addAction("Deactivate all iso lines"); + viewMenu.addSeparator(); + QAction* invertColorWashAct = viewMenu.addAction("Invert color wash visibility"); + QAction* activateColorWashAct = viewMenu.addAction("Activate all color wash levels"); + QAction* deactivateColorWashAct = viewMenu.addAction("Deactivate all color wash levels"); + viewMenu.addSeparator(); + QAction* swapAct = viewMenu.addAction("Swap iso line/color wash visibility"); + // ... + + QAction* selectedItem = viewMenu.exec(globalPos); + if (selectedItem == invertIsoLineAct) + { + this->m_LevelSetModel->invertVisibilityIsoLines(); + } + else if (selectedItem == activateIsoLineAct) + { + this->m_LevelSetModel->switchVisibilityIsoLines(true); + } + else if (selectedItem == deactivateIsoLineAct) + { + this->m_LevelSetModel->switchVisibilityIsoLines(false); + } + else if (selectedItem == invertColorWashAct) + { + this->m_LevelSetModel->invertVisibilityColorWash(); + } + else if (selectedItem == activateColorWashAct) + { + this->m_LevelSetModel->switchVisibilityColorWash(true); + } + else if (selectedItem == deactivateColorWashAct) + { + this->m_LevelSetModel->switchVisibilityColorWash(false); + } + else if (selectedItem == swapAct) + { + this->m_LevelSetModel->swapVisibility(); + } +} + +void RTDoseVisualizer::UpdateFreeIsoValues() +{ + this->m_Controls.listFreeValues->clear(); + + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + mitk::IsoDoseLevelVectorProperty::Pointer propfreeIsoVec; + + propfreeIsoVec = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); + + + mitk::IsoDoseLevelVector::Pointer freeIsoDoseLevelVec = propfreeIsoVec->GetValue(); + + for (mitk::IsoDoseLevelVector::Iterator pos = freeIsoDoseLevelVec->Begin(); pos != freeIsoDoseLevelVec->End(); ++pos) + { + QListWidgetItem* item = new QListWidgetItem; + item->setSizeHint(QSize(0,25)); + QmitkFreeIsoDoseLevelWidget* widget = new QmitkFreeIsoDoseLevelWidget; + + float pref; + m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),pref); + + widget->setIsoDoseLevel(pos.Value()); + widget->setReferenceDose(pref); + connect(m_Controls.spinReferenceDose, SIGNAL(valueChanged(double)), widget, SLOT(setReferenceDose(double))); + connect(widget,SIGNAL(ColorChanged(mitk::IsoDoseLevel*)), this, SLOT(ActualizeFreeIsoLine())); + connect(widget,SIGNAL(ValueChanged(mitk::IsoDoseLevel*,mitk::DoseValueRel)), this, SLOT(ActualizeFreeIsoLine())); + connect(widget,SIGNAL(VisualizationStyleChanged(mitk::IsoDoseLevel*)), this, SLOT(ActualizeFreeIsoLine())); + + this->m_Controls.listFreeValues->addItem(item); + this->m_Controls.listFreeValues->setItemWidget(item,widget); + } +} + +void RTDoseVisualizer::ActualizeFreeIsoLine() +{ + if(m_selectedNode.IsNotNull()) + { + //Hack: This is a dirty hack to reinit the isodose contour node. Only if the node (or property) has changed the rendering process register the RequestUpdateAll + //Only way to render the isoline by changes without a global reinit + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + isoDoseNode->Modified(); + + // Reinit if visibility of colorwash or isodoselevel changed + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} +void RTDoseVisualizer::OnAbsDoseToggled(bool showAbs) +{ + if (! m_internalUpdate) + { + mitk::SetDoseDisplayAbsolute(showAbs); + this->ActualizeDisplayStyleForAllDoseDataNodes(); + } +} + +void RTDoseVisualizer::OnGlobalVisColorWashToggled(bool showColorWash) +{ + if (m_selectedNode.IsNotNull()) + { + m_selectedNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(), showColorWash); + //The rendering mode could be set in the dose mapper: Refactoring! + mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); + if(showColorWash) + renderingMode->SetValue(mitk::RenderingModeProperty::COLORTRANSFERFUNCTION_COLOR); + else + renderingMode->SetValue(mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR); + m_selectedNode->SetProperty("Image Rendering.Mode", renderingMode); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + +void RTDoseVisualizer::OnGlobalVisIsoLineToggled(bool showIsoLines) +{ + if (m_selectedNode.IsNotNull()) + { + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + isoDoseNode->SetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(), showIsoLines); + + //toggle the visibility of the free isolevel sliders + this->m_Controls.listFreeValues->setEnabled(showIsoLines); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } +} + +void RTDoseVisualizer::UpdateColorWashTransferFunction() +{ + //Generating the Colorwash + vtkSmartPointer transferFunction = vtkSmartPointer::New(); + + if(m_selectedNode.IsNotNull()) + { + mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = dynamic_cast(m_selectedNode->GetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str())); + mitk::IsoDoseLevelSet::Pointer isoDoseLevelSet = propIsoSet->GetValue(); + + float referenceDose; + m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),referenceDose); + mitk::TransferFunction::ControlPoints scalarOpacityPoints; + scalarOpacityPoints.push_back( std::make_pair(0, 1 ) ); + //Backgroud + transferFunction->AddHSVPoint(((isoDoseLevelSet->Begin())->GetDoseValue()*referenceDose)-0.001,0,0,0,1.0,1.0); + + for(mitk::IsoDoseLevelSet::ConstIterator itIsoDoseLevel = isoDoseLevelSet->Begin(); itIsoDoseLevel != isoDoseLevelSet->End(); ++itIsoDoseLevel) + { + float *hsv = new float[3]; + //used for transfer rgb to hsv + vtkSmartPointer cCalc = vtkSmartPointer::New(); + + if(itIsoDoseLevel->GetVisibleColorWash()) + { + cCalc->RGBToHSV(itIsoDoseLevel->GetColor()[0],itIsoDoseLevel->GetColor()[1],itIsoDoseLevel->GetColor()[2],&hsv[0],&hsv[1],&hsv[2]); + transferFunction->AddHSVPoint(itIsoDoseLevel->GetDoseValue()*referenceDose,hsv[0],hsv[1],hsv[2],1.0,1.0); + } + else + { + scalarOpacityPoints.push_back( std::make_pair(itIsoDoseLevel->GetDoseValue()*referenceDose, 1 ) ); + } + } + + mitk::TransferFunction::Pointer mitkTransFunc = mitk::TransferFunction::New(); + mitk::TransferFunctionProperty::Pointer mitkTransFuncProp = mitk::TransferFunctionProperty::New(); + mitkTransFunc->SetColorTransferFunction(transferFunction); + mitkTransFunc->SetScalarOpacityPoints(scalarOpacityPoints); + mitkTransFuncProp->SetValue(mitkTransFunc); + m_selectedNode->SetProperty("Image Rendering.Transfer Function", mitkTransFuncProp); + } +} + +void RTDoseVisualizer::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, + const QList& nodes ) +{ + QList dataNodes = this->GetDataManagerSelection(); + + mitk::DataNode* selectedNode = NULL; + + if (!dataNodes.empty()) + { + bool isDoseNode = false; + dataNodes[0]->GetBoolProperty(mitk::RTConstants::DOSE_PROPERTY_NAME.c_str(),isDoseNode); + + if (isDoseNode) + { + selectedNode = dataNodes[0]; + } + } + + if (selectedNode != m_selectedNode.GetPointer()) + { + m_selectedNode = selectedNode; + } + + UpdateBySelectedNode(); +} + +void RTDoseVisualizer::UpdateBySelectedNode() +{ + m_Controls.groupNodeSpecific->setEnabled(m_selectedNode.IsNotNull()); + m_Controls.groupFreeValues->setEnabled(m_selectedNode.IsNotNull()); + m_Controls.checkGlobalVisColorWash->setEnabled(m_selectedNode.IsNotNull()); + m_Controls.checkGlobalVisIsoLine->setEnabled(m_selectedNode.IsNotNull()); + m_Controls.isoLevelSetView->setEnabled(m_selectedNode.IsNotNull()); + + + if(m_selectedNode.IsNull()) + { + m_Controls.NrOfFractions->setText(QString("N/A. No dose selected")); + m_Controls.prescribedDoseSpecific->setText(QString("N/A. No dose selected")); + } + else + { + //dose specific information + int fracCount = 1; + m_selectedNode->GetIntProperty(mitk::RTConstants::DOSE_FRACTION_COUNT_PROPERTY_NAME.c_str(),fracCount); + m_Controls.NrOfFractions->setText(QString::number(fracCount)); + + m_PrescribedDose_Data = 0.0; + + float tmp; + m_selectedNode->GetFloatProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(),tmp); + m_PrescribedDose_Data = (double)tmp; + + m_Controls.prescribedDoseSpecific->setText(QString::number(m_PrescribedDose_Data)); + + //free iso lines + mitk::DataNode::Pointer isoDoseNode = this->GetIsoDoseNode(m_selectedNode); + mitk::IsoDoseLevelVectorProperty::Pointer propIsoVector; + + propIsoVector = dynamic_cast(isoDoseNode->GetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str())); + + if (propIsoVector.IsNull()) + { + mitk::IsoDoseLevelVector::Pointer freeIsoValues = mitk::IsoDoseLevelVector::New(); + propIsoVector = mitk::IsoDoseLevelVectorProperty::New(freeIsoValues); + isoDoseNode->SetProperty(mitk::RTConstants::DOSE_FREE_ISO_VALUES_PROPERTY_NAME.c_str(),propIsoVector); + } + + UpdateFreeIsoValues(); + + //global dose issues + //ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring + bool showIsoLine = mitk::GetGlobalIsolineVis(); + isoDoseNode->GetBoolProperty(mitk::RTConstants::DOSE_SHOW_ISOLINES_PROPERTY_NAME.c_str(),showIsoLine); + m_Controls.checkGlobalVisIsoLine->setChecked(showIsoLine); + + bool showColorWash = mitk::GetGlobalColorwashVis(); + m_selectedNode->GetBoolProperty(mitk::RTConstants::DOSE_SHOW_COLORWASH_PROPERTY_NAME.c_str(),showColorWash); + m_Controls.checkGlobalVisColorWash->setChecked(showColorWash); + + float referenceDose = 0.0; + m_selectedNode->GetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(),referenceDose); + m_Controls.spinReferenceDose->setValue(referenceDose); + + mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = + dynamic_cast(m_selectedNode->GetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str())); + + if (propIsoSet) + { + this->m_LevelSetModel->setIsoDoseLevelSet(propIsoSet->GetValue()); + } + } +} + +void RTDoseVisualizer::NodeRemoved(const mitk::DataNode* node) +{ + mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(node); + mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); + + while (iterChildNodes != childNodes->end()) + { + this->GetDataStorage()->Remove((*iterChildNodes)); + ++iterChildNodes; + } +} + +void RTDoseVisualizer::NodeChanged(const mitk::DataNode *node) +{ + bool isdose = false; + if(node->GetBoolProperty(mitk::RTConstants::DOSE_PROPERTY_NAME.c_str(),isdose) && isdose) + { + bool isvisible = true; + if(node->GetBoolProperty("visible", isvisible)) + { + mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(node); + mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); + + while (iterChildNodes != childNodes->end()) + { + (*iterChildNodes)->SetVisibility(isvisible); + ++iterChildNodes; + } + } + } +} + +void RTDoseVisualizer::UpdateByPreferences() +{ + m_Presets = mitk::LoadPresetsMap(); + m_internalUpdate = true; + m_Controls.comboPresets->clear(); + this->m_selectedPresetName = mitk::GetSelectedPresetName(); + + m_Controls.checkGlobalVisIsoLine->setChecked(mitk::GetGlobalIsolineVis()); + m_Controls.checkGlobalVisColorWash->setChecked(mitk::GetGlobalColorwashVis()); + + if(m_Presets.empty()) + return; + + int index = 0; + int selectedIndex = -1; + for (mitk::PresetMapType::const_iterator pos = m_Presets.begin(); pos != m_Presets.end(); ++pos, ++index) + { + m_Controls.comboPresets->addItem(QString(pos->first.c_str())); + if (this->m_selectedPresetName == pos->first) + { + selectedIndex = index; + } + } + + if (selectedIndex == -1) + { + selectedIndex = 0; + MITK_WARN << "Error. Cannot iso dose level preset specified in preferences does not exist. Preset name: "<m_selectedPresetName; + this->m_selectedPresetName = m_Presets.begin()->first; + mitk::SetSelectedPresetName(this->m_selectedPresetName); + MITK_INFO << "Changed selected iso dose level preset to first existing preset. New preset name: "<m_selectedPresetName; + } + + m_Controls.comboPresets->setCurrentIndex(selectedIndex); + + this->m_LevelSetModel->setIsoDoseLevelSet(this->m_Presets[this->m_selectedPresetName]); + + mitk::DoseValueAbs referenceDose = 0.0; + bool globalSync = mitk::GetReferenceDoseValue(referenceDose); + if (globalSync || this->m_selectedNode.IsNull()) + { + m_Controls.spinReferenceDose->setValue(referenceDose); + } + + bool displayAbsoluteDose = mitk::GetDoseDisplayAbsolute(); + m_Controls.radioAbsDose->setChecked(displayAbsoluteDose); + m_Controls.radioRelDose->setChecked(!displayAbsoluteDose); + this->m_LevelSetModel->setShowAbsoluteDose(displayAbsoluteDose); + m_internalUpdate = false; +} + +void RTDoseVisualizer::OnCurrentPresetChanged(const QString& presetName) +{ + if (! m_internalUpdate) + { + mitk::SetSelectedPresetName(presetName.toStdString()); + this->UpdateByPreferences(); + this->ActualizeIsoLevelsForAllDoseDataNodes(); + this->UpdateBySelectedNode(); + } +} + +void RTDoseVisualizer::ActualizeIsoLevelsForAllDoseDataNodes() +{ + std::string presetName = mitk::GetSelectedPresetName(); + + mitk::PresetMapType presetMap = mitk::LoadPresetsMap(); + + mitk::NodePredicateProperty::Pointer isDoseNode = mitk::NodePredicateProperty::New(mitk::RTConstants::DOSE_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(true)); + + mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetSubset(isDoseNode); + + if(presetMap.empty()) + return; + + mitk::IsoDoseLevelSet* selectedPreset = presetMap[presetName]; + + if (!selectedPreset) + { + mitkThrow() << "Error. Cannot actualize iso dose level preset. Selected preset idoes not exist. Preset name: "<begin(); pos != nodes->end(); ++pos) + { + mitk::IsoDoseLevelSet::Pointer clonedPreset = selectedPreset->Clone(); + mitk::IsoDoseLevelSetProperty::Pointer propIsoSet = mitk::IsoDoseLevelSetProperty::New(clonedPreset); + (*pos)->SetProperty(mitk::RTConstants::DOSE_ISO_LEVELS_PROPERTY_NAME.c_str(),propIsoSet); + } +} + +void RTDoseVisualizer::ActualizeReferenceDoseForAllDoseDataNodes() +{ + /** @TODO Klären ob diese präsentations info genauso wie*/ + mitk::DoseValueAbs value = 0; + bool sync = mitk::GetReferenceDoseValue(value); + + if (sync) + { + mitk::NodePredicateProperty::Pointer isDoseNode = mitk::NodePredicateProperty::New(mitk::RTConstants::DOSE_PROPERTY_NAME.c_str(), mitk::BoolProperty::New(true)); + + mitk::DataStorage::SetOfObjects::ConstPointer nodes = this->GetDataStorage()->GetSubset(isDoseNode); + + for(mitk::DataStorage::SetOfObjects::const_iterator pos = nodes->begin(); pos != nodes->end(); ++pos) + { + (*pos)->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); + //ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring + mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(*pos); + mitk::DataStorage::SetOfObjects::const_iterator iterChildNodes = childNodes->begin(); + + while (iterChildNodes != childNodes->end()) + { + (*iterChildNodes)->SetFloatProperty(mitk::RTConstants::REFERENCE_DOSE_PROPERTY_NAME.c_str(), value); + ++iterChildNodes; + } + } + } +} + +void RTDoseVisualizer::ActualizeDisplayStyleForAllDoseDataNodes() +{ + /** @TODO Klären ob diese präsentations info global oder auch per node gespeichert wird*/ +} + +void RTDoseVisualizer::OnHandleCTKEventReferenceDoseChanged(const ctkEvent& event) +{ + mitk::DoseValueAbs referenceDose = 0.0; + bool globalSync = mitk::GetReferenceDoseValue(referenceDose); + + this->m_Controls.spinReferenceDose->setValue(referenceDose); +} + +void RTDoseVisualizer::OnHandleCTKEventGlobalVisChanged(const ctkEvent& event) +{ + this->m_Controls.checkGlobalVisIsoLine->setChecked(mitk::GetGlobalIsolineVis()); + this->m_Controls.checkGlobalVisColorWash->setChecked(mitk::GetGlobalColorwashVis()); +} + +void RTDoseVisualizer::OnHandleCTKEventPresetsChanged(const ctkEvent& event) +{ + std::string currentPresetName = mitk::GetSelectedPresetName(); + + this->OnCurrentPresetChanged(QString::fromStdString(currentPresetName)); +} + +//ATM the IsoDoseContours have an own (helper) node which is a child of dose node; Will be fixed with the doseMapper refactoring +mitk::DataNode::Pointer RTDoseVisualizer::GetIsoDoseNode(mitk::DataNode::Pointer doseNode) +{ + mitk::DataStorage::SetOfObjects::ConstPointer childNodes = this->GetDataStorage()->GetDerivations(doseNode); + return doseNode = (*childNodes->begin()); +} diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h new file mode 100644 index 0000000000..feb2b25bf4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizer.h @@ -0,0 +1,168 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef RTDoseVisualizer_h +#define RTDoseVisualizer_h + +#include + +#include +#include + +#include "ui_RTDoseVisualizerControls.h" + +#include + +#include + +#include "mitkDoseVisPreferenceHelper.h" + +// Shader +#include +#include +#include + +#include +#include + +#include + +#include +#include + +/*forward declarations*/ +class QmitkIsoDoseLevelSetModel; +class QmitkDoseColorDelegate; +class QmitkDoseValueDelegate; +class QmitkDoseVisualStyleDelegate; +class ctkEvent; + +/** +\brief RTDoseVisualizer + +\warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. + +\sa QmitkAbstractView +\ingroup ${plugin_target}_internal +*/ +class RTDoseVisualizer : public QmitkAbstractView +{ + // this is needed for all Qt objects that should have a Qt meta-object + // (everything that derives from QObject and wants to have signal/slots) + Q_OBJECT + +public: + + RTDoseVisualizer(); + virtual ~RTDoseVisualizer(); + static const std::string VIEW_ID; + + void OnSliceChanged(itk::Object *sender, const itk::EventObject &e); + + protected slots: + + void OnAddFreeValueClicked(); + + void OnRemoveFreeValueClicked(); + + void OnUsePrescribedDoseClicked(); + + void OnDataChangedInIsoLevelSetView(); + + void OnAbsDoseToggled(bool); + + void OnGlobalVisColorWashToggled(bool); + + void OnGlobalVisIsoLineToggled(bool); + + void OnShowContextMenuIsoSet(const QPoint&); + + void OnCurrentPresetChanged(const QString&); + + void OnReferenceDoseChanged(double); + + void OnHandleCTKEventReferenceDoseChanged(const ctkEvent& event); + + void OnHandleCTKEventPresetsChanged(const ctkEvent& event); + + void OnHandleCTKEventGlobalVisChanged(const ctkEvent& event); + + void ActualizeFreeIsoLine(); + +protected: + + virtual void CreateQtPartControl(QWidget *parent); + + virtual void SetFocus(); + + /// \brief called by QmitkFunctionality when DataManager's selection has changed + virtual void OnSelectionChanged( berry::IWorkbenchPart::Pointer source, + const QList& nodes ); + + /** Update the transfer funtion property for the color wash*/ + void UpdateColorWashTransferFunction(); + + /** Method updates the list widget according to the current free iso values.*/ + void UpdateFreeIsoValues(); + + /** Update the members according to the currently selected node */ + void UpdateBySelectedNode(); + + /** Update the member widgets according to the information stored in the application preferences*/ + void UpdateByPreferences(); + + /**helper function that iterates throug all data nodes and sets there iso level set property + according to the selected preset. + @TODO: should be moved outside the class, to be available for other classes at well.*/ + void ActualizeIsoLevelsForAllDoseDataNodes(); + + /**helper function that iterates throug all data nodes and sets there reference dose value + according to the preference. + @TODO: should be moved outside the class, to be available for other classes at well.*/ + void ActualizeReferenceDoseForAllDoseDataNodes(); + + /**helper function that iterates through all data nodes and sets there dose display style (relative/absolute) + according to the preference. + @TODO: should be moved outside the class, to be available for other classes at well.*/ + void ActualizeDisplayStyleForAllDoseDataNodes(); + + void NodeRemoved(const mitk::DataNode* node) override; + + void NodeChanged(const mitk::DataNode *node) override; + + Ui::RTDoseVisualizerControls m_Controls; + mitk::DataNode::Pointer m_selectedNode; + unsigned int m_freeIsoValuesCount; + + mitk::PresetMapType m_Presets; + std::string m_selectedPresetName; + + /** Prescribed Dose of the selected data.*/ + mitk::DoseValueAbs m_PrescribedDose_Data; + + QmitkIsoDoseLevelSetModel* m_LevelSetModel; + QmitkDoseColorDelegate* m_DoseColorDelegate; + QmitkDoseValueDelegate* m_DoseValueDelegate; + QmitkDoseVisualStyleDelegate* m_DoseVisualDelegate; + + bool m_internalUpdate; + +private: + mitk::DataNode::Pointer GetIsoDoseNode(mitk::DataNode::Pointer doseNode); +}; + +#endif // RTDoseVisualizer_h diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizerControls.ui b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizerControls.ui new file mode 100644 index 0000000000..c783cb8fb3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTDoseVisualizerControls.ui @@ -0,0 +1,410 @@ + + + RTDoseVisualizerControls + + + + 0 + 0 + 421 + 651 + + + + + 0 + 0 + + + + QmitkTemplate + + + + 5 + + + 5 + + + + + Dose specific information: + + + + 5 + + + 5 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + true + + + 30 Gy + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + + + + + + + Number of fractions: + + + + + + + Prescribed dose [Gy]: + + + + + + + Use as reference dose + + + + + + + true + + + + + + + + + + + + + 0 + 0 + + + + Free iso lines: + + + + 5 + + + 5 + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + 16777215 + 110 + + + + + 0 + 25 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + + + Global iso dose visualization: + + + + 5 + + + 5 + + + + + + + + 0 + 0 + + + + + 65 + 0 + + + + Dose display: + + + + + + + + + + + 0 + 0 + + + + + 65 + 0 + + + + Preset style: + + + + + + + + 0 + 0 + + + + + 105 + 0 + + + + Qt::NoFocus + + + Reference dose [Gy]: + + + + + + + + + + 1 + + + 0.100000000000000 + + + 9999.000000000000000 + + + 0.100000000000000 + + + + + + + + + relative [%] + + + true + + + + + + + absolute [Gy] + + + + + + + + + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + + 30 + 20 + + + + 80 + + + + + + + + + Global visibility: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + true + + + Isolines + + + + :/RTUI/eye_open.png + + + + + 24 + 16 + + + + false + + + + + + + true + + + Colorwash + + + + :/RTUI/eye_open.png + + + + + 24 + 16 + + + + + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.cpp new file mode 100644 index 0000000000..db949200c8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.cpp @@ -0,0 +1,115 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "RTUIPreferencePage.h" + +#include "mitkRTUIConstants.h" + +#include +#include + +//----------------------------------------------------------------------------- +RTUIPreferencePage::RTUIPreferencePage() + : m_MainControl(0), m_Controls(0) +{ + +} + + +//----------------------------------------------------------------------------- +RTUIPreferencePage::~RTUIPreferencePage() +{ + delete m_Controls; +} + + +//----------------------------------------------------------------------------- +void RTUIPreferencePage::Init(berry::IWorkbench::Pointer ) +{ + +} + + +//----------------------------------------------------------------------------- +void RTUIPreferencePage::CreateQtControl(QWidget* parent) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + m_PreferencesNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + m_MainControl = new QWidget(parent); + m_Controls = new Ui::RTUIPreferencePageControls; + m_Controls->setupUi( m_MainControl ); + + connect(m_Controls->radioDefault, SIGNAL(toggled(bool)), m_Controls->spinDefault, SLOT(setEnabled(bool))); + connect(m_Controls->radioRelativeToMax, SIGNAL(toggled(bool)), m_Controls->spinRelativeToMax, SLOT(setEnabled(bool))); + + this->Update(); +} + + +//----------------------------------------------------------------------------- +QWidget* RTUIPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +//----------------------------------------------------------------------------- +bool RTUIPreferencePage::PerformOk() +{ + bool useAsDefaultValue = m_Controls->radioDefault->isChecked(); + m_PreferencesNode->PutBool(mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_AS_DEFAULT_ID.c_str(),useAsDefaultValue); + + if (useAsDefaultValue) + { + m_PreferencesNode->PutDouble(mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE_ID.c_str(), m_Controls->spinDefault->value()); + } + else + { + m_PreferencesNode->PutDouble(mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE_ID.c_str(), m_Controls->spinRelativeToMax->value()/100.0); + } + + return true; +} + + +//----------------------------------------------------------------------------- +void RTUIPreferencePage::PerformCancel() +{ +} + + +//----------------------------------------------------------------------------- +void RTUIPreferencePage::Update() +{ + bool useAsDefaultValue = m_PreferencesNode->GetBool(mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_AS_DEFAULT_ID.c_str(), true); + double doseValue = m_PreferencesNode->GetDouble(mitk::RTUIConstants::UNKNOWN_PRESCRIBED_DOSE_HANDLING_VALUE_ID.c_str(), 50.0); + + m_Controls->radioDefault->setChecked(useAsDefaultValue); + m_Controls->radioRelativeToMax->setChecked(!useAsDefaultValue); + m_Controls->spinDefault->setEnabled(useAsDefaultValue); + m_Controls->spinRelativeToMax->setEnabled(!useAsDefaultValue); + + if (useAsDefaultValue) + { + m_Controls->spinDefault->setValue(doseValue); + } + else + { + m_Controls->spinRelativeToMax->setValue(doseValue*100.0); + } +} diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.h new file mode 100644 index 0000000000..208a41773f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePage.h @@ -0,0 +1,85 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __RT_UI_PREFERENCE_PAGE_H +#define __RT_UI_PREFERENCE_PAGE_H + +#include "berryIQtPreferencePage.h" +#include "berryIPreferences.h" + +#include "ui_RTUIPreferencePageControls.h" + +class QWidget; + +/** +* \class RTUIPreferencePage +* \brief Preference page for general RT visualization settings. +*/ +class RTUIPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + RTUIPreferencePage(); + ~RTUIPreferencePage(); + + /** + * \brief Called by framework to initialize this preference page, but currently does nothing. + * \param workbench The workbench. + */ + void Init(berry::IWorkbench::Pointer workbench); + + /** + * \brief Called by framework to create the GUI, and connect signals and slots. + * \param widget The Qt widget that acts as parent to all GUI components, as this class itself is not derived from QWidget. + */ + void CreateQtControl(QWidget* widget); + + /** + * \brief Required by framework to get hold of the GUI. + * \return QWidget* the top most QWidget for the GUI. + */ + QWidget* GetQtControl() const; + + /** + * \see IPreferencePage::PerformOk + */ + virtual bool PerformOk(); + + /** + * \see IPreferencePage::PerformCancel + */ + virtual void PerformCancel(); + + /** + * \see IPreferencePage::Update + */ + virtual void Update(); + + public slots: + +protected: + + QWidget *m_MainControl; + Ui::RTUIPreferencePageControls* m_Controls; + + berry::IPreferences::Pointer m_PreferencesNode; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePageControls.ui b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePageControls.ui new file mode 100644 index 0000000000..efd18081ca --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/RTUIPreferencePageControls.ui @@ -0,0 +1,86 @@ + + + RTUIPreferencePageControls + + + + 0 + 0 + 403 + 438 + + + + Form + + + + + + Handling of unkown prescribed dose: + + + + + + false + + + % + + + 200.000000000000000 + + + 80.000000000000000 + + + + + + + set to default value: + + + + + + + set relative to max dose: + + + + + + + Gy + + + 9999.000000000000000 + + + 50.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.cpp new file mode 100644 index 0000000000..1c81bd7724 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.cpp @@ -0,0 +1,285 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "mitkDoseVisPreferenceHelper.h" +#include "mitkRTUIConstants.h" +#include "mitkIsoLevelsGenerator.h" + + +#include + +#include + +#include +#include + +void mitk::StorePresetsMap(const PresetMapType& presetMap) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer doseVisNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + +// berry::IPreferences::Pointer presetsNode = doseVisNode->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer presetsNode = doseVisNode->Node("isoPresets"); + presetsNode->RemoveNode(); + doseVisNode->Flush(); + + //new empty preset node +// presetsNode = doseVisNode->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str()); + presetsNode = doseVisNode->Node("isoPresets"); + + //store map in new node + for (PresetMapType::const_iterator pos = presetMap.begin(); pos != presetMap.end(); ++pos) + { + berry::IPreferences::Pointer aPresetNode = presetsNode->Node(pos->first.c_str()); + + unsigned int id = 0; + + for (mitk::IsoDoseLevelSet::ConstIterator levelPos = pos->second->Begin(); levelPos != pos->second->End(); ++levelPos, ++id ) + { + std::ostringstream stream; + stream << id; + + berry::IPreferences::Pointer levelNode = aPresetNode->Node(QString::fromStdString(stream.str())); + + levelNode->PutDouble(mitk::RTUIConstants::ISO_LEVEL_DOSE_VALUE_ID.c_str(),levelPos->GetDoseValue()); + levelNode->PutFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_RED_ID.c_str(),levelPos->GetColor().GetRed()); + levelNode->PutFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_GREEN_ID.c_str(),levelPos->GetColor().GetGreen()); + levelNode->PutFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_BLUE_ID.c_str(),levelPos->GetColor().GetBlue()); + levelNode->PutBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_ISOLINES_ID.c_str(),levelPos->GetVisibleIsoLine()); + levelNode->PutBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_COLORWASH_ID.c_str(),levelPos->GetVisibleColorWash()); + levelNode->Flush(); + } + + aPresetNode->Flush(); + } + + presetsNode->Flush(); +} + +bool mitk::GetGlobalIsolineVis() +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer glIsolineVisNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + bool vis = glIsolineVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_ISOLINES_ID.c_str(),false); + + return vis; +} + +bool mitk::GetGlobalColorwashVis() +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer glDoseVisNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + bool vis = glDoseVisNode->GetBool(mitk::RTUIConstants::GLOBAL_VISIBILITY_COLORWASH_ID.c_str(),false); + + return vis; +} + +mitk::PresetMapType mitk::LoadPresetsMap() +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer presetsNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str()); + + typedef QStringList NamesType; + NamesType names = presetsNode->ChildrenNames(); + + PresetMapType presetMap; + + if(!names.empty()){ + for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) + { + berry::IPreferences::Pointer aPresetNode = presetsNode->Node(*pos); + + if (aPresetNode.IsNull()) + { + mitkThrow()<< "Error in preference interface. Cannot find preset node under given name. Name: "<<(*pos).toStdString(); + } + + mitk::IsoDoseLevelSet::Pointer levelSet = mitk::IsoDoseLevelSet::New(); + + NamesType levelNames = aPresetNode->ChildrenNames(); + for (NamesType::const_iterator levelName = levelNames.begin(); levelName != levelNames.end(); ++levelName) + { + berry::IPreferences::Pointer levelNode = aPresetNode->Node(*levelName); + if (aPresetNode.IsNull()) + { + mitkThrow()<< "Error in preference interface. Cannot find level node under given preset name. Name: "<<(*pos).toStdString()<<"; Level id: "<<(*levelName).toStdString(); + } + + mitk::IsoDoseLevel::Pointer isoLevel = mitk::IsoDoseLevel::New(); + + isoLevel->SetDoseValue(levelNode->GetDouble(mitk::RTUIConstants::ISO_LEVEL_DOSE_VALUE_ID.c_str(),0.0)); + mitk::IsoDoseLevel::ColorType color; + color.SetRed(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_RED_ID.c_str(),1.0)); + color.SetGreen(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_GREEN_ID.c_str(),1.0)); + color.SetBlue(levelNode->GetFloat(mitk::RTUIConstants::ISO_LEVEL_COLOR_BLUE_ID.c_str(),1.0)); + isoLevel->SetColor(color); + isoLevel->SetVisibleIsoLine(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_ISOLINES_ID.c_str(),true)); + isoLevel->SetVisibleColorWash(levelNode->GetBool(mitk::RTUIConstants::ISO_LEVEL_VISIBILITY_COLORWASH_ID.c_str(),true)); + + levelSet->SetIsoDoseLevel(isoLevel); + } + + presetMap.insert(std::make_pair((*pos).toStdString(),levelSet)); + } + } + + if (presetMap.size() == 0) + { //if there are no presets use fallback and store it. + presetMap = mitk::GenerateDefaultPresetsMap(); + StorePresetsMap(presetMap); + } + + return presetMap; +} + +mitk::PresetMapType mitk::GenerateDefaultPresetsMap() +{ + mitk::PresetMapType result; + + result.insert(std::make_pair(std::string("Virtuos"), mitk::GeneratIsoLevels_Virtuos())); + return result; +} + +std::string mitk::GetSelectedPresetName() +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + QString result = prefNode->Get(mitk::RTUIConstants::SELECTED_ISO_PRESET_ID.c_str(), ""); + + return result.toStdString(); +} + +void mitk::SetSelectedPresetName(const std::string& presetName) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer presetsNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_ISO_PRESETS_PREFERENCE_NODE_ID.c_str()); + + typedef QStringList NamesType; + typedef std::vector StdNamesType; + NamesType presetNames = presetsNode->ChildrenNames(); + + StdNamesType stdPresetNames; + + for (NamesType::const_iterator pos = presetNames.begin(); pos != presetNames.end(); ++pos) + { + stdPresetNames.push_back((*pos).toStdString()); + } + + StdNamesType::iterator finding = std::find(stdPresetNames.begin(),stdPresetNames.end(),presetName); + + if (finding == stdPresetNames.end()) + { + mitkThrow()<< "Error. Tried to set invalid selected preset name. Preset name does not exist in the defined presets. Preset name: "<Put(mitk::RTUIConstants::SELECTED_ISO_PRESET_ID.c_str(),presetName.c_str()); +} + +bool mitk::GetReferenceDoseValue(mitk::DoseValueAbs& value) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + bool result = prefNode->GetBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), true); + value = prefNode->GetDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), mitk::RTUIConstants::DEFAULT_REFERENCE_DOSE_VALUE); + + return result; +} + +void mitk::SetReferenceDoseValue(bool globalSync, mitk::DoseValueAbs value) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + prefNode->PutBool(mitk::RTUIConstants::GLOBAL_REFERENCE_DOSE_SYNC_ID.c_str(), globalSync); + if (value >= 0) + { + prefNode->PutDouble(mitk::RTUIConstants::REFERENCE_DOSE_ID.c_str(), value); + } +} + + +bool mitk::GetDoseDisplayAbsolute() +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + bool result = prefNode->GetBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), false); + + return result; +} + +void mitk::SetDoseDisplayAbsolute(bool isAbsolute) +{ + berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = prefService->GetSystemPreferences()->Node(mitk::RTUIConstants::ROOT_DOSE_VIS_PREFERENCE_NODE_ID.c_str()); + + prefNode->PutBool(mitk::RTUIConstants::DOSE_DISPLAY_ABSOLUTE_ID.c_str(), isAbsolute); +} + +void mitk::SignalReferenceDoseChange(bool globalSync, mitk::DoseValueAbs value, ctkPluginContext* context) +{ + ctkServiceReference ref = context->getServiceReference(); + if (ref) + { + ctkEventAdmin* eventAdmin = context->getService(ref); + ctkProperties props; + props["value"] = value; + props["globalSync"] = globalSync; + ctkEvent presetMapChangedEvent(mitk::RTCTKEventConstants::TOPIC_REFERENCE_DOSE_CHANGED.c_str()); + eventAdmin->sendEvent(presetMapChangedEvent); + } +} + +void mitk::SignalGlobalVisChange(bool globalSync, bool isolineVis, bool colorwashVis, ctkPluginContext *context) +{ + ctkServiceReference ref = context->getServiceReference(); + if (ref) + { + ctkEventAdmin* eventAdmin = context->getService(ref); + ctkProperties props; + props["globalIsolineVis"] = isolineVis; + props["globalColorwashVis"] = colorwashVis; + props["globalSync"] = globalSync; + ctkEvent presetMapChangedEvent(mitk::RTCTKEventConstants::TOPIC_GLOBAL_VISIBILITY_CHANGED.c_str()); + eventAdmin->sendEvent(presetMapChangedEvent); + } +} + +void mitk::SignalPresetMapChange(ctkPluginContext* context) +{ + ctkServiceReference ref = context->getServiceReference(); + if (ref) + { + ctkEventAdmin* eventAdmin = context->getService(ref); + ctkEvent presetMapChangedEvent(mitk::RTCTKEventConstants::TOPIC_ISO_DOSE_LEVEL_PRESETS_CHANGED.c_str()); + eventAdmin->sendEvent(presetMapChangedEvent); + } +} diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.h new file mode 100644 index 0000000000..a5416bdb44 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/mitkDoseVisPreferenceHelper.h @@ -0,0 +1,74 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef __DOSE_VIS_PREFERENCE_HELPER_H +#define __DOSE_VIS_PREFERENCE_HELPER_H + +#include +#include + +#include "mitkIsoDoseLevelCollections.h" + +class ctkPluginContext; + +namespace mitk +{ + typedef std::map PresetMapType; + + /** Stores the given preset map in the application preferences. */ + void StorePresetsMap(const PresetMapType& presetMap); + + /** Loads all defined iso dose level presets from the preferences and stores them + in a map. Key is the name of the preset. + @remark If no presets are stored in the preferences this function will generate default presets + (using GenerateDefaultPresetsMap()) and the stores it in the preferences (to guarantee a consistent state) + before passing the default presets back.*/ + PresetMapType LoadPresetsMap(); + + /** Generate the default presets map.*/ + PresetMapType GenerateDefaultPresetsMap(); + + /**Retrieves the name of the preset, that is currently selected for the application, from the preferences.*/ + std::string GetSelectedPresetName(); + + /** checks if the passed name exists in the preset map. If not an exception is thrown. If it exists, the new + * value will be set.*/ + void SetSelectedPresetName(const std::string& presetName); + + /** retrieves the reference dose from the preferences and indicates if global sync for reference dose is activated + or not. + @param value The reference dose value stored in the preferences. + @return Indicator for global sync. True: global sync activated -> preference value is relevant. + False: global sync deactivated. Value is irrelevant. Each node has its own value.*/ + bool GetReferenceDoseValue(DoseValueAbs& value); + /** Sets the global sync setting and dose reference value in the preferences. + * @param globalSync Indicator if global sync should be set active (true) or inactive (false). If it is true, the value is irrelevant (but will be set). + * @param value The dose reference value that should be stored in the preferences.If set to <0 it will be ignored and not changed/set.*/ + void SetReferenceDoseValue(bool globalSync, DoseValueAbs value = -1); + + bool GetDoseDisplayAbsolute(); + void SetDoseDisplayAbsolute(bool isAbsolute); + + bool GetGlobalIsolineVis(); + bool GetGlobalColorwashVis(); + + void SignalReferenceDoseChange(bool globalSync, mitk::DoseValueAbs value, ctkPluginContext* context); + void SignalPresetMapChange(ctkPluginContext* context); + void SignalGlobalVisChange(bool globalSync, bool isolineVis, bool colorwashVis, ctkPluginContext* context); +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.cpp b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.cpp new file mode 100644 index 0000000000..cb3204e95d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.cpp @@ -0,0 +1,55 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "org_mitk_gui_qt_dosevisualization_Activator.h" + +#include + +#include "RTDoseVisualizer.h" +#include "RTUIPreferencePage.h" +#include "DoseVisualizationPreferencePage.h" + +namespace mitk { + + ctkPluginContext* org_mitk_gui_qt_dosevisualization_Activator::m_Context = 0; + + void org_mitk_gui_qt_dosevisualization_Activator::start(ctkPluginContext* context) + { + BERRY_REGISTER_EXTENSION_CLASS(RTDoseVisualizer, context); + BERRY_REGISTER_EXTENSION_CLASS(RTUIPreferencePage, context) + BERRY_REGISTER_EXTENSION_CLASS(DoseVisualizationPreferencePage, context) + + m_Context = context; + } + + void org_mitk_gui_qt_dosevisualization_Activator::stop(ctkPluginContext* context) + { + Q_UNUSED(context); + + m_Context = NULL; + } + + ctkPluginContext* org_mitk_gui_qt_dosevisualization_Activator::GetContext() + { + return m_Context; + } + +} + +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) + Q_EXPORT_PLUGIN2(org_mitk_gui_qt_dosevisualization, mitk::org_mitk_gui_qt_dosevisualization_Activator) +#endif diff --git a/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.h b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.h new file mode 100644 index 0000000000..0e6534d731 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.dosevisualization/src/internal/org_mitk_gui_qt_dosevisualization_Activator.h @@ -0,0 +1,49 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#ifndef org_mitk_gui_qt_dosevisualization_Activator_h +#define org_mitk_gui_qt_dosevisualization_Activator_h + +#include + +namespace mitk { + + class org_mitk_gui_qt_dosevisualization_Activator : + public QObject, public ctkPluginActivator + { + Q_OBJECT +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_dosevisualization") +#endif + Q_INTERFACES(ctkPluginActivator) + + public: + + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + + static ctkPluginContext* GetContext(); + + private: + + static ctkPluginContext* m_Context; + + }; // org_mitk_gui_qt_dosevisualization_Activator + +} + +#endif // org_mitk_gui_qt_dosevisualization_Activator_h