diff --git a/Modules/SemanticRelations/files.cmake b/Modules/SemanticRelations/files.cmake index 3fbf24cd98..b5e1bddd7a 100644 --- a/Modules/SemanticRelations/files.cmake +++ b/Modules/SemanticRelations/files.cmake @@ -1,12 +1,14 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkControlPointManager.cpp mitkDICOMHelper.cpp mitkLesionData.cpp mitkLesionManager.cpp mitkNodePredicates.cpp mitkRelationStorage.cpp - mitkSemanticRelations.cpp + mitkSemanticRelationsDataStorageAccess.cpp + mitkSemanticRelationsInference.cpp + mitkSemanticRelationsIntegration.cpp mitkUIDGeneratorBoost.cpp ) diff --git a/Modules/SemanticRelations/include/mitkLesionManager.h b/Modules/SemanticRelations/include/mitkLesionManager.h index f637e7eccd..790382bc0e 100644 --- a/Modules/SemanticRelations/include/mitkLesionManager.h +++ b/Modules/SemanticRelations/include/mitkLesionManager.h @@ -1,80 +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 MITKLESIONMANAGER_H #define MITKLESIONMANAGER_H #include // semantic relations module -#include "mitkSemanticRelations.h" #include "mitkSemanticTypes.h" #include "mitkLesionData.h" // mitk core #include /* * @brief Provides helper functions that are needed to work with lesions. * * These functions help to generate new lesions, check for existing lesions or provide functionality * to find existing lesion class types. */ namespace mitk { typedef std::vector LesionClassVector; /** * @brief Generate a new lesion and lesion class with UIDs and the given string as lesion class type. * * @param lesionClassType The lesion class type as string. Default parameter is "". */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GenerateNewLesion(const std::string& lesionClassType = ""); /** * @brief Generate a new lesion class with UID and the given string as lesion class type. * * @param lesionClassType The lesion class type as string. Default parameter is "". */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClass GenerateNewLesionClass(const std::string& lesionClassType = ""); /** * @brief Find and return a whole lesion including its lesion class given a specific lesion UID. * * @param lesionUID The lesion UID as string. * @param allLesions All currently known lesions of a specific case. * * @return The lesion with its UID and the lesion class. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetLesionByUID(const SemanticTypes::ID& lesionUID, const std::vector& allLesions); /** * @brief Find and return the whole lesion class including its UID given a specific lesion class type. * * @param lesionClassType The lesion class type as string. * @param allLesionClasses All currently known lesion classes of a specific case. * * @return The lesion class with its UID and the class type. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClass FindExistingLesionClass(const std::string& lesionClassType, const std::vector& allLesionClasses); /** * @brief Generate and store additional lesion data such as lesion presence and lesion volume for each control point. * * @param lesionData The lesion data that holds the lesion and will hold the additional lesion data. * @param caseID The current case ID. - * @param semanticRelations An instance of the semantic relations to retrieve the additional data. */ - MITKSEMANTICRELATIONS_EXPORT void GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations); + MITKSEMANTICRELATIONS_EXPORT void GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID); } // namespace mitk #endif // MITKLESIONMANAGER_H diff --git a/Modules/SemanticRelations/include/mitkRelationStorage.h b/Modules/SemanticRelations/include/mitkRelationStorage.h index fc32e13c82..1ba900ea77 100644 --- a/Modules/SemanticRelations/include/mitkRelationStorage.h +++ b/Modules/SemanticRelations/include/mitkRelationStorage.h @@ -1,73 +1,81 @@ /*=================================================================== 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 MITKRELATIONSTORAGE_H #define MITKRELATIONSTORAGE_H +#include + // semantic relations module #include "mitkSemanticTypes.h" namespace mitk { namespace RelationStorage { - SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID); - SemanticTypes::Lesion GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); - - SemanticTypes::IDVector GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID); + SemanticTypes::Lesion GetLesionOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); SemanticTypes::ControlPoint GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); - SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID); - SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID); SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); - SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID); SemanticTypes::IDVector GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID); - std::vector GetAllCaseIDs(); + SemanticTypes::IDVector GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + SemanticTypes::IDVector GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); + SemanticTypes::IDVector GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID); + SemanticTypes::IDVector GetAllSegmentationIDsOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + SemanticTypes::IDVector GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); + + SemanticTypes::ID GetImageIDOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); + + MITKSEMANTICRELATIONS_EXPORT std::vector GetAllCaseIDs(); void AddCase(const SemanticTypes::CaseID& caseID); - void AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageNodeID); - void RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageNodeID); - void AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationNodeID, const SemanticTypes::ID& parentDataNodeID); - void RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationNodeID); + void AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + void RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + void AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::ID& parentID); + void RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); void AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); void OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); void LinkSegmentationToLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::Lesion& lesion); void UnlinkSegmentationFromLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); void RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); void RemoveLesionClass(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& lesionClassID); void AddControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); - void LinkDataToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& dataNodeID, const SemanticTypes::ControlPoint& controlPoint); - void UnlinkDataFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& dataNodeID); + void LinkImageToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::ControlPoint& controlPoint); + void UnlinkImageFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); void RemoveControlPointFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); void AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); - void AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod examinationPeriod); - void RemoveControlPointFromExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod examinationPeriod); - void RemoveExaminationPeriodFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod examinationPeriod); + void AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod); + void RemoveControlPointFromExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod); + void RemoveExaminationPeriodFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); - void AddInformationTypeToImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::InformationType informationType); + void AddInformationTypeToImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::InformationType& informationType); void RemoveInformationTypeFromImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); - void RemoveInformationTypeFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType informationType); + void RemoveInformationTypeFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); } // namespace RelationStorage } // namespace mitk #endif // MITKRELATIONSTORAGE_H diff --git a/Modules/SemanticRelations/include/mitkSemanticRelations.h b/Modules/SemanticRelations/include/mitkSemanticRelations.h deleted file mode 100644 index b4b017be56..0000000000 --- a/Modules/SemanticRelations/include/mitkSemanticRelations.h +++ /dev/null @@ -1,647 +0,0 @@ -/*=================================================================== - -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 MITKSEMANTICRELATIONS_H -#define MITKSEMANTICRELATIONS_H - -#include - -// semantic relations module -#include "mitkDICOMHelper.h" -#include "mitkISemanticRelationsObservable.h" -#include "mitkISemanticRelationsObserver.h" -#include "mitkSemanticTypes.h" - -// mitk core -#include -#include -#include - -namespace mitk -{ - /** - * @brief The API provides functions to query and manipulate image relations and instances, - * that are helpful during follow-up examination, like control-points (time period), - * types of the images or lesions that may be visible on multiple images. - * - * The class is able to generate IDs from given data nodes using DICOM information. - * These IDs are used to identify the corresponding instances of a specific case. - * The case can also be directly identified by the given case ID. - * - * In the BlackSwan context the case is identified with the DICOM PatientID. - * - * In order for most functions to work the case ID has to be defined in the model. If not, - * the functions do nothing. - */ - class MITKSEMANTICRELATIONS_EXPORT SemanticRelations : public ISemanticRelationsObservable - { - public: - - SemanticRelations(DataStorage* dataStorage); - ~SemanticRelations(); - - using DataNodeVector = std::vector ; - - /************************************************************************/ - /* functions to implement the observer pattern */ - /************************************************************************/ - /** - * @brief Adds the given concrete observer to the vector that holds all currently registered observer. - * If the observer is already registered, it will not be added to the observer vector. - * - * @param observer The concrete observer to register. - */ - virtual void AddObserver(ISemanticRelationsObserver* observer) override; - /** - * @brief Removes the given concrete observer from the vector that holds all currently registered observer. - * - * @param observer The concrete observer to unregister. - */ - virtual void RemoveObserver(ISemanticRelationsObserver* observer) override; - - /************************************************************************/ - /* functions to get instances / attributes */ - /************************************************************************/ - /** - * @brief Returns a vector of all lesions that are currently available for the given case. - * The lesions may be marked by a segmentation or may be empty - with no connection to a specific image / segmentation of the case data. - * If no lesions are stored for the current case, an empty vector is returned. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of lesions. - */ - SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief - * - * - */ - SemanticTypes::LesionClassVector GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Returns a vector of all lesions that are valid for the given case, given a specific control point. - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A specific control point which has to be available at a returned (found) lesion: - * Only those lesions are returned for which the image of the associated segmentation is linked to the given control point. - * If the control point instance does not exist, an empty vector is returned. - * @return A vector of control points. - */ - SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Returns a vector of all lesions that are currently available for the current case and are connected to the given image (via a segmentation). - * If no lesions are stored for the current case, an empty vector is returned. If no segmentation nodes are - * connected with the image node, no lesions for the specific image will be found and an empty vector is returned. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * @pre The image node has to have associated segmentation nodes (child nodes) in order to reference a lesion. - * - * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @return A vector of lesions. - */ - SemanticTypes::LesionVector GetAllLesionsInImage(const DataNode* imageNode) const; - /** - * @brief Returns the lesion that is defined by the given segmentation data. - * - * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). - * @pre The segmentation data node has to represent a lesion. If not, the retrieved lesion will be empty, which leads to an exception. - * @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion'). - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. - * @return The represented lesion. - */ - SemanticTypes::Lesion GetRepresentedLesion(const DataNode* segmentationNode) const; - /** - * @brief Check if the given lesion is present on the given data node. - * For this the given data node is checked against the image / segmentation predicate. If the node is a - * segmentation, the represented lesion of the segmentation is simply compared against the member lesion. - * If the node is an image its derived segmentations are retrieved. For each derived segmentation - * the represented lesion is compared against the member lesion. - * - * @pre The given data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given data node is invalid (==nullptr). - * - * @param dataNode The data node identifier is extracted from the given data node. - * The data node or it's derivations are used for a function call to 'GetRepresentedLesion'. - * @return True, if the lesion is present on the given data node; false otherwise. - */ - bool IsLesionPresentOnDataNode(const SemanticTypes::Lesion& lesion, const mitk::DataNode* dataNode) const; - /** - * @brief Check if the given segmentation refers to an existing lesion instance. - * This function can be used before calling 'GetRepresentedLesion' in order to avoid a possible exception. - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. - * @return True, if the segmentation refers to an existing lesion; false otherwise. - */ - bool IsRepresentingALesion(const DataNode* segmentationNode) const; - /** - * @brief Check if the given data node exists in the relation storage. - * The function receives the case- and the node-ID from the DICOM tags of the node itself. - * It uses node predicates to decide if the node is an image or a segmentation node and searches - * through the corresponding relations. - * - * @param dataNode A data node to check. - * @return True, if the data node exists; false otherwise. - */ - bool InstanceExists(const DataNode* dataNode) const; - /** - * @brief Return a vector of all segmentations that are currently available for the given case. - * The segmentations may be connected / not connected to a lesion of the case. - * If no segmentations are stored for the current case, an empty vector is returned. - * - * @pre The data storage member has to be valid (!nullptr). - * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of data nodes representing segmentations. - */ - mitk::SemanticRelations::DataNodeVector GetAllSegmentationsOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Return a vector of all segmentations that define the given lesion. These segmentations don't have to be linked to the same image. - * If the lesion is not referred to by any segmentation, an empty vector is returned. - * - * @pre The data storage member has to be valid (!nullptr). - * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). - * @pre The UID of the lesion has to exist for a lesion instance. - * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. - * @return A vector of data nodes representing segmentations that define the given lesion. - */ - DataNodeVector GetAllSegmentationsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; - /** - * @brief Return a vector of all images that are currently available for the given case. - * - * @pre The data storage member has to be valid (!nullptr). - * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of data nodes representing images. - */ - DataNodeVector GetAllImagesOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Return a vector of all images that are connected to those segmentations that are linked to the given lesion. - * If the lesion is not referred to by any segmentation, an empty vector is returned. - * - * @pre The UID of the lesion has to exist for a lesion instance. - * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. - * @return A vector of data nodes representing images on which the lesions are visible. - */ - DataNodeVector GetAllImagesOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; - /** - * @brief Check if the given lesion instance exists. - * This function can be used before calling 'GetAllSegmentationsOfLesion' in order to avoid a possible exception. - * This function can be used before calling 'AddLesionInstance' in order to avoid a possible exception. - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. - * @return True, if the lesion instance exists; false otherwise. - */ - bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; - /** - * @brief Return a vector of all control points that are valid for the given case. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of control points. - */ - SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Return a vector of all control points that are valid for the given case, given a specific lesion - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion A specific lesion which has to be available at a returned (found) control point: - * Only those control points are returned for which an associated data has a segmentation that references the given lesion. - * If the lesion does not exists, an empty vector is returned. - * @return A vector of control points. - */ - SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; - /** - * @brief Return a vector of all control points that are valid for the given case, given a specific information type. - * - * @param caseID The current case identifier is defined by the given string. - * @param informationType A specific information type which has to be available at a returned (found) control point: - * Only those control points are returned for which an associated data has the given information type. - * If the information type instance does not exists, an empty vector is returned. - * @return A vector of control points. - */ - SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const; - /** - * @brief Return the control point of a data node. - * If the data node is not linked to a control point or the data node refers to a non-existing control point, - * a control point with an empty UID is returned. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * - * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @return The control point of the given data node. - */ - SemanticTypes::ControlPoint GetControlPointOfData(const DataNode* dataNode) const; - /** - * @brief Return a vector of all image nodes that link to the given control point. - * If the control point is not referred to by any data node, an empty vector is returned. - * - * @pre The UID of the control point has to exist for a control point instance. - * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * @return A vector of image nodes that link to the given control point. - */ - DataNodeVector GetAllImagesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Check if the given control point instance exists. - * This function can be used before calling 'GetAllDataOfControlPoint' in order to avoid a possible exception. - * This function can be used before adding, linking and unlinking control points to avoid a possible exception. - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * @return True, if the control point instance exists; false otherwise. - */ - bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Return a vector of all examination periods nodes that are valid for the given case. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of examination periods. - */ - SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Check if the given examination period instance exists. - * This function can be used before calling 'AddExaminationPeriod' in order to avoid a possible exception. - * - * @param caseID The current case identifier is defined by the given string. - * @param examinationPeriod An examination period with a UID that identifies the corresponding examination period instance. - * @return True, if the examination period instance exists; false otherwise. - */ - bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) const; - /** - * @brief Return a vector of all information types that are valid for the given case. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of information types. - */ - SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID) const; - /** - * @brief Return a vector of all information types that are valid for the given case, given a specific control point. - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A specific control point which has to be available at a returned (found) information type: - * Only those information types are returned for which an associated data is linked to the given control point. - * If the control point instance does not exist, an empty vector is returned. - * @return A vector of information types. - */ - SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Return the information type of the given image. - * If the image does not contain any information type, an empty information type is returned. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * - * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @return The information type of the given data node. - */ - SemanticTypes::InformationType GetInformationTypeOfImage(const DataNode* imageNode) const; - /** - * @brief Return a vector of all image nodes that are defined with the given information type. - * - * @pre The information type has to exist for the given case (and is therefore used by at least one data node). - * @throw SemanticRelationException, if the information type is not used by any data node (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param informationType An information type that identifies the corresponding information type instance. - * @return A vector of image nodes that are defined with the given information type. - */ - DataNodeVector GetAllImagesOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const; - /** - * @brief Return a vector of all image nodes that are defined with the given information type and with the given control point. - * - * @pre The UID of the control point has to exist for a control point instance. - * The information type has to exist for the given case (and is therefore used by at least one data node). - * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or - * if the information type is not used by any data node (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * @param informationType An information type that identifies the corresponding information type instance. - * @return A vector of image nodes that are defined with the given information type with the given control point. - */ - DataNodeVector GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const; - /** - * @brief Return a vector of all segmentation nodes that are defined with the given information type and with the given control point. - * The function uses the 'GetAllSpecificImages'-function to retrieve the specific images and then searches for the derived nodes (segmentation child nodes). - * - * @pre The UID of the control point has to exist for a control point instance. - * The information type has to exist for the given case (and is therefore used by at least one data node). - * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or - * if the information type is not used by any data node (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * @param informationType An information type that identifies the corresponding information type instance. - * @return A vector of segmentation nodes that are defined with the given information type with the given control point. - */ - DataNodeVector GetAllSpecificSegmentations(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const; - /** - * @brief Check if the given information type exists. - * This function can be used before calling 'GetAllDataOfInformationType' in order to avoid a possible exception. - * - * @param caseID The current case identifier is defined by the given string. - * @param informationType An information type - * @return True, if the information type exists; false otherwise. - */ - bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const; - /** - * @brief Return a vector of all CaseIDs that are currently available. - * - * @return A vector of CaseIDs as strings. - */ - std::vector GetAllCaseIDs() const; - - /************************************************************************/ - /* functions to add / remove instances / attributes */ - /************************************************************************/ - /** - * @brief Add the given image to the set of already existing images. - * The date is extracted from the DICOM data of the image node and is compared to already existing control points in the semantic relations model. - * The function tries to find a fitting control point or to extend an already existing control point, if the extracted control point is close to - * any other, already existing control point. - * Finally, the image is linked to the correct control point. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * - * @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node. - */ - void AddImage(const DataNode* imageNode); - /** - * @brief Remove the given image from the set of already existing images. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * - * @param imageNode The current case identifier and node identifier is extracted from the given image data node, which contains DICOM information about the case and the node. - */ - void RemoveImage(const DataNode* imageNode); - /** - * @brief Add a newly created lesion to the set of already existing lesions - with no connection to a specific image / segmentation of the case data. - * - * @pre The UID of the lesion must not already exist for a lesion instance. - * @throw SemanticRelationException, it the UID of the lesion already exists for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion The lesion instance to add. - */ - void AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); - /** - * @brief Overwrite an already existing lesion instance (this may be useful to overwrite the lesion with a different lesion class). - * - * @pre The UID of the lesion has to exist for a lesion instance. - * @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion The lesion instance that overwrites an existing lesion. - */ - void OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); - /** - * @brief Add a newly created lesion to the set of already existing lesions. The lesion is added and a reference to - * the lesion is added to the segmentation data. If the segmentation is already linked to a lesion, the - * old linkage is overwritten (this can be checked via 'IsRepresentingALesion'). - * - * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). - * @pre The UID of the lesion must not already exist for a lesion instance. - * @throw SemanticRelationException, if the UID of the lesion already exists for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. The segmentation node has DICOM information from its parent node. - * @param lesion The lesion instance to add and link. - */ - void AddLesionAndLinkSegmentation(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion); - /** - * @brief Remove the given lesion from the set of already existing lesions. - * - * @pre The UID of the lesion has to exist for a lesion instance. - * @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). - * @pre The function needs to assure that no segmentation is still representing (linked to) this lesion. - * @throw SemanticRelationException, if the lesion instance to remove is still linked to by any segmentation (this can be checked via 'GetAllSegmentationsOfLesion'). - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion The lesion instance to remove. - */ - void RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); - /** - * @brief Add a segmentation instance to the set of already existing segmentations - with no connection to a specific lesion. - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. The segmentation node has DICOM information from its parent node. - * @param parentNode The node identifier of the parent node is extracted from the given parent data node. - */ - void AddSegmentation(const DataNode* segmentationNode, const DataNode* parentNode); - /** - * @brief Link the given segmentation instance to an an already existing lesion instance. If the segmentation is already linked to a lesion instance, the - * old linkage is overwritten (this can be checked via 'IsRepresentingALesion'). - * - * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). - * @pre The UID of the lesion has to exist for a lesion instance. - * @throw SemanticRelationException, if the UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. The segmentation node has DICOM information from its parent node. - * @param lesion The lesion instance to link. - */ - void LinkSegmentationToLesion(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion); - /** - * @brief Unlink the given segmentation instance from the linked lesion instance. - * The lesion may stay unlinked to any segmentation. - * - * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. The segmentation node has DICOM information from its parent node. - */ - void UnlinkSegmentationFromLesion(const DataNode* segmentationNode); - /** - * @brief Remove the given segmentation from the set of already existing segmentations. - * - * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). - * - * @param segmentationNode The segmentation identifier is extracted from the given data node. The segmentation node has DICOM information from its parent node. - */ - void RemoveSegmentation(const DataNode* segmentationNode); - /** - * @brief Set the control point for the given data node. - * - * @pre The given data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given data node is invalid (==nullptr). - */ - void SetControlPointOfData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint); - /** - * @brief Add a newly created control point to the set of already existing control points. A reference to the control point is added to the given data. - * This function combines adding a control point and linking it, since a control point with no associated data is not allowed. - * - * @pre The given data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given data node is invalid (==nullptr). - * @pre The UID of the control point must not already exist for a control point instance. - * @throw SemanticRelationException, if the UID of the control point already exists for a control point instance (this can be checked via 'InstanceExists'). - * @pre The given control point must not already be contained in an existing control point interval. - * @throw SemanticRelationException, if the given control point is already contained in an existing control point interval (this can be checked via 'CheckContainingControlPoint'). - * @pre The given control point must contain the date of the given data node (if parameter 'checkConsistence = true'). - * @throw SemanticRelationException, if the given control point does not contain the date of the given data node and 'checkConsistence = true' (this can be checked via 'ControlPointManager::InsideControlPoint'). - * - * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @param controlPoint The control point instance to add. For a newly added control point always has "startDate = endDate". - * @param checkConsistence If true, the function checks, whether the date of the data node actually lies inside the control point to link. - */ - void AddControlPointAndLinkData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence = true); - /** - * @brief Link the given data to an already existing control point. - * - * @pre The given data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given data node is invalid (==nullptr). - * @pre The UID of the control point has to exist for a control point instance. - * @throw SemanticRelationException, if the UID of the control point does not exists for a control point instance (this can be checked via 'InstanceExists'). - * @pre The given control point must contain the date of the given data node (if parameter 'checkConsistence = true'). - * @throw SemanticRelationException, if the given control point does not contain the date of the given data node and 'checkConsistence = true' (this can be checked via 'ControlPointManager::InsideControlPoint'). - * - * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @param controlPoint The control point instance to link. - * @param checkConsistence If true, the function checks, whether the date of the data node actually lies inside the control point to link. - */ - void LinkDataToControlPoint(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence = true); - /** - * @brief Unlink the given image from the linked control point. - * If data is unlinked from a control point, the function needs to check whether the control point is still linked to any other data: - * - if not, the control point instance will be removed (has to be removed since a control point with no associated data is not allowed). - * - if so, the function has to make sure that the control point instance is shortened to its minimum time period (e.g. moving the end point to an earlier date). - * - * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - */ - void UnlinkDataFromControlPoint(const DataNode* dataNode); - /** - * @brief Add an examination period instance to the set of already existing examination periods - with no connection to a specific control point. - * - * @pre The UID of the examination period must not already exist for an examination period instance. - * @throw SemanticRelationException, if the UID of the examination period already exists for a examination period instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param examinationPeriod The examination period to add. - */ - void AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); - /** - * @brief Add a control point to the vector of control point UIDs of an existing examination period. - * - * @pre The UID of the control point has to exist for a control point instance. - * @throw SemanticRelationException, if the UID of the control point does not exists for a control point instance (this can be checked via 'InstanceExists'). - * @pre The UID of the examination period must not already exist for an examination period instance. - * @throw SemanticRelationException, if the UID of the examination period already exists for a examination period instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint The control point instance to add to the examination period. - * @param examinationPeriod The examination period to which the control point should be added. - */ - void AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod); - /** - * @brief Set (and possibly overwrite) the information type of the given image. - * An already associated information type might be removed if is not referenced by any other image: - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * @post If the information type instance did not exist before, it is now added. - * - * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @param informationType An information type that identifies the corresponding information type instance. - */ - void SetInformationType(const DataNode* imageNode, const SemanticTypes::InformationType& informationType); - /** - * @brief Set the information type of the given image. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * @post If the information type instance did not exist before, it is now added. - * - * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - * @param informationType An information type that identifies the corresponding information type instance. - */ - void AddInformationTypeToImage(const DataNode* imageNode, const SemanticTypes::InformationType& informationType); - /** - * @brief Remove the information type of the given image. - * If the information type is removed, the function needs to check whether the information type is referenced by any other image: - * - if not, the information type instance can be removed (has to be removed since an information type with no associated image is not allowed). - * - if so, the information type is just removed from the given image. - * - * @pre The given image data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). - * - * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. - */ - void RemoveInformationTypeFromImage(const DataNode* imageNode); - - private: - - WeakPointer m_DataStorage; - - /** - * @brief A vector that stores the currently registered observer of this observable subject. - */ - static std::vector m_ObserverVector; - /** - * @brief The SemanticRelations, as an example of an observable subject, notifies (updates) the observer with a given case ID. - * The view's caseID was set before in the GUI. The parts of the view that observe changes in the semantic relations are only updated, - * if the given case ID is equal to the observer's current caseID and thus the observer currently shows the semantic information of the given case. - * - * @param caseID The caseID that identifies the currently active patient / case. - */ - virtual void NotifyObserver(const mitk::SemanticTypes::CaseID& caseID) const override; - /** - * @brief Determine if the given control point contains images, which are connected to segmentations that represent the given lesion. - * If the lesion or the control point are not correctly stored, the function returns false. - * - * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * - * @return True, if the given control point contains data that is related to the given lesion; false otherwise. - */ - bool ControlPointContainsLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Determine if the given control point contains images, which refer to the given information type. - * If the information type or the control point are not correctly stored, the function returns false. - * - * @param caseID The current case identifier is defined by the given string. - * @param informationType An information type that identifies the corresponding information type instance. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * - * @return True, if the given control point contains data that is related to the given information type; false otherwise. - */ - bool ControlPointContainsInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ControlPoint& controlPoint) const; - /** - * @brief Remove all control points from the storage that are not referenced by any image anymore. - * This might happen if an image has been removed (and unlinked from the corresponding control point) - * or if the user sets a new control point for an image manually in the GUI. - * - * @param caseID The current case identifier is defined by the given string. - */ - void ClearControlPoints(const SemanticTypes::CaseID& caseID); - }; -} // namespace mitk - -#endif // MITKSEMANTICRELATIONS_H diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h b/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h new file mode 100644 index 0000000000..07b2854aaf --- /dev/null +++ b/Modules/SemanticRelations/include/mitkSemanticRelationsDataStorageAccess.h @@ -0,0 +1,140 @@ +/*=================================================================== + +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 MITKSEMANTICRELATIONSDATASTORAGEACCESS_H +#define MITKSEMANTICRELATIONSDATASTORAGEACCESS_H + +#include + +// semantic relations module +#include "mitkSemanticTypes.h" + +// mitk core +#include +#include + +namespace mitk +{ + /** + * @brief The API provides functions to query and manipulate image relations and instances, + * that are helpful during follow-up examination, like control-points (time period), + * types of the images or lesions that may be visible on multiple images. + * + * The class is able to generate IDs from given data nodes using DICOM information. + * These IDs are used to identify the corresponding instances of a specific case. + * The case can also be directly identified by the given case ID. + * + * In order for most functions to work the case ID has to be used as a parameter. + * If not, these functions do nothing. + */ + class MITKSEMANTICRELATIONS_EXPORT SemanticRelationsDataStorageAccess + { + public: + + using DataNodeVector = std::vector; + + SemanticRelationsDataStorageAccess(DataStorage* dataStorage); + ~SemanticRelationsDataStorageAccess(); + + /************************************************************************/ + /* functions to get instances / attributes */ + /************************************************************************/ + /** + * @brief Return a vector of all segmentations that are currently available for the given case. + * The segmentations may be connected / not connected to a lesion of the case. + * If no segmentations are stored for the current case, an empty vector is returned. + * + * @pre The data storage member has to be valid (!nullptr). + * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of data nodes representing segmentations. + */ + DataNodeVector GetAllSegmentationsOfCase(const SemanticTypes::CaseID& caseID) const; + /** + * @brief Return a vector of all segmentations that define the given lesion. These segmentations don't have to be linked to the same image. + * If the lesion is not referred to by any segmentation, an empty vector is returned. + * + * @pre The data storage member has to be valid (!nullptr). + * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). + * @pre The UID of the lesion has to exist for a lesion instance. + * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @return A vector of data nodes representing segmentations that define the given lesion. + */ + DataNodeVector GetAllSegmentationsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; + /** + * @brief Return a vector of all images that are currently available for the given case. + * + * @pre The data storage member has to be valid (!nullptr). + * @throw SemanticRelationException, if the data storage member is invalid (==nullptr). + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of data nodes representing images. + */ + DataNodeVector GetAllImagesOfCase(const SemanticTypes::CaseID& caseID) const; + /** + * @brief Return a vector of all images that are connected to those segmentations that are linked to the given lesion. + * If the lesion is not referred to by any segmentation, an empty vector is returned. + * + * @pre The UID of the lesion has to exist for a lesion instance. + * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @return A vector of data nodes representing images on which the lesions are visible. + */ + DataNodeVector GetAllImagesOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const; + /** + * @brief Return a vector of all image nodes that are defined with the given information type and with the given control point. + * + * @pre The UID of the control point has to exist for a control point instance. + * The information type has to exist for the given case (and is therefore used by at least one data node). + * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or + * if the information type is not used by any data node (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * @param informationType An information type that identifies the corresponding information type instance. + * @return A vector of image nodes that are defined with the given information type with the given control point. + */ + DataNodeVector GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const; + /** + * @brief Return a vector of all segmentation nodes that are defined with the given information type and with the given control point. + * The function uses the 'GetAllSpecificImages'-function to retrieve the specific images and then searches for the derived nodes (segmentation child nodes). + * + * @pre The UID of the control point has to exist for a control point instance. + * The information type has to exist for the given case (and is therefore used by at least one data node). + * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists') or + * if the information type is not used by any data node (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * @param informationType An information type that identifies the corresponding information type instance. + * @return A vector of segmentation nodes that are defined with the given information type with the given control point. + */ + DataNodeVector GetAllSpecificSegmentations(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const; + + private: + + WeakPointer m_DataStorage; + + }; +} // namespace mitk + +#endif // MITKSEMANTICRELATIONSDATASTORAGEACCESS_H diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h index 857caff09e..1c21322699 100644 --- a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h +++ b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h @@ -1,278 +1,344 @@ /*=================================================================== 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 MITKSEMANTICRELATIONSINFERENCE_H #define MITKSEMANTICRELATIONSINFERENCE_H #include // semantic relations module #include "mitkSemanticTypes.h" // mitk core #include namespace mitk { /** * @brief The API provides functions to query image relations and instances * that are helpful during follow-up examination, like control-points (time period), * types of the images or lesions that may be visible on multiple images. * * The class is able to generate IDs from given data nodes using DICOM information. * These IDs are used to identify the corresponding instances of a specific case. * The case can also be directly identified by the given case ID. * * In order for most functions to work the case ID has to be used as a parameter. * If not, these functions do nothing. */ namespace SemanticRelationsInference { /************************************************************************/ /* functions to get instances / attributes */ /************************************************************************/ /** - * @brief Return a vector of all lesions that are currently available for the given case. - * The lesions may be marked by a segmentation or may be empty - with no connection to a specific image / segmentation of the case data. - * If no lesions are stored for the current case, an empty vector is returned. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of lesions. - */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID); - /** * @brief Return a vector of lesion classes that are currently available for the given case. * * @param caseID The current case identifier is defined by the given string. * @return A vector of lesion classes. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClassVector GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID); /** - * @brief Return the lesion that is defined by the given segmentation data. + * @brief Return the lesion that is defined by the given segmentation. * * @pre The given segmentation data node has to be valid (!nullptr). - * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). + * @throw SemanticRelationException, if the given segmentation is invalid (==nullptr). * @pre The segmentation data node has to represent a lesion. If not, the retrieved lesion will be empty, which leads to an exception. * @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion'). * * @param segmentationNode The segmentation identifier is extracted from the given data node. * @return The represented lesion. */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetRepresentedLesion(const DataNode* segmentationNode); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetLesionOfSegmentation(const DataNode* segmentationNode); /** - * @brief Returns the lesion that is defined by the segmentation identified by the segmentation ID. + * @brief Returns a vector of all lesions that are currently available for the current case and are connected to the given image (via a segmentation). + * If no lesions are stored for the current case, an empty vector is returned. If no segmentations are + * connected with the image node, no lesions for the specific image will be found and an empty vector is returned. * - * @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion'). + * @pre The given image data node has to be valid (!nullptr). + * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). * - * @param caseID The current case identifier is defined by the given string. - * @param segmentationID The segmentation node identifier is defined by the given string. - * @return The represented lesion. + * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. + * @return A vector of lesions. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfImage(const DataNode* imageNode); + /** + * @brief Returns a vector of all lesions that are valid for the given case, given a specific control point. + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A specific control point which has to be available at a returned (found) lesion: + * Only those lesions are returned for which the image of the associated segmentation is linked to the given control point. + * If the control point instance does not exist, an empty vector is returned. + * @return A vector of control points. */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); /** * @brief Check if the given segmentation refers to an existing lesion instance. * This function can be used before calling 'GetRepresentedLesion' in order to avoid a possible exception. * * @param segmentationNode The segmentation identifier is extracted from the given data node. * @return True, if the segmentation refers to an existing lesion; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool IsRepresentingALesion(const DataNode* segmentationNode); /** * @brief Check if the segmentation identified by the given segmentation ID refers to an existing lesion instance. * This function can be used before calling 'GetRepresentedLesion' in order to avoid a possible exception. * * @param caseID The current case identifier is defined by the given string. * @param segmentationID The segmentation node identifier is defined by the given string. * @return True, if the segmentation refers to an existing lesion; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool IsRepresentingALesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); /** + * @brief Check if the given lesion is present on the given data node. + * The function receives the case- and the node-ID from the DICOM tags of the node itself. + * It uses node predicates to decide if the node is an image or a segmentation node. + * + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. + * @param dataNode A data node to check. + * @return True, if the lesion is present on the data node; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresent(const SemanticTypes::Lesion& lesion, const DataNode* dataNode); + /** + * @brief Check if the given lesion is related to the image identified by the given image ID. + * Each lesion is represented by a segmentation which is connected to its parent image. + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. + * @param imageID The image node identifier is defined by the given string. + * @return True, if the lesion is related to image identified by the given image ID; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentOnImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& imageID); + /** * @brief Check if the given lesion is present on the segmentation identified by the given segmentation ID. * * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. * @param segmentationID The segmentation node identifier is defined by the given string. * @return True, if the lesion is present on the segmentation identified by the given segmentation ID; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentOnSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& segmentationID); /** + * @brief Check if the given lesion is present at the given control point. + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * @return True, if the lesion is present at the given control point; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool IsLesionPresentAtControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint); + /** * @brief Check if the given data node exists in the relation storage. * The function receives the case- and the node-ID from the DICOM tags of the node itself. * It uses node predicates to decide if the node is an image or a segmentation node and searches * through the corresponding relations. * * @param dataNode A data node to check. * @return True, if the data node exists; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const DataNode* dataNode); /** * @brief Check if the given lesion instance exists. * This function can be used before calling 'GetAllSegmentationsOfLesion' in order to avoid a possible exception. * This function can be used before calling 'AddLesionInstance' in order to avoid a possible exception. * * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. * @return True, if the lesion instance exists; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); /** + * @brief Return a vector of all image IDs that identify images that are related to the given lesion. + * Each lesion is represented by a segmentation which is connected to its parent image. + * If the lesion is not represented by any segmentation, an empty vector is returned. + * + * @pre The UID of the lesion has to exist for a lesion instance. + * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. + * @return A vector of IDs identifying images that identify images that are related to the given lesion. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); + /** * @brief Return a vector of all segmentation IDs that identify segmentations that define the given lesion. * These segmentations don't have to be linked to the same image. * If the lesion is not referred to by any segmentation, an empty vector is returned. * * @pre The UID of the lesion has to exist for a lesion instance. * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). * * @param caseID The current case identifier is defined by the given string. - * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @param lesion A lesion with a UID that identifies the corresponding lesion instance. * @return A vector of IDs identifying segmentations that define the given lesion. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); /** - * @brief Return a vector of all control points that are valid for the given case. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of control points. - */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID); - /** * @brief Return the control point of a data node. * If the data node is not linked to a control point or the data node refers to a non-existing control point, * a control point with an empty UID is returned. * * @pre The given image data node has to be valid (!nullptr). * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). * * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. * @return The control point of the given data node. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointOfImage(const DataNode* dataNode); /** - * @brief Return the control point of a data node identified by the image ID. - * If the data node is not linked to a control point or the data node refers to a non-existing control point, - * a control point with an empty UID is returned. + * @brief Return a vector of all control points that are valid for the given case, given a specific lesion * - * @param caseID The current case identifier is defined by the given string. - * @param imageID The image node identifier is defined by the given string. - * @return The control point of the image node, defined by the image node ID. + * @param caseID The current case identifier is defined by the given string. + * @param lesion A specific lesion which has to be available at a returned (found) control point: + * Only those control points are returned for which an associated data has a segmentation that references the given lesion. + * If the lesion does not exists, an empty vector is returned. + * @return A vector of control points. */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); /** - * @brief Return a vector of all image IDs that identify images that link to the given control point. - * If the control point is not referred to by any image, an empty vector is returned. + * @brief Return a vector of all control points that are valid for the given case, given a specific information type. * - * @pre The UID of the control point has to exist for a control point instance. - * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists'). - * - * @param caseID The current case identifier is defined by the given string. - * @param controlPoint A control point with a UID that identifies the corresponding control point instance. - * @return A vector of IDs identifying images that link to the given control point. + * @param caseID The current case identifier is defined by the given string. + * @param informationType A specific information type which has to be available at a returned (found) control point: + * Only those control points are returned for which an associated data has the given information type. + * If the information type instance does not exists, an empty vector is returned. + * @return A vector of control points. */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); /** * @brief Check if the given control point instance exists. * This function can be used before calling 'GetAllDataOfControlPoint' in order to avoid a possible exception. * This function can be used before adding, linking and unlinking control points to avoid a possible exception. * * @param caseID The current case identifier is defined by the given string. * @param controlPoint A control point with a UID that identifies the corresponding control point instance. * @return True, if the control point instance exists; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); /** * @brief Return a vector of all examination periods nodes that are valid for the given case. * * @param caseID The current case identifier is defined by the given string. * @return A vector of examination periods. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID); /** * @brief Check if the given examination period instance exists. * This function can be used before calling 'AddExaminationPeriod' in order to avoid a possible exception. * * @param caseID The current case identifier is defined by the given string. * @param examinationPeriod An examination period with a UID that identifies the corresponding examination period instance. * @return True, if the examination period instance exists; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); /** - * @brief Return a vector of all information types that are valid for the given case. - * - * @param caseID The current case identifier is defined by the given string. - * @return A vector of information types. - */ - MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID); - /** * @brief Return the information type of the given image. * If the image does not contain any information type, an empty information type is returned. * * @pre The given image data node has to be valid (!nullptr). * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). * * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. * @return The information type of the given data node. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationType GetInformationTypeOfImage(const DataNode* imageNode); /** * @brief Return the information type of the given image. * If the image does not contain any information type, an empty information type is returned. * * @param caseID The current case identifier is defined by the given string. * @param imageID The image node identifier is defined by the given string. * @return The information type of the image node, defined by the image node ID. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); /** + * @brief Return a vector of all information types that are valid for the given case, given a specific control point. + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A specific control point which has to be available at a returned (found) information type: + * Only those information types are returned for which an associated data is linked to the given control point. + * If the control point instance does not exist, an empty vector is returned. + * @return A vector of information types. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + /** * @brief Return a vector of all image IDs that identify images that are of the given information type. * If the information type is not used by any image, an empty vector is returned. * * @pre The information type has to exist. * @throw SemanticRelationException, if the information type does not exist (this can be checked via 'InstanceExists'). * * @param caseID The current case identifier is defined by the given string. * @param informationType An information type. * @return A vector of IDs identifying images that are of the given information type. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); /** * @brief Check if the given information type exists. * This function can be used before calling 'GetAllDataOfInformationType' in order to avoid a possible exception. * * @param caseID The current case identifier is defined by the given string. * @param informationType An information type. * @return True, if the information type exists; false otherwise. */ MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); /** - * @brief Return a vector of all CaseIDs that are currently available. + * @brief Determine if the given information type contains images, which are connected to segmentations that represent the given lesion. + * If the lesion or the information type are not correctly stored, the function returns false. + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @param informationType An information type that identifies the corresponding information type instance. + * + * @return True, if the given information type contains data that is related to the given lesion; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::InformationType& informationType); + /** + * @brief Determine if the given control point contains images, which are connected to segmentations that represent the given lesion. + * If the lesion or the control point are not correctly stored, the function returns false. + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * + * @return True, if the given control point contains data that is related to the given lesion; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint); + /** + * @brief Determine if the given control point contains images, which refer to the given information type. + * If the information type or the control point are not correctly stored, the function returns false. + * + * @param caseID The current case identifier is defined by the given string. + * @param informationType An information type that identifies the corresponding information type instance. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. * - * @return A vector of CaseIDs as strings. + * @return True, if the given control point contains data that is related to the given information type; false otherwise. */ - MITKSEMANTICRELATIONS_EXPORT std::vector GetAllCaseIDs(); + MITKSEMANTICRELATIONS_EXPORT bool SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ControlPoint& controlPoint); /** * @brief Remove all control points from the storage that are not referenced by any image anymore. * This might happen if an image has been removed (and unlinked from the corresponding control point) * or if the user sets a new control point for an image manually in the GUI. * * @param caseID The current case identifier is defined by the given string. */ - void ClearControlPoints(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT void ClearControlPoints(const SemanticTypes::CaseID& caseID); } // namespace SemanticRelationsInference } // namespace mitk #endif // MITKSEMANTICRELATIONSINFERENCE_H diff --git a/Modules/SemanticRelations/src/mitkLesionManager.cpp b/Modules/SemanticRelations/src/mitkLesionManager.cpp index 7764bbe5ba..fc459ad32e 100644 --- a/Modules/SemanticRelations/src/mitkLesionManager.cpp +++ b/Modules/SemanticRelations/src/mitkLesionManager.cpp @@ -1,144 +1,122 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations module #include "mitkLesionManager.h" #include "mitkSemanticRelationException.h" +#include "mitkSemanticRelationsInference.h" +#include "mitkRelationStorage.h" #include "mitkUIDGeneratorBoost.h" -bool GetLesionPresence(const mitk::SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint); - -double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint); +double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint); mitk::SemanticTypes::Lesion mitk::GenerateNewLesion(const std::string& lesionClassType/* = ""*/) { mitk::SemanticTypes::Lesion lesion; lesion.UID = mitk::UIDGeneratorBoost::GenerateUID(); lesion.name = "New lesion"; lesion.lesionClass = mitk::SemanticTypes::LesionClass(); lesion.lesionClass.UID = mitk::UIDGeneratorBoost::GenerateUID(); lesion.lesionClass.classType = lesionClassType; return lesion; } mitk::SemanticTypes::LesionClass mitk::GenerateNewLesionClass(const std::string& lesionClassType/* = ""*/) { mitk::SemanticTypes::LesionClass lesionClass; lesionClass.UID = mitk::UIDGeneratorBoost::GenerateUID(); lesionClass.classType = lesionClassType; return lesionClass; } mitk::SemanticTypes::Lesion mitk::GetLesionByUID(const SemanticTypes::ID& lesionUID, const std::vector& allLesions) { auto lambda = [&lesionUID](const SemanticTypes::Lesion& currentLesion) { return currentLesion.UID == lesionUID; }; const auto existingLesion = std::find_if(allLesions.begin(), allLesions.end(), lambda); mitk::SemanticTypes::Lesion lesion; if (existingLesion != allLesions.end()) { lesion = *existingLesion; } return lesion; } mitk::SemanticTypes::LesionClass mitk::FindExistingLesionClass(const std::string& lesionClassType, const std::vector& allLesionClasses) { auto lambda = [&lesionClassType](const SemanticTypes::LesionClass& currentLesionClass) { return currentLesionClass.classType == lesionClassType; }; const auto existingLesionClass = std::find_if(allLesionClasses.begin(), allLesionClasses.end(), lambda); mitk::SemanticTypes::LesionClass lesionClass; if (existingLesionClass != allLesionClasses.end()) { lesionClass = *existingLesionClass; } return lesionClass; } -void mitk::GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations) +void mitk::GenerateAdditionalLesionData(LesionData& lesionData, const SemanticTypes::CaseID& caseID) { std::vector lesionPresence; std::vector lesionVolume; SemanticTypes::Lesion lesion = lesionData.GetLesion(); bool presence = false; double volume = 0.0; try { - std::vector controlPoints = semanticRelations->GetAllControlPointsOfCase(caseID); + SemanticTypes::ControlPointVector controlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(caseID); for (const auto& controlPoint : controlPoints) { - presence = GetLesionPresence(caseID, semanticRelations, lesion, controlPoint); + presence = mitk::SemanticRelationsInference::IsLesionPresentAtControlPoint(caseID, lesion, controlPoint); lesionPresence.push_back(presence); - volume = GetLesionVolume(caseID, semanticRelations, lesion, controlPoint); + volume = GetLesionVolume(caseID, lesion, controlPoint); lesionVolume.push_back(volume); } } catch (const mitk::SemanticRelationException&) { return; } lesionData.SetLesionPresence(lesionPresence); lesionData.SetLesionVolume(lesionVolume); } -bool GetLesionPresence(const mitk::SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controllPoint) -{ - try - { - mitk::SemanticRelations::DataNodeVector allImagesOfLesion = semanticRelations->GetAllImagesOfLesion(caseID, lesion); - for (const auto& image : allImagesOfLesion) - { - auto imageControlPoint = semanticRelations->GetControlPointOfData(image); - if (imageControlPoint.date == controllPoint.date) - { - return true; - } - } - } - catch (const mitk::SemanticRelationException&) - { - return false; - } - - return false; -} - -double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, std::shared_ptr semanticRelations, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint) +double GetLesionVolume(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::Lesion& lesion, const mitk::SemanticTypes::ControlPoint& controlPoint) { - bool presence = GetLesionPresence(caseID, semanticRelations, lesion, controlPoint); + bool presence = mitk::SemanticRelationsInference::IsLesionPresentAtControlPoint(caseID, lesion, controlPoint); if (presence) { return 1.0; } else { return 0.0; } } diff --git a/Modules/SemanticRelations/src/mitkRelationStorage.cpp b/Modules/SemanticRelations/src/mitkRelationStorage.cpp index 2a4327543a..3a9dd560e1 100644 --- a/Modules/SemanticRelations/src/mitkRelationStorage.cpp +++ b/Modules/SemanticRelations/src/mitkRelationStorage.cpp @@ -1,1294 +1,1498 @@ /*=================================================================== 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 "mitkRelationStorage.h" // semantic relations module #include "mitkDICOMHelper.h" // multi label module #include // mitk core #include #include // c++ #include #include namespace { mitk::PropertyList::Pointer GetStorageData(const mitk::SemanticTypes::CaseID& caseID) { // access the storage PERSISTENCE_GET_SERVICE_MACRO if (nullptr == persistenceService) { MITK_DEBUG << "Persistence service could not be loaded"; return nullptr; } // the property list is valid for a whole case and contains all the properties for the current case // the persistence service may create a new property list with the given ID, if no property list is found return persistenceService->GetPropertyList(const_cast(caseID)); } mitk::SemanticTypes::Lesion GenerateLesion(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::ID& lesionID) { mitk::PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return mitk::SemanticTypes::Lesion(); } mitk::VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesionID)); if (nullptr == lesionDataProperty) { MITK_DEBUG << "Lesion " << lesionID << " not found. Lesion can not be retrieved."; return mitk::SemanticTypes::Lesion(); } std::vector lesionData = lesionDataProperty->GetValue(); // a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class) if (lesionData.size() != 2) { MITK_DEBUG << "Incorrect lesion data storage. Not two (2) strings of the lesion name and the lesion UID are stored."; return mitk::SemanticTypes::Lesion(); } // the lesion class ID is stored as the second property std::string lesionClassID = lesionData[1]; mitk::StringProperty* lesionClassProperty = dynamic_cast(propertyList->GetProperty(lesionClassID)); if (nullptr != lesionClassProperty) { mitk::SemanticTypes::LesionClass generatedLesionClass; generatedLesionClass.UID = lesionClassID; generatedLesionClass.classType = lesionClassProperty->GetValue(); mitk::SemanticTypes::Lesion generatedLesion; generatedLesion.UID = lesionID; generatedLesion.name = lesionData[0]; generatedLesion.lesionClass = generatedLesionClass; return generatedLesion; } MITK_DEBUG << "Incorrect lesion class storage. Lesion " << lesionID << " can not be retrieved."; return mitk::SemanticTypes::Lesion(); } mitk::SemanticTypes::ControlPoint GenerateControlpoint(const mitk::SemanticTypes::CaseID& caseID, const mitk::SemanticTypes::ID& controlPointUID) { mitk::PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return mitk::SemanticTypes::ControlPoint(); } // retrieve a vector property that contains the integer values of the date of a control point (0. year 1. month 2. day) mitk::VectorProperty* controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty(controlPointUID)); if (nullptr == controlPointVectorProperty) { MITK_DEBUG << "Could not find the control point " << controlPointUID << " in the storage."; return mitk::SemanticTypes::ControlPoint(); } - std::vector controlPointVectorValue = controlPointVectorProperty->GetValue(); + std::vector controlPointVectorPropertyValue = controlPointVectorProperty->GetValue(); // a control point has to have exactly three integer values (year, month and day) - if (controlPointVectorValue.size() != 3) + if (controlPointVectorPropertyValue.size() != 3) { MITK_DEBUG << "Incorrect control point storage. Not three (3) values of the date are stored."; return mitk::SemanticTypes::ControlPoint(); } // set the values of the control point mitk::SemanticTypes::ControlPoint generatedControlPoint; generatedControlPoint.UID = controlPointUID; - generatedControlPoint.date = boost::gregorian::date(controlPointVectorValue[0], - controlPointVectorValue[1], - controlPointVectorValue[2]); + generatedControlPoint.date = boost::gregorian::date(controlPointVectorPropertyValue[0], + controlPointVectorPropertyValue[1], + controlPointVectorPropertyValue[2]); return generatedControlPoint; } } mitk::SemanticTypes::LesionVector mitk::RelationStorage::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::LesionVector(); } // retrieve a vector property that contains the valid lesion-IDs for the current case - VectorProperty* vectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); - if (nullptr == vectorProperty) + VectorProperty* lesionsVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); + if (nullptr == lesionsVectorProperty) { MITK_DEBUG << "Could not find any lesion in the storage."; return SemanticTypes::LesionVector(); } - std::vector vectorValue = vectorProperty->GetValue(); + std::vector lesionsVectorPropertyValue = lesionsVectorProperty->GetValue(); SemanticTypes::LesionVector allLesionsOfCase; - for (const auto& lesionID : vectorValue) + for (const auto& lesionID : lesionsVectorPropertyValue) { SemanticTypes::Lesion generatedLesion = GenerateLesion(caseID, lesionID); if (!generatedLesion.UID.empty()) { allLesionsOfCase.push_back(generatedLesion); } } return allLesionsOfCase; } -mitk::SemanticTypes::Lesion mitk::RelationStorage::GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) +mitk::SemanticTypes::Lesion mitk::RelationStorage::GetLesionOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::Lesion(); } // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); if (nullptr == segmentationVectorProperty) { - MITK_DEBUG << "Could not find the segmentation node " << segmentationID << " in the storage."; + MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage."; return SemanticTypes::Lesion(); } - std::vector segmentationVectorValue = segmentationVectorProperty->GetValue(); + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); // the lesion ID of a segmentation is the second value in the vector - if (segmentationVectorValue.size() != 2) + if (segmentationVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored."; return SemanticTypes::Lesion(); } - std::string lesionID = segmentationVectorValue[1]; + std::string lesionID = segmentationVectorPropertyValue[1]; if (lesionID.empty()) { // segmentation does not refer to any lesion; return empty lesion return SemanticTypes::Lesion(); } return GenerateLesion(caseID, lesionID); } -mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID) -{ - PropertyList::Pointer propertyList = GetStorageData(caseID); - if (nullptr == propertyList) - { - MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; - return SemanticTypes::IDVector(); - } - // retrieve a vector property that contains the valid segmentation-IDs for the current case - VectorProperty* allSegmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); - if (nullptr == allSegmentationsVectorProperty) - { - MITK_DEBUG << "Could not find any segmentation in the storage."; - return SemanticTypes::IDVector(); - } - - return allSegmentationsVectorProperty->GetValue(); -} - mitk::SemanticTypes::ControlPoint mitk::RelationStorage::GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::ControlPoint(); } // retrieve a vector property that contains the information type and the referenced ID of a control point (0. information type 1. control point ID) - VectorProperty* dataNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); - if (nullptr == dataNodeVectorProperty) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { - MITK_DEBUG << "Could not find the data node " << imageID << " in the storage."; + MITK_DEBUG << "Could not find the image " << imageID << " in the storage."; return SemanticTypes::ControlPoint(); } - std::vector dataNodeVectorValue = dataNodeVectorProperty->GetValue(); + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); SemanticTypes::ControlPoint controlPoint; - // an image node has to have exactly two values (the information type and the ID of the control point) - if (dataNodeVectorValue.size() != 2) + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return SemanticTypes::ControlPoint(); } - // the second value of the data node vector is the ID of the referenced control point - std::string controlPointID = dataNodeVectorValue[1]; + // the second value of the image vector is the ID of the referenced control point + std::string controlPointID = imageVectorPropertyValue[1]; // retrieve a vector property that contains the integer values of the date of a control point (0. year 1. month 2. day) VectorProperty* controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty(controlPointID)); if (nullptr == controlPointVectorProperty) { MITK_DEBUG << "Could not find the control point " << controlPointID << " in the storage."; return SemanticTypes::ControlPoint(); } - std::vector controlPointVectorValue = controlPointVectorProperty->GetValue(); + std::vector controlPointVectorPropertyValue = controlPointVectorProperty->GetValue(); // a control point has to have exactly three integer values (year, month and day) - if (controlPointVectorValue.size() != 3) + if (controlPointVectorPropertyValue.size() != 3) { MITK_DEBUG << "Incorrect control point storage. Not three (3) values of the date are stored."; return SemanticTypes::ControlPoint(); } // set the values of the control point controlPoint.UID = controlPointID; - controlPoint.date = boost::gregorian::date(controlPointVectorValue[0], - controlPointVectorValue[1], - controlPointVectorValue[2]); + controlPoint.date = boost::gregorian::date(controlPointVectorPropertyValue[0], + controlPointVectorPropertyValue[1], + controlPointVectorPropertyValue[2]); return controlPoint; } mitk::SemanticTypes::ControlPointVector mitk::RelationStorage::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::ControlPointVector(); } // retrieve a vector property that contains the valid control point-IDs for the current case - VectorProperty* vectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); - if (nullptr == vectorProperty) + VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); + if (nullptr == controlPointsVectorProperty) { MITK_DEBUG << "Could not find any control points in the storage."; return SemanticTypes::ControlPointVector(); } - std::vector vectorValue = vectorProperty->GetValue(); + std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); SemanticTypes::ControlPointVector allControlPointsOfCase; - for (const auto& controlPointUID : vectorValue) + for (const auto& controlPointUID : controlPointsVectorPropertyValue) { SemanticTypes::ControlPoint generatedControlPoint = GenerateControlpoint(caseID, controlPointUID); if (!generatedControlPoint.UID.empty()) { allControlPointsOfCase.push_back(generatedControlPoint); } } return allControlPointsOfCase; } mitk::SemanticTypes::ExaminationPeriodVector mitk::RelationStorage::GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::ExaminationPeriodVector(); } // retrieve a vector property that contains the valid examination period UIDs for the current case - VectorProperty::Pointer vectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); - if (nullptr == vectorProperty) + VectorProperty::Pointer examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); + if (nullptr == examinationPeriodsVectorProperty) { MITK_DEBUG << "Could not find any examination periods in the storage."; return SemanticTypes::ExaminationPeriodVector(); } - std::vector vectorValue = vectorProperty->GetValue(); + std::vector examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue(); SemanticTypes::ExaminationPeriodVector allExaminationPeriods; - for (const auto& examinationPeriodID : vectorValue) + for (const auto& examinationPeriodID : examinationPeriodsVectorPropertyValue) { // retrieve a vector property that contains the represented control point-IDs VectorProperty::Pointer examinationPeriodVectorProperty = dynamic_cast*>(propertyList->GetProperty(examinationPeriodID)); if (nullptr == examinationPeriodVectorProperty) { MITK_DEBUG << "Could not find the examination period " << examinationPeriodID << " in the storage."; continue; } - std::vector examinationPeriodVectorValue = examinationPeriodVectorProperty->GetValue(); + std::vector examinationPeriodVectorPropertyValue = examinationPeriodVectorProperty->GetValue(); // an examination period has an arbitrary number of vector values (name and control point UIDs) (at least one for the name) - if (examinationPeriodVectorValue.empty()) + if (examinationPeriodVectorPropertyValue.empty()) { MITK_DEBUG << "Incorrect examination period storage. At least one (1) value for the examination period name has to be stored."; continue; } else { // set the values of the name and the control points SemanticTypes::ExaminationPeriod generatedExaminationPeriod; generatedExaminationPeriod.UID = examinationPeriodID; - generatedExaminationPeriod.name = examinationPeriodVectorValue[0]; - for (int i = 1; i < examinationPeriodVectorValue.size(); ++i) + generatedExaminationPeriod.name = examinationPeriodVectorPropertyValue[0]; + for (int i = 1; i < examinationPeriodVectorPropertyValue.size(); ++i) { - generatedExaminationPeriod.controlPointUIDs.push_back(examinationPeriodVectorValue[i]); + generatedExaminationPeriod.controlPointUIDs.push_back(examinationPeriodVectorPropertyValue[i]); } allExaminationPeriods.push_back(generatedExaminationPeriod); } } return allExaminationPeriods; } mitk::SemanticTypes::InformationType mitk::RelationStorage::GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::InformationType(); } - // retrieve a vector property that contains the information type and the referenced ID of an image data node (0. information type 1. control point ID) - VectorProperty* dataNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); - if (nullptr == dataNodeVectorProperty) + // retrieve a vector property that contains the information type and the referenced ID of an image (0. information type 1. control point ID) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { MITK_DEBUG << "Could not find the image " << imageID << " in the storage."; return SemanticTypes::InformationType(); } - std::vector dataNodeVectorValue = dataNodeVectorProperty->GetValue(); - // an image node has to have exactly two values (the information type and the ID of the control point) - if (dataNodeVectorValue.size() != 2) + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return SemanticTypes::InformationType(); } - // the first value of the data node vector is the information type - return dataNodeVectorValue[0]; + // the first value of the image vector is the information type + return imageVectorPropertyValue[0]; } mitk::SemanticTypes::InformationTypeVector mitk::RelationStorage::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return SemanticTypes::InformationTypeVector(); } // retrieve a vector property that contains the valid information types of the current case - VectorProperty* informationTypeVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); - if (nullptr == informationTypeVectorProperty) + VectorProperty* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); + if (nullptr == informationTypesVectorProperty) { MITK_DEBUG << "Could not find any information types in the storage."; return SemanticTypes::InformationTypeVector(); } - return informationTypeVectorProperty->GetValue(); + return informationTypesVectorProperty->GetValue(); } mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; - return SemanticTypes::InformationTypeVector(); + return SemanticTypes::IDVector(); } // retrieve a vector property that contains the valid image-IDs of the current case - VectorProperty* allImagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); - if (nullptr == allImagesVectorProperty) + VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); + if (nullptr == imagesVectorProperty) { MITK_DEBUG << "Could not find any image in the storage."; - return SemanticTypes::InformationTypeVector(); + return SemanticTypes::IDVector(); + } + + return imagesVectorProperty->GetValue(); +} + +mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::IDVector(); + } + // retrieve a vector property that contains the valid image-IDs of the current case + VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); + if (nullptr == imagesVectorProperty) + { + MITK_DEBUG << "Could not find any image in the storage."; + return SemanticTypes::IDVector(); + } + + mitk::SemanticTypes::IDVector allImageIDsOfControlPoint; + std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue(); + for (const auto& imageID : imagesVectorPropertyValue) + { + // retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) + { + continue; + } + + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) + { + continue; + } + + // the second value of the image vector is the ID of the referenced control point + if (imageVectorPropertyValue[1] == controlPoint.UID) + { + allImageIDsOfControlPoint.push_back(imageID); + } + } + + return allImageIDsOfControlPoint; +} + +mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::IDVector(); + } + // retrieve a vector property that contains the valid image-IDs of the current case + VectorProperty* imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); + if (nullptr == imagesVectorProperty) + { + MITK_DEBUG << "Could not find any image in the storage."; + return SemanticTypes::IDVector(); + } + + mitk::SemanticTypes::IDVector allImageIDsOfInformationType; + std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue(); + for (const auto& imageID : imagesVectorPropertyValue) + { + // retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) + { + continue; + } + + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) + { + continue; + } + + // the first value of the image vector is the ID of the referenced information type + if (imageVectorPropertyValue[0] == informationType) + { + allImageIDsOfInformationType.push_back(imageID); + } + } + + return allImageIDsOfInformationType; +} + +mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::IDVector(); + } + // retrieve a vector property that contains the valid segmentation-IDs for the current case + VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); + if (nullptr == segmentationsVectorProperty) + { + MITK_DEBUG << "Could not find any segmentation in the storage."; + return SemanticTypes::IDVector(); + } + + return segmentationsVectorProperty->GetValue(); +} + +mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::IDVector(); + } + // retrieve a vector property that contains the valid segmentation-IDs for the current case + VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); + if (nullptr == segmentationsVectorProperty) + { + MITK_DEBUG << "Could not find any segmentation in the storage."; + return SemanticTypes::IDVector(); + } + + mitk::SemanticTypes::IDVector allSegmentationIDsOfImage; + std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue(); + for (const auto& segmentationID : segmentationsVectorPropertyValue) + { + // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) + VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); + if (nullptr == segmentationVectorProperty) + { + continue; + } + + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); + // a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion) + if (segmentationVectorPropertyValue.size() != 2) + { + continue; + } + + // the first value of the segmentation vector is the ID of the referenced image + if (segmentationVectorPropertyValue[0] == imageID) + { + allSegmentationIDsOfImage.push_back(imageID); + } + } + + return allSegmentationIDsOfImage; +} + +mitk::SemanticTypes::IDVector mitk::RelationStorage::GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::IDVector(); + } + // retrieve a vector property that contains the valid segmentation-IDs for the current case + VectorProperty* segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); + if (nullptr == segmentationsVectorProperty) + { + MITK_DEBUG << "Could not find any segmentation in the storage."; + return SemanticTypes::IDVector(); } - return allImagesVectorProperty->GetValue(); + mitk::SemanticTypes::IDVector allSegmentationIDsOfLesion; + std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue(); + for (const auto& segmentationID : segmentationsVectorPropertyValue) + { + // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) + VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); + if (nullptr == segmentationVectorProperty) + { + continue; + } + + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); + // a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion) + if (segmentationVectorPropertyValue.size() != 2) + { + continue; + } + + // the second value of the segmentation vector is the ID of the referenced lesion + if (segmentationVectorPropertyValue[1] == lesion.UID) + { + allSegmentationIDsOfLesion.push_back(segmentationID); + } + } + + return allSegmentationIDsOfLesion; +} + +mitk::SemanticTypes::ID mitk::RelationStorage::GetImageIDOfSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) +{ + PropertyList::Pointer propertyList = GetStorageData(caseID); + if (nullptr == propertyList) + { + MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; + return SemanticTypes::ID(); + } + + // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) + VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); + if (nullptr == segmentationVectorProperty) + { + MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage."; + return SemanticTypes::ID(); + } + + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); + // the lesion ID of a segmentation is the second value in the vector + if (segmentationVectorPropertyValue.size() != 2) + { + MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored."; + return SemanticTypes::ID(); + } + + return segmentationVectorPropertyValue[0]; } std::vector mitk::RelationStorage::GetAllCaseIDs() { PERSISTENCE_GET_SERVICE_MACRO if (nullptr == persistenceService) { MITK_DEBUG << "Persistence service could not be loaded"; return std::vector(); } // the property list is valid for a certain scenario and contains all the case IDs of the radiological user's MITK session std::string listIdentifier = "caseIDs"; PropertyList::Pointer propertyList = persistenceService->GetPropertyList(listIdentifier); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << listIdentifier << " for the current MITK workbench / session."; return std::vector(); } // retrieve a vector property that contains all case IDs VectorProperty* caseIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(listIdentifier)); if (nullptr == caseIDsVectorProperty) { MITK_DEBUG << "Could not find the property " << listIdentifier << " for the " << listIdentifier << " property list."; return std::vector(); } return caseIDsVectorProperty->GetValue(); } void mitk::RelationStorage::AddCase(const SemanticTypes::CaseID& caseID) { PERSISTENCE_GET_SERVICE_MACRO if (nullptr == persistenceService) { MITK_DEBUG << "Persistence service could not be loaded"; return; } // the property list is valid for a certain scenario and contains all the case IDs of the radiological user's MITK session std::string listIdentifier = "caseIDs"; PropertyList::Pointer propertyList = persistenceService->GetPropertyList(listIdentifier); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << listIdentifier << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains all case IDs VectorProperty::Pointer caseIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(listIdentifier)); - std::vector caseIDsVectorValue; + std::vector caseIDsVectorPropertyValue; if (nullptr == caseIDsVectorProperty) { caseIDsVectorProperty = VectorProperty::New(); } else { - caseIDsVectorValue = caseIDsVectorProperty->GetValue(); + caseIDsVectorPropertyValue = caseIDsVectorProperty->GetValue(); } - auto existingCase = std::find(caseIDsVectorValue.begin(), caseIDsVectorValue.end(), caseID); - if (existingCase != caseIDsVectorValue.end()) + auto existingCase = std::find(caseIDsVectorPropertyValue.begin(), caseIDsVectorPropertyValue.end(), caseID); + if (existingCase != caseIDsVectorPropertyValue.end()) { return; } // add case to the "caseIDs" property list - caseIDsVectorValue.push_back(caseID); - caseIDsVectorProperty->SetValue(caseIDsVectorValue); + caseIDsVectorPropertyValue.push_back(caseID); + caseIDsVectorProperty->SetValue(caseIDsVectorPropertyValue); propertyList->SetProperty(listIdentifier, caseIDsVectorProperty); } -void mitk::RelationStorage::AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageNodeID) +void mitk::RelationStorage::AddImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid image-IDs for the current case - VectorProperty::Pointer allImagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); - std::vector allImagesIDs; - if (nullptr == allImagesVectorProperty) + VectorProperty::Pointer imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); + std::vector imagesVectorPropertyValue; + if (nullptr == imagesVectorProperty) { - allImagesVectorProperty = VectorProperty::New(); + imagesVectorProperty = VectorProperty::New(); } else { - allImagesIDs = allImagesVectorProperty->GetValue(); + imagesVectorPropertyValue = imagesVectorProperty->GetValue(); } - auto existingImage = std::find(allImagesIDs.begin(), allImagesIDs.end(), imageNodeID); - if (existingImage != allImagesIDs.end()) + auto existingImage = std::find(imagesVectorPropertyValue.begin(), imagesVectorPropertyValue.end(), imageID); + if (existingImage != imagesVectorPropertyValue.end()) { return; } // add image to the "images" property list - allImagesIDs.push_back(imageNodeID); - allImagesVectorProperty->SetValue(allImagesIDs); - propertyList->SetProperty("images", allImagesVectorProperty); + imagesVectorPropertyValue.push_back(imageID); + imagesVectorProperty->SetValue(imagesVectorPropertyValue); + propertyList->SetProperty("images", imagesVectorProperty); // add the image itself - VectorProperty::Pointer imageNodeVectorProperty = VectorProperty::New(); - // an image node has to have exactly two values (the information type and the ID of the control point) - std::vector imageNodeVectorValue(2); - imageNodeVectorProperty->SetValue(imageNodeVectorValue); - propertyList->SetProperty(imageNodeID, imageNodeVectorProperty); + VectorProperty::Pointer imageVectorProperty = VectorProperty::New(); + // an image has to have exactly two values (the information type and the ID of the control point) + std::vector imageVectorPropertyValue(2); + imageVectorProperty->SetValue(imageVectorPropertyValue); + propertyList->SetProperty(imageID, imageVectorProperty); } -void mitk::RelationStorage::RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageNodeID) +void mitk::RelationStorage::RemoveImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid image-IDs for the current case - VectorProperty::Pointer allImagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); - if (nullptr == allImagesVectorProperty) + VectorProperty::Pointer imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); + if (nullptr == imagesVectorProperty) { MITK_DEBUG << "Could not find any images in the storage."; return; } // remove the image reference from the list of all images of the current case - std::vector allImagesIDs = allImagesVectorProperty->GetValue(); - allImagesIDs.erase(std::remove(allImagesIDs.begin(), allImagesIDs.end(), imageNodeID), allImagesIDs.end()); - if (allImagesIDs.empty()) + std::vector imagesVectorPropertyValue = imagesVectorProperty->GetValue(); + imagesVectorPropertyValue.erase(std::remove(imagesVectorPropertyValue.begin(), imagesVectorPropertyValue.end(), imageID), imagesVectorPropertyValue.end()); + if (imagesVectorPropertyValue.empty()) { // no more images stored -> remove the images property list propertyList->DeleteProperty("images"); } else { // or store the modified vector value - allImagesVectorProperty->SetValue(allImagesIDs); + imagesVectorProperty->SetValue(imagesVectorPropertyValue); } // remove the image instance itself - propertyList->DeleteProperty(imageNodeID); + propertyList->DeleteProperty(imageID); } -void mitk::RelationStorage::AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationNodeID, const SemanticTypes::ID& parentNodeID) +void mitk::RelationStorage::AddSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::ID& parentID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid segmentation-IDs for the current case - VectorProperty::Pointer allSegmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); - std::vector allSegmentationsIDs; - if (nullptr == allSegmentationsVectorProperty) + VectorProperty::Pointer segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); + std::vector segmentationsVectorPropertyValue; + if (nullptr == segmentationsVectorProperty) { - allSegmentationsVectorProperty = VectorProperty::New(); + segmentationsVectorProperty = VectorProperty::New(); } else { - allSegmentationsIDs = allSegmentationsVectorProperty->GetValue(); + segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue(); } - auto existingImage = std::find(allSegmentationsIDs.begin(), allSegmentationsIDs.end(), segmentationNodeID); - if (existingImage != allSegmentationsIDs.end()) + auto existingImage = std::find(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID); + if (existingImage != segmentationsVectorPropertyValue.end()) { return; } // add segmentation to the "segmentations" property list - allSegmentationsIDs.push_back(segmentationNodeID); - allSegmentationsVectorProperty->SetValue(allSegmentationsIDs); - propertyList->SetProperty("segmentations", allSegmentationsVectorProperty); + segmentationsVectorPropertyValue.push_back(segmentationID); + segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue); + propertyList->SetProperty("segmentations", segmentationsVectorProperty); // add the segmentation itself - VectorProperty::Pointer segmentationNodeVectorProperty = VectorProperty::New(); - // a segmentation node has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion) - std::vector segmentationNodeVectorValue(2); - segmentationNodeVectorValue[0] = parentNodeID; - segmentationNodeVectorProperty->SetValue(segmentationNodeVectorValue); - propertyList->SetProperty(segmentationNodeID, segmentationNodeVectorProperty); + VectorProperty::Pointer segmentationVectorProperty = VectorProperty::New(); + // a segmentation has to have exactly two values (the ID of the referenced image and the ID of the referenced lesion) + std::vector segmentationVectorPropertyValue(2); + segmentationVectorPropertyValue[0] = parentID; + segmentationVectorProperty->SetValue(segmentationVectorPropertyValue); + propertyList->SetProperty(segmentationID, segmentationVectorProperty); } -void mitk::RelationStorage::RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationNodeID) +void mitk::RelationStorage::RemoveSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid segmentation-IDs for the current case - VectorProperty::Pointer allSegmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); - if (nullptr == allSegmentationsVectorProperty) + VectorProperty::Pointer segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); + if (nullptr == segmentationsVectorProperty) { MITK_DEBUG << "Could not find any segmentation in the storage."; return; } // remove the lesion reference from the list of all lesions of the current case - std::vector allSegmentationsIDs = allSegmentationsVectorProperty->GetValue(); - allSegmentationsIDs.erase(std::remove(allSegmentationsIDs.begin(), allSegmentationsIDs.end(), segmentationNodeID), allSegmentationsIDs.end()); - if (allSegmentationsIDs.empty()) + std::vector segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue(); + segmentationsVectorPropertyValue.erase(std::remove(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID), segmentationsVectorPropertyValue.end()); + if (segmentationsVectorPropertyValue.empty()) { // no more segmentations stored -> remove the segmentations property list propertyList->DeleteProperty("segmentations"); } else { // or store the modified vector value - allSegmentationsVectorProperty->SetValue(allSegmentationsIDs); + segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue); } // remove the lesion instance itself - propertyList->DeleteProperty(segmentationNodeID); + propertyList->DeleteProperty(segmentationID); } void mitk::RelationStorage::AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid lesion-IDs for the current case VectorProperty::Pointer lesionsVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); - std::vector lesionsVectorValue; + std::vector lesionsVectorPropertyValue; if (nullptr == lesionsVectorProperty) { lesionsVectorProperty = VectorProperty::New(); } else { - lesionsVectorValue = lesionsVectorProperty->GetValue(); + lesionsVectorPropertyValue = lesionsVectorProperty->GetValue(); } - const auto& existingIndex = std::find(lesionsVectorValue.begin(), lesionsVectorValue.end(), lesion.UID); - if (existingIndex != lesionsVectorValue.end()) + const auto& existingIndex = std::find(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(), lesion.UID); + if (existingIndex != lesionsVectorPropertyValue.end()) { return; } // add the new lesion id from the given lesion to the vector of all current lesion IDs - lesionsVectorValue.push_back(lesion.UID); + lesionsVectorPropertyValue.push_back(lesion.UID); // overwrite the current vector property with the new, extended string vector - lesionsVectorProperty->SetValue(lesionsVectorValue); + lesionsVectorProperty->SetValue(lesionsVectorPropertyValue); propertyList->SetProperty("lesions", lesionsVectorProperty); // add the lesion with the lesion UID as the key and the lesion information as value std::vector lesionData; lesionData.push_back(lesion.name); lesionData.push_back(lesion.lesionClass.UID); VectorProperty::Pointer newLesionVectorProperty = VectorProperty::New(); newLesionVectorProperty->SetValue(lesionData); propertyList->SetProperty(lesion.UID, newLesionVectorProperty); // add the lesion class with the lesion class UID as key and the class type as value std::string lesionClassType = lesion.lesionClass.classType; propertyList->SetStringProperty(lesion.lesionClass.UID.c_str(), lesionClassType.c_str()); } void mitk::RelationStorage::OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid lesion-IDs for the current case VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); if (nullptr == lesionVectorProperty) { MITK_DEBUG << "Could not find any lesion in the storage."; return; } - std::vector lesionVectorValue = lesionVectorProperty->GetValue(); - const auto existingLesion = std::find(lesionVectorValue.begin(), lesionVectorValue.end(), lesion.UID); - if (existingLesion != lesionVectorValue.end()) + std::vector lesionVectorPropertyValue = lesionVectorProperty->GetValue(); + const auto existingLesion = std::find(lesionVectorPropertyValue.begin(), lesionVectorPropertyValue.end(), lesion.UID); + if (existingLesion != lesionVectorPropertyValue.end()) { // overwrite the referenced lesion class UID with the new, given lesion class data std::vector lesionData; lesionData.push_back(lesion.name); lesionData.push_back(lesion.lesionClass.UID); VectorProperty::Pointer newLesionVectorProperty = VectorProperty::New(); newLesionVectorProperty->SetValue(lesionData); propertyList->SetProperty(lesion.UID, newLesionVectorProperty); // overwrite the lesion class with the lesion class UID as key and the new, given class type as value std::string lesionClassType = lesion.lesionClass.classType; propertyList->SetStringProperty(lesion.lesionClass.UID.c_str(), lesionClassType.c_str()); } else { MITK_DEBUG << "Could not find lesion " << lesion.UID << " in the storage. Cannot overwrite the lesion."; } } void mitk::RelationStorage::LinkSegmentationToLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID, const SemanticTypes::Lesion& lesion) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid lesion-IDs for the current case VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); if (nullptr == lesionVectorProperty) { - MITK_DEBUG << "Could not find any lesion property in the storage."; + MITK_DEBUG << "Could not find any lesion in the storage."; return; } - std::vector lesionVectorValue = lesionVectorProperty->GetValue(); - const auto existingLesion = std::find(lesionVectorValue.begin(), lesionVectorValue.end(), lesion.UID); - if (existingLesion != lesionVectorValue.end()) + std::vector lesionVectorPropertyValue = lesionVectorProperty->GetValue(); + const auto existingLesion = std::find(lesionVectorPropertyValue.begin(), lesionVectorPropertyValue.end(), lesion.UID); + if (existingLesion != lesionVectorPropertyValue.end()) { // set / overwrite the lesion reference of the given segmentation // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); if (nullptr == segmentationVectorProperty) { - MITK_DEBUG << "Could not find the segmentation node " << segmentationID << " in the storage. Cannot link segmentation to lesion."; + MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage. Cannot link segmentation to lesion."; return; } - std::vector segmentationVectorValue = segmentationVectorProperty->GetValue(); - if (segmentationVectorValue.size() != 2) + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); + if (segmentationVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect segmentation storage. Not two (2) IDs stored."; return; } // the lesion ID of a segmentation is the second value in the vector - segmentationVectorValue[1] = lesion.UID; - segmentationVectorProperty->SetValue(segmentationVectorValue); + segmentationVectorPropertyValue[1] = lesion.UID; + segmentationVectorProperty->SetValue(segmentationVectorPropertyValue); return; } MITK_DEBUG << "Could not find lesion " << lesion.UID << " in the storage. Cannot link segmentation to lesion."; } void mitk::RelationStorage::UnlinkSegmentationFromLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the referenced ID of a segmentation (0. image ID 1. lesion ID) VectorProperty* segmentationVectorProperty = dynamic_cast*>(propertyList->GetProperty(segmentationID)); if (nullptr == segmentationVectorProperty) { - MITK_DEBUG << "Could not find the segmentation node " << segmentationID << " in the storage. Cannot unlink lesion from segmentation."; + MITK_DEBUG << "Could not find the segmentation " << segmentationID << " in the storage. Cannot unlink lesion from segmentation."; return; } - std::vector segmentationVectorValue = segmentationVectorProperty->GetValue(); + std::vector segmentationVectorPropertyValue = segmentationVectorProperty->GetValue(); // a segmentation has to have exactly two values (the ID of the linked image and the ID of the lesion) - if (segmentationVectorValue.size() != 2) + if (segmentationVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } - // the second value of the data node vector is the ID of the referenced lesion + // the second value of the segmentation vector is the ID of the referenced lesion // set the lesion reference to an empty string for removal - segmentationVectorValue[1] = ""; - segmentationVectorProperty->SetValue(segmentationVectorValue); + segmentationVectorPropertyValue[1] = ""; + segmentationVectorProperty->SetValue(segmentationVectorPropertyValue); } void mitk::RelationStorage::RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid lesions of the current case VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); if (nullptr == lesionVectorProperty) { - MITK_DEBUG << "Could not find any lesion property in the storage."; + MITK_DEBUG << "Could not find any lesion in the storage."; return; } // remove the lesion reference from the list of all lesions of the current case - std::vector lesionVectorValue = lesionVectorProperty->GetValue(); - lesionVectorValue.erase(std::remove(lesionVectorValue.begin(), lesionVectorValue.end(), lesion.UID), lesionVectorValue.end()); - if (lesionVectorValue.empty()) + std::vector lesionsVectorPropertyValue = lesionVectorProperty->GetValue(); + lesionsVectorPropertyValue.erase(std::remove(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(), lesion.UID), lesionsVectorPropertyValue.end()); + if (lesionsVectorPropertyValue.empty()) { // no more lesions stored -> remove the lesions property list propertyList->DeleteProperty("lesions"); } else { // or store the modified vector value - lesionVectorProperty->SetValue(lesionVectorValue); + lesionVectorProperty->SetValue(lesionsVectorPropertyValue); } // remove the lesion instance itself // the lesion data is stored under the lesion ID VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesion.UID)); if (nullptr == lesionDataProperty) { MITK_DEBUG << "Lesion " << lesion.UID << " not found (already removed?). Cannot remove the lesion."; return; } std::vector lesionData = lesionDataProperty->GetValue(); // a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class) if (lesionData.size() != 2) { MITK_DEBUG << "Incorrect lesion data storage. Not two (2) strings of the lesion UID and the lesion name are stored."; } else { std::string lesionClassID = lesionData[1]; RemoveLesionClass(caseID, lesionClassID); } propertyList->DeleteProperty(lesion.UID); } void mitk::RelationStorage::RemoveLesionClass(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& lesionClassID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the lesion class StringProperty* lesionClassProperty = dynamic_cast(propertyList->GetProperty(lesionClassID)); if (nullptr == lesionClassProperty) { MITK_DEBUG << "Lesion class " << lesionClassID << " not found (already removed?). Cannot remove the lesion class."; return; } // retrieve a vector property that contains the valid lesions of the current case VectorProperty* lesionVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); if (nullptr == lesionVectorProperty) { return; } // check if the lesion class ID is referenced by any other lesion - std::vector lesionVectorValue = lesionVectorProperty->GetValue(); - const auto existingLesionClass = std::find_if(lesionVectorValue.begin(), lesionVectorValue.end(), + std::vector lesionsVectorPropertyValue = lesionVectorProperty->GetValue(); + const auto existingLesionClass = std::find_if(lesionsVectorPropertyValue.begin(), lesionsVectorPropertyValue.end(), [&propertyList, &lesionClassID](const std::string& lesionID) { VectorProperty* lesionDataProperty = dynamic_cast*>(propertyList->GetProperty(lesionID)); if (nullptr == lesionDataProperty) { return false; } std::vector lesionData = lesionDataProperty->GetValue(); // a lesion date has to have exactly two values (the name of the lesion and the UID of the lesion class) if (lesionData.size() != 2) { return false; } return lesionData[1] == lesionClassID; }); - if (existingLesionClass == lesionVectorValue.end()) + if (existingLesionClass == lesionsVectorPropertyValue.end()) { // lesion class ID not referenced; remove lesion class propertyList->DeleteProperty(lesionClassID); } } void mitk::RelationStorage::AddControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid controlPoint UIDs for the current case - VectorProperty::Pointer controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); - std::vector controlPointVectorValue; - if (nullptr == controlPointVectorProperty) + VectorProperty::Pointer controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); + std::vector controlPointsVectorPropertyValue; + if (nullptr == controlPointsVectorProperty) { - controlPointVectorProperty = VectorProperty::New(); + controlPointsVectorProperty = VectorProperty::New(); } else { - controlPointVectorValue = controlPointVectorProperty->GetValue(); + controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); } - const auto existingControlPoint = std::find(controlPointVectorValue.begin(), controlPointVectorValue.end(), controlPoint.UID); - if (existingControlPoint != controlPointVectorValue.end()) + const auto existingControlPoint = std::find(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID); + if (existingControlPoint != controlPointsVectorPropertyValue.end()) { return; } // add the new control point UID from the given control point to the vector of all current control point UIDs - controlPointVectorValue.push_back(controlPoint.UID); + controlPointsVectorPropertyValue.push_back(controlPoint.UID); // overwrite the current vector property with the new, extended string vector - controlPointVectorProperty->SetValue(controlPointVectorValue); - propertyList->SetProperty("controlpoints", controlPointVectorProperty); + controlPointsVectorProperty->SetValue(controlPointsVectorPropertyValue); + propertyList->SetProperty("controlpoints", controlPointsVectorProperty); // store the control point values (the three integer values of a date) std::vector controlPointDate; controlPointDate.push_back(controlPoint.date.year()); controlPointDate.push_back(controlPoint.date.month()); controlPointDate.push_back(controlPoint.date.day()); VectorProperty::Pointer newControlPointVectorProperty = VectorProperty::New(); newControlPointVectorProperty->SetValue(controlPointDate); propertyList->SetProperty(controlPoint.UID, newControlPointVectorProperty); } -void mitk::RelationStorage::LinkDataToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& dataNodeID, const SemanticTypes::ControlPoint& controlPoint) +void mitk::RelationStorage::LinkImageToControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::ControlPoint& controlPoint) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid controlPoint UIDs for the current case - VectorProperty* controlPointVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); - if (nullptr == controlPointVectorProperty) + VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); + if (nullptr == controlPointsVectorProperty) { - MITK_DEBUG << "Could not find any control point property in the storage."; + MITK_DEBUG << "Could not find any control point in the storage."; return; } - std::vector controlPointVectorValue = controlPointVectorProperty->GetValue(); - const auto existingControlPoint = std::find(controlPointVectorValue.begin(), controlPointVectorValue.end(), controlPoint.UID); - if (existingControlPoint != controlPointVectorValue.end()) + std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); + const auto existingControlPoint = std::find(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID); + if (existingControlPoint != controlPointsVectorPropertyValue.end()) { // set / overwrite the control point reference of the given data - // retrieve a vector property that contains the referenced ID of a data node (0. information type 1. control point ID) - VectorProperty* dataNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(dataNodeID)); - if (nullptr == dataNodeVectorProperty) + // retrieve a vector property that contains the referenced ID of a image (0. information type 1. control point ID) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { - MITK_DEBUG << "Could not find the data node " << dataNodeID << " in the storage. Cannot link data to control point."; + MITK_DEBUG << "Could not find the image " << imageID << " in the storage. Cannot link data to control point."; return; } - std::vector dataNodeVectorValue = dataNodeVectorProperty->GetValue(); - // an image node has to have exactly two values (the information type and the ID of the control point) - if (dataNodeVectorValue.size() != 2) + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } - // the second value of the data node vector is the ID of the referenced control point - dataNodeVectorValue[1] = controlPoint.UID; - dataNodeVectorProperty->SetValue(dataNodeVectorValue); + // the second value of the image vector is the ID of the referenced control point + imageVectorPropertyValue[1] = controlPoint.UID; + imageVectorProperty->SetValue(imageVectorPropertyValue); return; } MITK_DEBUG << "Could not find control point " << controlPoint.UID << " in the storage. Cannot link data to control point."; } -void mitk::RelationStorage::UnlinkDataFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& dataNodeID) +void mitk::RelationStorage::UnlinkImageFromControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the referenced ID of a date (0. information type 1. control point ID) - VectorProperty* dataNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(dataNodeID)); - if (nullptr == dataNodeVectorProperty) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { - MITK_DEBUG << "Could not find the date " << dataNodeID << " in the storage. Cannot unlink control point from date."; + MITK_DEBUG << "Could not find the date " << imageID << " in the storage. Cannot unlink control point from date."; return; } - std::vector dataNodeVectorValue = dataNodeVectorProperty->GetValue(); - // a data node has to have exactly two values (the information type and the ID of the control point) - if (dataNodeVectorValue.size() != 2) + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } - // the second value of the data node vector is the ID of the referenced control point + // the second value of the image vector is the ID of the referenced control point // set the control point reference to an empty string for removal - dataNodeVectorValue[1] = ""; - dataNodeVectorProperty->SetValue(dataNodeVectorValue); + imageVectorPropertyValue[1] = ""; + imageVectorProperty->SetValue(imageVectorPropertyValue); } void mitk::RelationStorage::RemoveControlPointFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid controlPoint UIDs for the current case - VectorProperty* allControlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); - if (nullptr == allControlPointsVectorProperty) + VectorProperty* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); + if (nullptr == controlPointsVectorProperty) { - MITK_DEBUG << "Could not find any control point property in the storage."; + MITK_DEBUG << "Could not find any control point in the storage."; return; } // remove the control point reference from the list of all control points of the current case - std::vector currentControlPointVectorValue = allControlPointsVectorProperty->GetValue(); - currentControlPointVectorValue.erase(std::remove(currentControlPointVectorValue.begin(), currentControlPointVectorValue.end(), controlPoint.UID), currentControlPointVectorValue.end()); - allControlPointsVectorProperty->SetValue(currentControlPointVectorValue); + std::vector controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); + controlPointsVectorPropertyValue.erase(std::remove(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID), controlPointsVectorPropertyValue.end()); + controlPointsVectorProperty->SetValue(controlPointsVectorPropertyValue); // remove the control point instance itself propertyList->DeleteProperty(controlPoint.UID); } void mitk::RelationStorage::AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid examination period UIDs for the current case - VectorProperty::Pointer vectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); - std::vector examinationPeriodsVectorValue; - if (nullptr == vectorProperty) + VectorProperty::Pointer examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); + std::vector examinationPeriodsVectorPropertyValue; + if (nullptr == examinationPeriodsVectorProperty) { - vectorProperty = VectorProperty::New(); + examinationPeriodsVectorProperty = VectorProperty::New(); } else { - examinationPeriodsVectorValue = vectorProperty->GetValue(); + examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue(); } - const auto& existingIndex = std::find(examinationPeriodsVectorValue.begin(), examinationPeriodsVectorValue.end(), examinationPeriod.UID); - if (existingIndex != examinationPeriodsVectorValue.end()) + const auto& existingIndex = std::find(examinationPeriodsVectorPropertyValue.begin(), examinationPeriodsVectorPropertyValue.end(), examinationPeriod.UID); + if (existingIndex != examinationPeriodsVectorPropertyValue.end()) { return; } // add the new examination period id from the given examination period to the vector of all current examination period UIDs - examinationPeriodsVectorValue.push_back(examinationPeriod.UID); + examinationPeriodsVectorPropertyValue.push_back(examinationPeriod.UID); // overwrite the current vector property with the new, extended string vector - vectorProperty->SetValue(examinationPeriodsVectorValue); - propertyList->SetProperty("examinationperiods", vectorProperty); + examinationPeriodsVectorProperty->SetValue(examinationPeriodsVectorPropertyValue); + propertyList->SetProperty("examinationperiods", examinationPeriodsVectorProperty); // add the examination period with the UID as the key and the name as as the vector value std::vector examinationPeriodData; examinationPeriodData.push_back(examinationPeriod.name); VectorProperty::Pointer newExaminationPeriodVectorProperty = VectorProperty::New(); newExaminationPeriodVectorProperty->SetValue(examinationPeriodData); propertyList->SetProperty(examinationPeriod.UID, newExaminationPeriodVectorProperty); } -void mitk::RelationStorage::AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod examinationPeriod) +void mitk::RelationStorage::AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the represented control point UIDs of the given examination period VectorProperty* controlPointUIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(examinationPeriod.UID)); if (nullptr == controlPointUIDsVectorProperty) { MITK_DEBUG << "Could not find the examination period " << examinationPeriod.UID << " in the storage. Cannot add the control point to the examination period."; return; } - std::vector controlPointUIDsVectorValue = controlPointUIDsVectorProperty->GetValue(); + std::vector controlPointUIDsVectorPropertyValue = controlPointUIDsVectorProperty->GetValue(); // store the control point UID - controlPointUIDsVectorValue.push_back(controlPoint.UID); + controlPointUIDsVectorPropertyValue.push_back(controlPoint.UID); // sort the vector according to the date of the control points referenced by the UIDs auto lambda = [&caseID](const SemanticTypes::ID& leftControlPointUID, const SemanticTypes::ID& rightControlPointUID) { const auto& leftControlPoint = GenerateControlpoint(caseID, leftControlPointUID); const auto& rightControlPoint = GenerateControlpoint(caseID, rightControlPointUID); return leftControlPoint.date <= rightControlPoint.date; }; - std::sort(controlPointUIDsVectorValue.begin(), controlPointUIDsVectorValue.end(), lambda); + std::sort(controlPointUIDsVectorPropertyValue.begin(), controlPointUIDsVectorPropertyValue.end(), lambda); // store the modified and sorted control point UID vector of this examination period - controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorValue); + controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorPropertyValue); } -void mitk::RelationStorage::RemoveControlPointFromExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod examinationPeriod) +void mitk::RelationStorage::RemoveControlPointFromExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the represented control point UIDs of the given examination period VectorProperty* controlPointUIDsVectorProperty = dynamic_cast*>(propertyList->GetProperty(examinationPeriod.UID)); if (nullptr == controlPointUIDsVectorProperty) { MITK_DEBUG << "Could not find examination period " << examinationPeriod.UID << " in the storage. Cannot add the control point to the examination period."; return; } - std::vector controlPointUIDsVectorValue = controlPointUIDsVectorProperty->GetValue(); + std::vector controlPointUIDsVectorPropertyValue = controlPointUIDsVectorProperty->GetValue(); // an examination period has an arbitrary number of vector values (name and control point UIDs) (at least one for the name) - if (controlPointUIDsVectorValue.size() < 2) + if (controlPointUIDsVectorPropertyValue.size() < 2) { MITK_DEBUG << "Incorrect examination period storage. At least one (1) control point ID has to be stored."; return; } else { - controlPointUIDsVectorValue.erase(std::remove(controlPointUIDsVectorValue.begin(), controlPointUIDsVectorValue.end(), controlPoint.UID), controlPointUIDsVectorValue.end()); - if (controlPointUIDsVectorValue.size() < 2) + controlPointUIDsVectorPropertyValue.erase(std::remove(controlPointUIDsVectorPropertyValue.begin(), controlPointUIDsVectorPropertyValue.end(), controlPoint.UID), controlPointUIDsVectorPropertyValue.end()); + if (controlPointUIDsVectorPropertyValue.size() < 2) { RemoveExaminationPeriodFromCase(caseID, examinationPeriod); } else { // store the modified vector value - controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorValue); + controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorPropertyValue); } } } -void mitk::RelationStorage::RemoveExaminationPeriodFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod examinationPeriod) +void mitk::RelationStorage::RemoveExaminationPeriodFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid examination period UIDs for the current case - VectorProperty::Pointer vectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); - if (nullptr == vectorProperty) + VectorProperty::Pointer examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); + if (nullptr == examinationPeriodsVectorProperty) { MITK_DEBUG << "Could not find any examination periods in the storage."; return; } - std::vector examinationPeriodVectorValue = vectorProperty->GetValue(); - examinationPeriodVectorValue.erase(std::remove(examinationPeriodVectorValue.begin(), examinationPeriodVectorValue.end(), examinationPeriod.UID), examinationPeriodVectorValue.end()); - if (examinationPeriodVectorValue.empty()) + std::vector examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue(); + examinationPeriodsVectorPropertyValue.erase(std::remove(examinationPeriodsVectorPropertyValue.begin(), examinationPeriodsVectorPropertyValue.end(), examinationPeriod.UID), examinationPeriodsVectorPropertyValue.end()); + if (examinationPeriodsVectorPropertyValue.empty()) { // no more examination periods stored -> remove the examination period property list propertyList->DeleteProperty("examinationperiods"); } else { // or store the modified vector value - vectorProperty->SetValue(examinationPeriodVectorValue); + examinationPeriodsVectorProperty->SetValue(examinationPeriodsVectorPropertyValue); } } -void mitk::RelationStorage::AddInformationTypeToImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::InformationType informationType) +void mitk::RelationStorage::AddInformationTypeToImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID, const SemanticTypes::InformationType& informationType) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid information types of the current case - VectorProperty::Pointer informationTypeVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); - std::vector informationTypeVectorValue; - if (nullptr == informationTypeVectorProperty) + VectorProperty::Pointer informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); + std::vector informationTypesVectorPropertyValue; + if (nullptr == informationTypesVectorProperty) { - informationTypeVectorProperty = VectorProperty::New(); + informationTypesVectorProperty = VectorProperty::New(); } else { - informationTypeVectorValue = informationTypeVectorProperty->GetValue(); + informationTypesVectorPropertyValue = informationTypesVectorProperty->GetValue(); } - const auto existingInformationType = std::find(informationTypeVectorValue.begin(), informationTypeVectorValue.end(), informationType); - if (existingInformationType == informationTypeVectorValue.end()) + const auto existingInformationType = std::find(informationTypesVectorPropertyValue.begin(), informationTypesVectorPropertyValue.end(), informationType); + if (existingInformationType == informationTypesVectorPropertyValue.end()) { // at first: add the information type to the storage - informationTypeVectorValue.push_back(informationType); - informationTypeVectorProperty->SetValue(informationTypeVectorValue); - propertyList->SetProperty("informationtypes", informationTypeVectorProperty); + informationTypesVectorPropertyValue.push_back(informationType); + informationTypesVectorProperty->SetValue(informationTypesVectorPropertyValue); + propertyList->SetProperty("informationtypes", informationTypesVectorProperty); } // set / overwrite the information type of the given data // retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID) - VectorProperty* imageNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); - if (nullptr == imageNodeVectorProperty) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { MITK_DEBUG << "Could not find the image " << imageID << " in the storage. Cannot add information type to image."; return; } - std::vector imageNodeVectorValue = imageNodeVectorProperty->GetValue(); - // an image node has to have exactly two values (the information type and the ID of the control point) - if (imageNodeVectorValue.size() != 2) + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } - // the first value of the data node vector is the information type - imageNodeVectorValue[0] = informationType; - imageNodeVectorProperty->SetValue(imageNodeVectorValue); + // the first value of the image vector is the information type + imageVectorPropertyValue[0] = informationType; + imageVectorProperty->SetValue(imageVectorPropertyValue); } void mitk::RelationStorage::RemoveInformationTypeFromImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the referenced ID of an image (0. information type 1. control point ID) - VectorProperty* imageNodeVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); - if (nullptr == imageNodeVectorProperty) + VectorProperty* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); + if (nullptr == imageVectorProperty) { MITK_DEBUG << "Could not find the image " << imageID << " in the storage. Cannot remove information type from image."; return; } - std::vector imageNodeVectorValue = imageNodeVectorProperty->GetValue(); - // an image node has to have exactly two values (the information type and the ID of the control point) - if (imageNodeVectorValue.size() != 2) + std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); + // an image has to have exactly two values (the information type and the ID of the control point) + if (imageVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } - // the first value of the data node vector is the information type + // the first value of the image vector is the information type // set the information type to an empty string for removal - imageNodeVectorValue[0] = ""; - imageNodeVectorProperty->SetValue(imageNodeVectorValue); + imageVectorPropertyValue[0] = ""; + imageVectorProperty->SetValue(imageVectorPropertyValue); } -void mitk::RelationStorage::RemoveInformationTypeFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType informationType) +void mitk::RelationStorage::RemoveInformationTypeFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) { PropertyList::Pointer propertyList = GetStorageData(caseID); if (nullptr == propertyList) { MITK_DEBUG << "Could not find the property list " << caseID << " for the current MITK workbench / session."; return; } // retrieve a vector property that contains the valid information types of the current case - VectorProperty* informationTypeVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); - if (nullptr == informationTypeVectorProperty) + VectorProperty* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); + if (nullptr == informationTypesVectorProperty) { - MITK_DEBUG << "Could not find any information type property in the storage."; + MITK_DEBUG << "Could not find any information type in the storage."; return; } - std::vector informationTypeVectorValue = informationTypeVectorProperty->GetValue(); - informationTypeVectorValue.erase(std::remove(informationTypeVectorValue.begin(), informationTypeVectorValue.end(), informationType), informationTypeVectorValue.end()); - if (informationTypeVectorValue.empty()) + std::vector informationTypesVectorPropertyValue = informationTypesVectorProperty->GetValue(); + informationTypesVectorPropertyValue.erase(std::remove(informationTypesVectorPropertyValue.begin(), informationTypesVectorPropertyValue.end(), informationType), informationTypesVectorPropertyValue.end()); + if (informationTypesVectorPropertyValue.empty()) { // no more information types stored -> remove the information types property list propertyList->DeleteProperty("informationtypes"); } else { // or store the modified vector value - informationTypeVectorProperty->SetValue(informationTypeVectorValue); + informationTypesVectorProperty->SetValue(informationTypesVectorPropertyValue); } } diff --git a/Modules/SemanticRelations/src/mitkSemanticRelations.cpp b/Modules/SemanticRelations/src/mitkSemanticRelations.cpp deleted file mode 100644 index 72f247f5f0..0000000000 --- a/Modules/SemanticRelations/src/mitkSemanticRelations.cpp +++ /dev/null @@ -1,1060 +0,0 @@ -/*=================================================================== - -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 "mitkSemanticRelations.h" - -// semantic relations module -#include "mitkControlPointManager.h" -#include "mitkNodePredicates.h" -#include "mitkRelationStorage.h" -#include "mitkSemanticRelationException.h" -#include "mitkUIDGeneratorBoost.h" - -// multi label module -#include - -// c++ -#include -#include - -std::vector mitk::SemanticRelations::m_ObserverVector; - -mitk::SemanticRelations::SemanticRelations(DataStorage* dataStorage) - : m_DataStorage(dataStorage) -{ - // nothing here -} - -mitk::SemanticRelations::~SemanticRelations() -{ - // nothing here -} - -void mitk::SemanticRelations::AddObserver(ISemanticRelationsObserver* observer) -{ - std::vector::iterator existingObserver = std::find(m_ObserverVector.begin(), m_ObserverVector.end(), observer); - if (existingObserver != m_ObserverVector.end()) - { - // no need to add the already existing observer - return; - } - - m_ObserverVector.push_back(observer); -} - -void mitk::SemanticRelations::RemoveObserver(ISemanticRelationsObserver* observer) -{ - m_ObserverVector.erase(std::remove(m_ObserverVector.begin(), m_ObserverVector.end(), observer), m_ObserverVector.end()); -} - -/************************************************************************/ -/* functions to get instances / attributes */ -/************************************************************************/ - -mitk::SemanticTypes::LesionVector mitk::SemanticRelations::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID) const -{ - return RelationStorage::GetAllLesionsOfCase(caseID); -} - -mitk::SemanticTypes::LesionVector mitk::SemanticRelations::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const -{ - SemanticTypes::LesionVector allLesions = GetAllLesionsOfCase(caseID); - - // filter the lesions: use only those, where the associated data is connected to image data that refers to the given control point using a lambda function - auto lambda = [&caseID, &controlPoint, this](const SemanticTypes::Lesion& lesion) { return !ControlPointContainsLesion(caseID, lesion, controlPoint); }; - allLesions.erase(std::remove_if(allLesions.begin(), allLesions.end(), lambda), allLesions.end()); - - return allLesions; -} - -mitk::SemanticTypes::LesionClassVector mitk::SemanticRelations::GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID) const -{ - SemanticTypes::LesionVector allLesionsOfCase = GetAllLesionsOfCase(caseID); - SemanticTypes::LesionClassVector allLesionClassesOfCase; - - for (const auto& lesion : allLesionsOfCase) - { - allLesionClassesOfCase.push_back(lesion.lesionClass); - } - - // remove duplicate entries - auto lessThan = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) - { - return lesionClassLeft.UID < lesionClassRight.UID; - }; - - auto equal = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) - { - return lesionClassLeft.UID == lesionClassRight.UID; - }; - - std::sort(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), lessThan); - allLesionClassesOfCase.erase(std::unique(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), equal), allLesionClassesOfCase.end()); - - return allLesionClassesOfCase; -} - -mitk::SemanticTypes::LesionVector mitk::SemanticRelations::GetAllLesionsInImage(const DataNode* imageNode) const -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid image data node."; - } - - if (m_DataStorage.IsExpired()) - { - mitkThrowException(SemanticRelationException) << "Not a valid data storage."; - } - - SemanticTypes::LesionVector allLesionsInImage; - // get child nodes of the current node with the segmentation predicate - DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage.Lock()->GetDerivations(imageNode, NodePredicates::GetSegmentationPredicate(), false); - for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) - { - DataNode* segmentationNode = it->Value(); - try - { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(segmentationNode); - allLesionsInImage.push_back(representedLesion); - } - catch (const SemanticRelationException&) - { - continue; - } - } - return allLesionsInImage; -} - -mitk::SemanticTypes::Lesion mitk::SemanticRelations::GetRepresentedLesion(const DataNode* segmentationNode) const -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); - SemanticTypes::Lesion representedLesion = RelationStorage::GetRepresentedLesion(caseID, segmentationID); - - if (representedLesion.UID.empty()) - { - mitkThrowException(SemanticRelationException) << "Could not find a represented lesion instance for the given segmentation node " << segmentationNode->GetName(); - } - else - { - return representedLesion; - } -} - -bool mitk::SemanticRelations::IsLesionPresentOnDataNode(const SemanticTypes::Lesion& lesion, const mitk::DataNode* dataNode) const -{ - if (nullptr == dataNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - if (m_DataStorage.IsExpired()) - { - mitkThrowException(SemanticRelationException) << "Not a valid data storage."; - } - - try - { - if (NodePredicates::GetImagePredicate()->CheckNode(dataNode)) - { - // get segmentations of the image node with the segmentation predicate - DataStorage::SetOfObjects::ConstPointer segmentations = m_DataStorage.Lock()->GetDerivations(dataNode, mitk::NodePredicates::GetSegmentationPredicate(), false); - for (auto it = segmentations->Begin(); it != segmentations->End(); ++it) - { - const auto representedLesion = GetRepresentedLesion(it.Value()); - return lesion.UID == representedLesion.UID; - } - } - else if (NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) - { - const auto representedLesion = GetRepresentedLesion(dataNode); - return lesion.UID == representedLesion.UID; - } - } - catch (const SemanticRelationException&) - { - return false; - } - - return false; -} - -bool mitk::SemanticRelations::IsRepresentingALesion(const DataNode* segmentationNode) const -{ - try - { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(segmentationNode); - return true; - } - catch (const Exception&) - { - return false; - } -} - -bool mitk::SemanticRelations::InstanceExists(const DataNode* dataNode) const -{ - try - { - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); - SemanticTypes::ID dataNodeID = GetIDFromDataNode(dataNode); - - if (NodePredicates::GetImagePredicate()->CheckNode(dataNode)) - { - std::vector allImageIDsOfCase = RelationStorage::GetAllImageIDsOfCase(caseID); - return std::find(allImageIDsOfCase.begin(), allImageIDsOfCase.end(), dataNodeID) != allImageIDsOfCase.end(); - } - else if (NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) - { - std::vector allSegmentationIDsOfCase = RelationStorage::GetAllSegmentationIDsOfCase(caseID); - return std::find(allSegmentationIDsOfCase.begin(), allSegmentationIDsOfCase.end(), dataNodeID) != allSegmentationIDsOfCase.end(); - } - else - { - return false; - } - } - catch (const SemanticRelationException&) - { - return false; - } -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllSegmentationsOfCase(const SemanticTypes::CaseID& caseID) const -{ - if (m_DataStorage.IsExpired()) - { - mitkThrowException(SemanticRelationException) << "Not a valid data storage."; - } - - std::vector allSegmentationIDsOfCase = RelationStorage::GetAllSegmentationIDsOfCase(caseID); - std::vector allSegmentationsOfCase; - // get all segmentation nodes of the current data storage - // only those nodes are respected, that are currently held in the data storage - DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage.Lock()->GetSubset(NodePredicates::GetSegmentationPredicate()); - for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) - { - DataNode* segmentationNode = it->Value(); - try - { - // find the corresponding segmentation node for the given segmentation ID - std::string nodeCaseID = GetCaseIDFromDataNode(segmentationNode); - std::string nodeSegmentationID = GetIDFromDataNode(segmentationNode); - if (nodeCaseID == caseID && (std::find(allSegmentationIDsOfCase.begin(), allSegmentationIDsOfCase.end(), nodeSegmentationID) != allSegmentationIDsOfCase.end())) - { - // found current image node in the storage, add it to the return vector - allSegmentationsOfCase.push_back(segmentationNode); - } - } - catch (const std::exception&) - { - // found a segmentation node that is not stored in the semantic relations - // this segmentation node does not have any DICOM information --> exception thrown - // continue with the next segmentation to compare IDs - continue; - } - } - - return allSegmentationsOfCase; -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllSegmentationsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const -{ - if (InstanceExists(caseID, lesion)) - { - // lesion exists, retrieve all case segmentations from the storage - DataNodeVector allSegmentationsOfLesion = GetAllSegmentationsOfCase(caseID); - - // filter all segmentations: check for semantic relation with the given lesion using a lambda function - auto lambda = [&lesion, this](DataNode::Pointer segmentation) - { - try - { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(segmentation); - return lesion.UID != representedLesion.UID; - } - catch (const SemanticRelationException&) - { - return true; - } - }; - allSegmentationsOfLesion.erase(std::remove_if(allSegmentationsOfLesion.begin(), allSegmentationsOfLesion.end(), lambda), allSegmentationsOfLesion.end()); - - return allSegmentationsOfLesion; - } - else - { - mitkThrowException(SemanticRelationException) << "Could not find an existing lesion instance for the given caseID " << caseID << " and lesion " << lesion.UID << "."; - } -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllImagesOfCase(const SemanticTypes::CaseID& caseID) const -{ - if (m_DataStorage.IsExpired()) - { - mitkThrowException(SemanticRelationException) << "Not a valid data storage."; - } - - std::vector allImageIDsOfCase = RelationStorage::GetAllImageIDsOfCase(caseID); - std::vector allImagesOfCase; - // get all image nodes of the current data storage - // only those nodes are respected, that are currently held in the data storage - DataStorage::SetOfObjects::ConstPointer imageNodes = m_DataStorage.Lock()->GetSubset(NodePredicates::GetImagePredicate()); - for (auto it = imageNodes->Begin(); it != imageNodes->End(); ++it) - { - DataNode* imageNode = it->Value(); - // find the corresponding image node for the given segmentation ID - std::string nodeCaseID = GetCaseIDFromDataNode(imageNode); - std::string nodeImageID = GetIDFromDataNode(imageNode); - if (nodeCaseID == caseID && (std::find(allImageIDsOfCase.begin(), allImageIDsOfCase.end(), nodeImageID) != allImageIDsOfCase.end())) - { - // found current image node in the storage, add it to the return vector - allImagesOfCase.push_back(imageNode); - } - } - - return allImagesOfCase; -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllImagesOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const -{ - if (m_DataStorage.IsExpired()) - { - mitkThrowException(SemanticRelationException) << "Not a valid data storage."; - } - - DataNodeVector allImagesOfLesion; - // 1. get all segmentations that define the lesion - // 2. retrieve the parent node (source) of the found segmentation node - DataNodeVector allSegmentationsOfLesion = GetAllSegmentationsOfLesion(caseID, lesion); - for (const auto& segmentationNode : allSegmentationsOfLesion) - { - // get parent node of the current segmentation node with the node predicate - DataStorage::SetOfObjects::ConstPointer parentNodes = m_DataStorage.Lock()->GetSources(segmentationNode, NodePredicates::GetImagePredicate(), false); - for (auto it = parentNodes->Begin(); it != parentNodes->End(); ++it) - { - DataNode::Pointer dataNode = it->Value(); - allImagesOfLesion.push_back(it->Value()); - } - } - - std::sort(allImagesOfLesion.begin(), allImagesOfLesion.end()); - allImagesOfLesion.erase(std::unique(allImagesOfLesion.begin(), allImagesOfLesion.end()), allImagesOfLesion.end()); - return allImagesOfLesion; -} - -bool mitk::SemanticRelations::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const -{ - SemanticTypes::LesionVector allLesions = GetAllLesionsOfCase(caseID); - - // filter all lesions: check for equality with the given lesion using a lambda function - auto lambda = [&lesion](const SemanticTypes::Lesion& currentLesion) { return currentLesion.UID == lesion.UID; }; - const auto existingLesion = std::find_if(allLesions.begin(), allLesions.end(), lambda); - - if (existingLesion != allLesions.end()) - { - return true; - } - else - { - return false; - } -} - -mitk::SemanticTypes::ControlPointVector mitk::SemanticRelations::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID) const -{ - return RelationStorage::GetAllControlPointsOfCase(caseID); -} - -mitk::SemanticTypes::ControlPointVector mitk::SemanticRelations::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const -{ - SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); - - // filter the control points: use only those, where the associated image data has a segmentation that refers to the given lesion using a lambda function - auto lambda = [&caseID, &lesion, this](const SemanticTypes::ControlPoint& controlPoint) { return !ControlPointContainsLesion(caseID, lesion, controlPoint); }; - allControlPoints.erase(std::remove_if(allControlPoints.begin(), allControlPoints.end(), lambda), allControlPoints.end()); - - return allControlPoints; -} - -mitk::SemanticTypes::ControlPointVector mitk::SemanticRelations::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const -{ - SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); - - // filter the control points: use only those, where the associated image data refers to the given information type using a lambda function - auto lambda = [&caseID, &informationType, this](const SemanticTypes::ControlPoint& controlPoint) { return !ControlPointContainsInformationType(caseID, informationType, controlPoint); }; - allControlPoints.erase(std::remove_if(allControlPoints.begin(), allControlPoints.end(), lambda), allControlPoints.end()); - - return allControlPoints; -} - -mitk::SemanticTypes::ControlPoint mitk::SemanticRelations::GetControlPointOfData(const DataNode* imageNode) const -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID dataNodeID = GetIDFromDataNode(imageNode); - return RelationStorage::GetControlPointOfImage(caseID, dataNodeID); -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllImagesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const -{ - if (InstanceExists(caseID, controlPoint)) - { - // control point exists, retrieve all images from the storage - DataNodeVector allImagesOfControlPoint = GetAllImagesOfCase(caseID); - - // filter all images to remove the ones with a different control point using a lambda function - auto lambda = [&controlPoint, this](DataNode::Pointer imageNode) - { - return controlPoint.UID != GetControlPointOfData(imageNode).UID; - }; - - allImagesOfControlPoint.erase(std::remove_if(allImagesOfControlPoint.begin(), allImagesOfControlPoint.end(), lambda), allImagesOfControlPoint.end()); - - return allImagesOfControlPoint; - } - else - { - mitkThrowException(SemanticRelationException) << "Could not find an existing control point instance for the given caseID " << caseID << " and control point " << controlPoint.UID << "."; - } -} - -bool mitk::SemanticRelations::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const -{ - SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); - - // filter all control points: check for equality with the given control point using a lambda function - auto lambda = [&controlPoint](const SemanticTypes::ControlPoint& currentControlPoint) { return currentControlPoint.UID == controlPoint.UID; }; - const auto existingControlPoint = std::find_if(allControlPoints.begin(), allControlPoints.end(), lambda); - - if (existingControlPoint != allControlPoints.end()) - { - return true; - } - else - { - return false; - } -} - -mitk::SemanticTypes::ExaminationPeriodVector mitk::SemanticRelations::GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID) const -{ - return RelationStorage::GetAllExaminationPeriodsOfCase(caseID); -} - -bool mitk::SemanticRelations::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) const -{ - SemanticTypes::ExaminationPeriodVector allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); - - // filter all examination periods: check for equality with the given examination period using a lambda function - auto lambda = [&examinationPeriod](const SemanticTypes::ExaminationPeriod& currentExaminationPeriod) { return currentExaminationPeriod.UID == examinationPeriod.UID; }; - const auto existingExaminationPeriod = std::find_if(allExaminationPeriods.begin(), allExaminationPeriods.end(), lambda); - - if (existingExaminationPeriod != allExaminationPeriods.end()) - { - return true; - } - else - { - return false; - } -} - -mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelations::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID) const -{ - return RelationStorage::GetAllInformationTypesOfCase(caseID); -} - -mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelations::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) const -{ - SemanticTypes::InformationTypeVector allInformationTypes = GetAllInformationTypesOfCase(caseID); - - // filter the information types: use only those, where the associated data refers to the given control point using a lambda function - auto lambda = [&caseID, &controlPoint, this](const SemanticTypes::InformationType& informationType) { return !ControlPointContainsInformationType(caseID, informationType, controlPoint); }; - allInformationTypes.erase(std::remove_if(allInformationTypes.begin(), allInformationTypes.end(), lambda), allInformationTypes.end()); - - return allInformationTypes; -} - -mitk::SemanticTypes::InformationType mitk::SemanticRelations::GetInformationTypeOfImage(const DataNode* imageNode) const -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid image data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); - return RelationStorage::GetInformationTypeOfImage(caseID, imageID); -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllImagesOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const -{ - if (InstanceExists(caseID, informationType)) - { - // information type exists, retrieve all images from the storage - DataNodeVector allImagesOfInformationType = GetAllImagesOfCase(caseID); - - // filter all images to remove the ones with a different information type using a lambda function - auto lambda = [&informationType, this](DataNode::Pointer imageNode) - { - return informationType != GetInformationTypeOfImage(imageNode); - }; - - allImagesOfInformationType.erase(std::remove_if(allImagesOfInformationType.begin(), allImagesOfInformationType.end(), lambda), allImagesOfInformationType.end()); - - return allImagesOfInformationType; - } - else - { - mitkThrowException(SemanticRelationException) << "Could not find an existing information type for the given caseID " << caseID << " and information type " << informationType; - } -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const -{ - if (InstanceExists(caseID, controlPoint)) - { - if (InstanceExists(caseID, informationType)) - { - // control point exists, information type exists, retrieve all images from the storage - DataNodeVector allImagesOfCase = GetAllImagesOfCase(caseID); - // filter all images to remove the ones with a different control point and information type using a lambda function - auto lambda = [&controlPoint, &informationType, this](DataNode::Pointer imageNode) - { - return (informationType != GetInformationTypeOfImage(imageNode)) || (controlPoint.date != GetControlPointOfData(imageNode).date); - }; - - allImagesOfCase.erase(std::remove_if(allImagesOfCase.begin(), allImagesOfCase.end(), lambda), allImagesOfCase.end()); - - return allImagesOfCase; - } - else - { - mitkThrowException(SemanticRelationException) << "Could not find an existing information type for the given caseID " << caseID << " and information type " << informationType; - } - } - else - { - mitkThrowException(SemanticRelationException) << "Could not find an existing control point for the given caseID " << caseID << " and control point " << controlPoint.UID; - } -} - -mitk::SemanticRelations::DataNodeVector mitk::SemanticRelations::GetAllSpecificSegmentations(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const -{ - if (m_DataStorage.IsExpired()) - { - mitkThrow() << "Not a valid data storage."; - } - - DataNodeVector allSpecificImages = GetAllSpecificImages(caseID, controlPoint, informationType); - DataNodeVector allSpecificSegmentations; - for (const auto& imageNode : allSpecificImages) - { - DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage.Lock()->GetDerivations(imageNode, NodePredicates::GetSegmentationPredicate(), false); - for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) - { - allSpecificSegmentations.push_back(it->Value()); - } - } - - return allSpecificSegmentations; -} - -bool mitk::SemanticRelations::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) const -{ - SemanticTypes::InformationTypeVector allInformationTypes = GetAllInformationTypesOfCase(caseID); - - // filter all information types: check for equality with the given information type using a lambda function - auto lambda = [&informationType](const SemanticTypes::InformationType& currentInformationType) { return currentInformationType == informationType; }; - const auto existingInformationType = std::find_if(allInformationTypes.begin(), allInformationTypes.end(), lambda); - - if (existingInformationType != allInformationTypes.end()) - { - return true; - } - else - { - return false; - } -} - -std::vector mitk::SemanticRelations::GetAllCaseIDs() const -{ - return RelationStorage::GetAllCaseIDs(); -} - -/************************************************************************/ -/* functions to add / remove instances / attributes */ -/************************************************************************/ - -void mitk::SemanticRelations::AddImage(const DataNode* imageNode) -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - // continue with a valid data node - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID nodeID = GetIDFromDataNode(imageNode); - - RelationStorage::AddCase(caseID); - RelationStorage::AddImage(caseID, nodeID); - - SemanticTypes::InformationType informationType = GetDICOMModalityFromDataNode(imageNode); - AddInformationTypeToImage(imageNode, informationType); - - // set the correct control point for this image - SemanticTypes::ControlPoint controlPoint = GenerateControlPoint(imageNode); - SetControlPointOfData(imageNode, controlPoint); -} - -void mitk::SemanticRelations::RemoveImage(const DataNode* imageNode) -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - // continue with a valid data node - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID nodeID = GetIDFromDataNode(imageNode); - - RemoveInformationTypeFromImage(imageNode); - UnlinkDataFromControlPoint(imageNode); - RelationStorage::RemoveImage(caseID, nodeID); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) -{ - if (InstanceExists(caseID, lesion)) - { - mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to add already exists for the given case."; - } - else - { - RelationStorage::AddLesion(caseID, lesion); - NotifyObserver(caseID); - } -} - -void mitk::SemanticRelations::OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) -{ - if (InstanceExists(caseID, lesion)) - { - RelationStorage::OverwriteLesion(caseID, lesion); - NotifyObserver(caseID); - } - else - { - mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to overwrite does not exist for the given case."; - } -} - -void mitk::SemanticRelations::AddLesionAndLinkSegmentation(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion) -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - AddLesion(caseID, lesion); - LinkSegmentationToLesion(segmentationNode, lesion); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) -{ - if (InstanceExists(caseID, lesion)) - { - DataNodeVector allSegmentationsOfLesion = GetAllSegmentationsOfLesion(caseID, lesion); - if (allSegmentationsOfLesion.empty()) - { - // no more segmentations are linked to the specific lesion - // the lesion can be removed from the storage - RelationStorage::RemoveLesion(caseID, lesion); - NotifyObserver(caseID); - } - else - { - mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to remove is still referred to by a segmentation node. Lesion will not be removed."; - } - } - else - { - mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to remove does not exist for the given case."; - } -} - -void mitk::SemanticRelations::AddSegmentation(const DataNode* segmentationNode, const DataNode* parentNode) -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - if (nullptr == parentNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid parent data node."; - } - - // continue with a valid data node - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - SemanticTypes::ID segmentationNodeID = GetIDFromDataNode(segmentationNode); - SemanticTypes::ID parentNodeID = GetIDFromDataNode(parentNode); - - RelationStorage::AddSegmentation(caseID, segmentationNodeID, parentNodeID); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::LinkSegmentationToLesion(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion) -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - if (InstanceExists(caseID, lesion)) - { - SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); - RelationStorage::LinkSegmentationToLesion(caseID, segmentationID, lesion); - NotifyObserver(caseID); - } - else - { - mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to link does not exist for the given case."; - } -} - -void mitk::SemanticRelations::UnlinkSegmentationFromLesion(const DataNode* segmentationNode) -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); - RelationStorage::UnlinkSegmentationFromLesion(caseID, segmentationID); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::RemoveSegmentation(const DataNode* segmentationNode) -{ - if (nullptr == segmentationNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; - } - - // continue with a valid data node - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); - SemanticTypes::ID segmentationNodeID = GetIDFromDataNode(segmentationNode); - RelationStorage::RemoveSegmentation(caseID, segmentationNodeID); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::SetControlPointOfData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint) -{ - if (nullptr == dataNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); - SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); - // need to check if an already existing control point fits/contains the user control point - SemanticTypes::ControlPoint existingControlPoint = FindExistingControlPoint(controlPoint, allControlPoints); - if (!existingControlPoint.UID.empty()) - { - try - { - // found an already existing control point - LinkDataToControlPoint(dataNode, existingControlPoint, false); - } - catch (const SemanticRelationException&) - { - mitkThrowException(SemanticRelationException) << "The data can not be linked. Inconsistency in the semantic relations storage assumed."; - } - } - else - { - try - { - AddControlPointAndLinkData(dataNode, controlPoint, false); - // added a new control point - // find closest control point to add the new control point to the correct examination period - SemanticTypes::ControlPoint closestControlPoint = FindClosestControlPoint(controlPoint, allControlPoints); - SemanticTypes::ExaminationPeriodVector allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); - SemanticTypes::ExaminationPeriod examinationPeriod = FindExaminationPeriod(closestControlPoint, allExaminationPeriods); - if (examinationPeriod.UID.empty()) - { - // no closest control point (exceed threshold) or no examination period found - // create a new examination period for this control point and add it to the storage - examinationPeriod.UID = UIDGeneratorBoost::GenerateUID(); - examinationPeriod.name = "New examination period " + std::to_string(allExaminationPeriods.size()); - AddExaminationPeriod(caseID, examinationPeriod); - } - - // add the control point to the (newly created or found / close) examination period - AddControlPointToExaminationPeriod(caseID, controlPoint, examinationPeriod); - } - catch (const SemanticRelationException&) - { - mitkThrowException(SemanticRelationException) << "The data can not be linked. Inconsistency in the semantic relations storage assumed."; - } - } - - ClearControlPoints(caseID); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::AddControlPointAndLinkData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) -{ - if (nullptr == dataNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); - if (InstanceExists(caseID, controlPoint)) - { - mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to add already exists for the given case. \n Use 'LinkDataToControlPoint' instead."; - } - - RelationStorage::AddControlPoint(caseID, controlPoint); - LinkDataToControlPoint(dataNode, controlPoint, checkConsistence); -} - -void mitk::SemanticRelations::LinkDataToControlPoint(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) -{ - if (nullptr == dataNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); - if (InstanceExists(caseID, controlPoint)) - { - SemanticTypes::ID dataID = GetIDFromDataNode(dataNode); - RelationStorage::LinkDataToControlPoint(caseID, dataID, controlPoint); - } - else - { - mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to link does not exist for the given case."; - } -} - -void mitk::SemanticRelations::UnlinkDataFromControlPoint(const DataNode* dataNode) -{ - if (nullptr == dataNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); - SemanticTypes::ID dataID = GetIDFromDataNode(dataNode); - SemanticTypes::ControlPoint controlPoint = RelationStorage::GetControlPointOfImage(caseID, dataID); - RelationStorage::UnlinkDataFromControlPoint(caseID, dataID); - ClearControlPoints(caseID); -} - -void mitk::SemanticRelations::AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) -{ - if (InstanceExists(caseID, examinationPeriod)) - { - mitkThrowException(SemanticRelationException) << "The examination period " << examinationPeriod.UID << " to add already exists for the given case."; - } - else - { - RelationStorage::AddExaminationPeriod(caseID, examinationPeriod); - } -} - -void mitk::SemanticRelations::AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod) -{ - if (!InstanceExists(caseID, controlPoint)) - { - mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to add does not exist for the given case."; - } - - if (!InstanceExists(caseID, examinationPeriod)) - { - mitkThrowException(SemanticRelationException) << "The examination period " << examinationPeriod.UID << " does not exist for the given case. \n Use 'AddExaminationPeriod' before."; - } - - RelationStorage::AddControlPointToExaminationPeriod(caseID, controlPoint, examinationPeriod); -} - -void mitk::SemanticRelations::SetInformationType(const DataNode* imageNode, const SemanticTypes::InformationType& informationType) -{ - RemoveInformationTypeFromImage(imageNode); - AddInformationTypeToImage(imageNode, informationType); - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - NotifyObserver(caseID); -} - -void mitk::SemanticRelations::AddInformationTypeToImage(const DataNode* imageNode, const SemanticTypes::InformationType& informationType) -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid image data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); - RelationStorage::AddInformationTypeToImage(caseID, imageID, informationType); -} - -void mitk::SemanticRelations::RemoveInformationTypeFromImage(const DataNode* imageNode) -{ - if (nullptr == imageNode) - { - mitkThrowException(SemanticRelationException) << "Not a valid image data node."; - } - - SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); - SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); - SemanticTypes::InformationType originalInformationType = RelationStorage::GetInformationTypeOfImage(caseID, imageID); - RelationStorage::RemoveInformationTypeFromImage(caseID, imageID); - - // check for further references to the removed information type - std::vector allImageIDsVectorValue = RelationStorage::GetAllImageIDsOfCase(caseID); - for (const auto otherImageID : allImageIDsVectorValue) - { - SemanticTypes::InformationType otherInformationType = RelationStorage::GetInformationTypeOfImage(caseID, otherImageID); - if (otherInformationType == originalInformationType) - { - // found the information type in another image -> cannot remove the information type from the case - return; - } - } - - // given information type was not referred by any other image of the case -> the information type can be removed from the case - RelationStorage::RemoveInformationTypeFromCase(caseID, originalInformationType); -} - -/************************************************************************/ -/* private functions */ -/************************************************************************/ -void mitk::SemanticRelations::NotifyObserver(const SemanticTypes::CaseID& caseID) const -{ - for (auto& observer : m_ObserverVector) - { - observer->Update(caseID); - } -} - -bool mitk::SemanticRelations::ControlPointContainsLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint) const -{ - DataNodeVector allImagesOfLesion; - try - { - allImagesOfLesion = GetAllImagesOfLesion(caseID, lesion); - } - catch (const SemanticRelationException&) - { - // error retrieving image data; lesion has to be outside the control point - return false; - } - - DataNodeVector allImagesOfControlPoint; - try - { - allImagesOfControlPoint = GetAllImagesOfControlPoint(caseID, controlPoint); - } - catch (const SemanticRelationException&) - { - // error retrieving control point data; lesion has to be outside the control point - return false; - } - - std::sort(allImagesOfLesion.begin(), allImagesOfLesion.end()); - std::sort(allImagesOfControlPoint.begin(), allImagesOfControlPoint.end()); - DataNodeVector allImagesIntersection; - // set intersection removes duplicated nodes, since 'GetAllImagesOfControlPoint' only contains at most one of each node - std::set_intersection(allImagesOfLesion.begin(), allImagesOfLesion.end(), - allImagesOfControlPoint.begin(), allImagesOfControlPoint.end(), - std::back_inserter(allImagesIntersection)); - - // if the vector of intersecting data is empty, the control point does not contain the lesion - return !allImagesIntersection.empty(); -} - -bool mitk::SemanticRelations::ControlPointContainsInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ControlPoint& controlPoint) const -{ - DataNodeVector allImagesIntersection = GetAllSpecificImages(caseID, controlPoint, informationType); - return !allImagesIntersection.empty(); -} - -void mitk::SemanticRelations::ClearControlPoints(const SemanticTypes::CaseID& caseID) -{ - SemanticTypes::ControlPointVector allControlPointsOfCase = GetAllControlPointsOfCase(caseID); - - DataNodeVector allImagesOfCase; - try - { - allImagesOfCase = GetAllImagesOfCase(caseID); - } - catch (const SemanticRelationException&) - { - // error retrieving image data - return; - } - - SemanticTypes::ControlPointVector referencedControlPoints; - for (const auto& image : allImagesOfCase) - { - try - { - referencedControlPoints.push_back(GetControlPointOfData(image)); - } - catch (const SemanticRelationException&) - { - // error retrieving control point of data - continue; - } - } - - std::sort(allControlPointsOfCase.begin(), allControlPointsOfCase.end()); - std::sort(referencedControlPoints.begin(), referencedControlPoints.end()); - - SemanticTypes::ControlPointVector nonReferencedControlPoints; - std::set_difference(allControlPointsOfCase.begin(), allControlPointsOfCase.end(), - referencedControlPoints.begin(), referencedControlPoints.end(), - std::inserter(nonReferencedControlPoints, nonReferencedControlPoints.begin())); - - auto allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); - for (const auto& controlPoint : nonReferencedControlPoints) - { - const auto& examinationPeriod = FindExaminationPeriod(controlPoint, allExaminationPeriods); - RelationStorage::RemoveControlPointFromExaminationPeriod(caseID, controlPoint, examinationPeriod); - RelationStorage::RemoveControlPointFromCase(caseID, controlPoint); - } -} diff --git a/Modules/SemanticRelations/src/mitkSemanticRelationsDataStorageAccess.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsDataStorageAccess.cpp new file mode 100644 index 0000000000..b02e89d69e --- /dev/null +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsDataStorageAccess.cpp @@ -0,0 +1,218 @@ +/*=================================================================== + +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 "mitkSemanticRelationsDataStorageAccess.h" + +// semantic relations module +#include "mitkControlPointManager.h" +#include "mitkDICOMHelper.h" +#include "mitkNodePredicates.h" +#include "mitkRelationStorage.h" +#include "mitkSemanticRelationException.h" +#include "mitkSemanticRelationsInference.h" + +// c++ +#include +#include + +mitk::SemanticRelationsDataStorageAccess::SemanticRelationsDataStorageAccess(DataStorage* dataStorage) + : m_DataStorage(dataStorage) +{ + // nothing here +} + +mitk::SemanticRelationsDataStorageAccess::~SemanticRelationsDataStorageAccess() +{ + // nothing here +} + +/************************************************************************/ +/* functions to get instances / attributes */ +/************************************************************************/ + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllSegmentationsOfCase(const SemanticTypes::CaseID& caseID) const +{ + if (m_DataStorage.IsExpired()) + { + mitkThrowException(SemanticRelationException) << "Not a valid data storage."; + } + + std::vector allSegmentationIDsOfCase = RelationStorage::GetAllSegmentationIDsOfCase(caseID); + std::vector allSegmentationsOfCase; + // get all segmentation nodes of the current data storage + // only those nodes are respected, that are currently held in the data storage + DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage.Lock()->GetSubset(NodePredicates::GetSegmentationPredicate()); + for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) + { + DataNode* segmentationNode = it->Value(); + try + { + // find the corresponding segmentation node for the given segmentation ID + std::string nodeCaseID = GetCaseIDFromDataNode(segmentationNode); + std::string nodeSegmentationID = GetIDFromDataNode(segmentationNode); + if (nodeCaseID == caseID && (std::find(allSegmentationIDsOfCase.begin(), allSegmentationIDsOfCase.end(), nodeSegmentationID) != allSegmentationIDsOfCase.end())) + { + // found current image node in the storage, add it to the return vector + allSegmentationsOfCase.push_back(segmentationNode); + } + } + catch (const std::exception&) + { + // found a segmentation node that is not stored in the semantic relations + // this segmentation node does not have any DICOM information --> exception thrown + // continue with the next segmentation to compare IDs + continue; + } + } + + return allSegmentationsOfCase; +} + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllSegmentationsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const +{ + if (SemanticRelationsInference::InstanceExists(caseID, lesion)) + { + // lesion exists, retrieve all case segmentations from the storage + DataNodeVector allSegmentationsOfLesion = GetAllSegmentationsOfCase(caseID); + + // filter all segmentations: check for semantic relation with the given lesion using a lambda function + auto lambda = [&lesion, this](DataNode::Pointer segmentation) + { + try + { + SemanticTypes::Lesion representedLesion = SemanticRelationsInference::GetLesionOfSegmentation(segmentation); + return lesion.UID != representedLesion.UID; + } + catch (const SemanticRelationException&) + { + return true; + } + }; + allSegmentationsOfLesion.erase(std::remove_if(allSegmentationsOfLesion.begin(), allSegmentationsOfLesion.end(), lambda), allSegmentationsOfLesion.end()); + + return allSegmentationsOfLesion; + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing lesion instance for the given caseID " << caseID << " and lesion " << lesion.UID << "."; + } +} + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllImagesOfCase(const SemanticTypes::CaseID& caseID) const +{ + if (m_DataStorage.IsExpired()) + { + mitkThrowException(SemanticRelationException) << "Not a valid data storage."; + } + + std::vector allImageIDsOfCase = RelationStorage::GetAllImageIDsOfCase(caseID); + std::vector allImagesOfCase; + // get all image nodes of the current data storage + // only those nodes are respected, that are currently held in the data storage + DataStorage::SetOfObjects::ConstPointer imageNodes = m_DataStorage.Lock()->GetSubset(NodePredicates::GetImagePredicate()); + for (auto it = imageNodes->Begin(); it != imageNodes->End(); ++it) + { + DataNode* imageNode = it->Value(); + // find the corresponding image node for the given segmentation ID + std::string nodeCaseID = GetCaseIDFromDataNode(imageNode); + std::string nodeImageID = GetIDFromDataNode(imageNode); + if (nodeCaseID == caseID && (std::find(allImageIDsOfCase.begin(), allImageIDsOfCase.end(), nodeImageID) != allImageIDsOfCase.end())) + { + // found current image node in the storage, add it to the return vector + allImagesOfCase.push_back(imageNode); + } + } + + return allImagesOfCase; +} + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllImagesOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) const +{ + if (m_DataStorage.IsExpired()) + { + mitkThrowException(SemanticRelationException) << "Not a valid data storage."; + } + + DataNodeVector allImagesOfLesion; + // 1. get all segmentations that define the lesion + // 2. retrieve the parent node (source) of the found segmentation node + DataNodeVector allSegmentationsOfLesion = GetAllSegmentationsOfLesion(caseID, lesion); + for (const auto& segmentationNode : allSegmentationsOfLesion) + { + // get parent node of the current segmentation node with the node predicate + DataStorage::SetOfObjects::ConstPointer parentNodes = m_DataStorage.Lock()->GetSources(segmentationNode, NodePredicates::GetImagePredicate(), false); + for (auto it = parentNodes->Begin(); it != parentNodes->End(); ++it) + { + DataNode::Pointer dataNode = it->Value(); + allImagesOfLesion.push_back(it->Value()); + } + } + + std::sort(allImagesOfLesion.begin(), allImagesOfLesion.end()); + allImagesOfLesion.erase(std::unique(allImagesOfLesion.begin(), allImagesOfLesion.end()), allImagesOfLesion.end()); + return allImagesOfLesion; +} + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllSpecificImages(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const +{ + if (SemanticRelationsInference::InstanceExists(caseID, controlPoint)) + { + if (SemanticRelationsInference::InstanceExists(caseID, informationType)) + { + // control point exists, information type exists, retrieve all images from the storage + DataNodeVector allImagesOfCase = GetAllImagesOfCase(caseID); + // filter all images to remove the ones with a different control point and information type using a lambda function + auto lambda = [&controlPoint, &informationType, this](DataNode::Pointer imageNode) + { + return (informationType != SemanticRelationsInference::GetInformationTypeOfImage(imageNode)) + || (controlPoint.date != SemanticRelationsInference::GetControlPointOfImage(imageNode).date); + }; + + allImagesOfCase.erase(std::remove_if(allImagesOfCase.begin(), allImagesOfCase.end(), lambda), allImagesOfCase.end()); + + return allImagesOfCase; + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing information type for the given caseID " << caseID << " and information type " << informationType; + } + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing control point for the given caseID " << caseID << " and control point " << controlPoint.UID; + } +} + +mitk::SemanticRelationsDataStorageAccess::DataNodeVector mitk::SemanticRelationsDataStorageAccess::GetAllSpecificSegmentations(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::InformationType& informationType) const +{ + if (m_DataStorage.IsExpired()) + { + mitkThrow() << "Not a valid data storage."; + } + + DataNodeVector allSpecificImages = GetAllSpecificImages(caseID, controlPoint, informationType); + DataNodeVector allSpecificSegmentations; + for (const auto& imageNode : allSpecificImages) + { + DataStorage::SetOfObjects::ConstPointer segmentationNodes = m_DataStorage.Lock()->GetDerivations(imageNode, NodePredicates::GetSegmentationPredicate(), false); + for (auto it = segmentationNodes->Begin(); it != segmentationNodes->End(); ++it) + { + allSpecificSegmentations.push_back(it->Value()); + } + } + + return allSpecificSegmentations; +} diff --git a/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp index 9f3bdf1d59..3e6174fc76 100644 --- a/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp @@ -1,394 +1,561 @@ /*=================================================================== 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 "mitkSemanticRelationsInference.h" // semantic relations module #include "mitkControlPointManager.h" #include "mitkDICOMHelper.h" #include "mitkNodePredicates.h" #include "mitkRelationStorage.h" #include "mitkSemanticRelationException.h" /************************************************************************/ /* functions to get instances / attributes */ /************************************************************************/ -mitk::SemanticTypes::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID) -{ - return RelationStorage::GetAllLesionsOfCase(caseID); -} - mitk::SemanticTypes::LesionClassVector mitk::SemanticRelationsInference::GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID) { - SemanticTypes::LesionVector allLesionsOfCase = GetAllLesionsOfCase(caseID); + SemanticTypes::LesionVector allLesionsOfCase = RelationStorage::GetAllLesionsOfCase(caseID); SemanticTypes::LesionClassVector allLesionClassesOfCase; for (const auto& lesion : allLesionsOfCase) { allLesionClassesOfCase.push_back(lesion.lesionClass); } // remove duplicate entries auto lessThan = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) { return lesionClassLeft.UID < lesionClassRight.UID; }; auto equal = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) { return lesionClassLeft.UID == lesionClassRight.UID; }; std::sort(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), lessThan); allLesionClassesOfCase.erase(std::unique(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), equal), allLesionClassesOfCase.end()); return allLesionClassesOfCase; } -mitk::SemanticTypes::Lesion mitk::SemanticRelationsInference::GetRepresentedLesion(const DataNode* segmentationNode) +mitk::SemanticTypes::Lesion mitk::SemanticRelationsInference::GetLesionOfSegmentation(const DataNode* segmentationNode) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); + return RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); +} - if (representedLesion.UID.empty()) +mitk::SemanticTypes::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfImage(const DataNode* imageNode) +{ + if (nullptr == imageNode) { - mitkThrowException(SemanticRelationException) << "Could not find a represented lesion instance for the given segmentation node " << segmentationNode->GetName(); + mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } - else + + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); + SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); + + SemanticTypes::LesionVector allLesionsOfImage; + // 1. get all segmentations that are connected to the given image + // 2. get the lesion of each segmentation + // 3. guarantee uniqueness of lesions + SemanticTypes::IDVector allSegmentationIDsOfImage = RelationStorage::GetAllSegmentationIDsOfImage(caseID, imageID); + for (const auto& segmentationID : allSegmentationIDsOfImage) { - return representedLesion; + // get represented lesion of the current segmentation + SemanticTypes::Lesion representedLesion = RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); + if (!representedLesion.UID.empty()) + { + allLesionsOfImage.push_back(representedLesion); + } } + + // remove duplicate entries + auto lessThan = [](const SemanticTypes::Lesion& lesionLeft, const SemanticTypes::Lesion& lesionRight) + { + return lesionLeft.UID < lesionRight.UID; + }; + + auto equal = [](const SemanticTypes::Lesion& lesionLeft, const SemanticTypes::Lesion& lesionRight) + { + return lesionLeft.UID == lesionRight.UID; + }; + + std::sort(allLesionsOfImage.begin(), allLesionsOfImage.end(), lessThan); + allLesionsOfImage.erase(std::unique(allLesionsOfImage.begin(), allLesionsOfImage.end(), equal), allLesionsOfImage.end()); + + return allLesionsOfImage; } -mitk::SemanticTypes::Lesion mitk::SemanticRelationsInference::GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) +mitk::SemanticTypes::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { - SemanticTypes::Lesion representedLesion = RelationStorage::GetRepresentedLesion(caseID, segmentationID); + SemanticTypes::LesionVector allLesions = RelationStorage::GetAllLesionsOfCase(caseID); - if (representedLesion.UID.empty()) + // filter the lesions: use only those, where the associated data is connected to image data that refers to the given control point using a lambda function + auto lambda = [&caseID, &controlPoint](const SemanticTypes::Lesion& lesion) { - mitkThrowException(SemanticRelationException) << "Could not find a represented lesion instance for the given segmentation node ID " << segmentationID; - } - else - { - return representedLesion; - } + return !SpecificImageExists(caseID, lesion, controlPoint); + }; + + allLesions.erase(std::remove_if(allLesions.begin(), allLesions.end(), lambda), allLesions.end()); + + return allLesions; } bool mitk::SemanticRelationsInference::IsRepresentingALesion(const DataNode* segmentationNode) { try { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(segmentationNode); - return true; + SemanticTypes::Lesion representedLesion = GetLesionOfSegmentation(segmentationNode); + if (representedLesion.UID.empty()) + { + return false; + } } catch (const Exception&) { return false; } + + return true; } bool mitk::SemanticRelationsInference::IsRepresentingALesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) { - try - { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); - return true; - } - catch (const Exception&) + SemanticTypes::Lesion representedLesion = RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); + if (representedLesion.UID.empty()) { return false; } + + return true; } -bool mitk::SemanticRelationsInference::IsLesionPresentOnSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& segmentationID) +bool mitk::SemanticRelationsInference::IsLesionPresent(const SemanticTypes::Lesion& lesion, const DataNode* dataNode) { try { - const auto representedLesion = GetRepresentedLesion(caseID, segmentationID); - return lesion.UID == representedLesion.UID; + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); + SemanticTypes::ID dataNodeID = GetIDFromDataNode(dataNode); + + if (NodePredicates::GetImagePredicate()->CheckNode(dataNode)) + { + return IsLesionPresentOnImage(caseID, lesion, dataNodeID); + } + + if (NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) + { + return IsLesionPresentOnSegmentation(caseID, lesion, dataNodeID); + } + + return false; } catch (const SemanticRelationException&) { return false; } } +bool mitk::SemanticRelationsInference::IsLesionPresentOnImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& imageID) +{ + SemanticTypes::IDVector allImageIDsOfLesion = GetAllImageIDsOfLesion(caseID, lesion); + for (const auto& imageIDOfLesion : allImageIDsOfLesion) + { + if (imageIDOfLesion == imageID) + { + return true; + } + } + + return false; +} + +bool mitk::SemanticRelationsInference::IsLesionPresentOnSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& segmentationID) +{ + const auto representedLesion = RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); + return lesion.UID == representedLesion.UID; +} + +bool mitk::SemanticRelationsInference::IsLesionPresentAtControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint) +{ + SemanticTypes::IDVector allImageIDsOfLesion = GetAllImageIDsOfLesion(caseID, lesion); + for (const auto& imageID : allImageIDsOfLesion) + { + auto imageControlPoint = mitk::RelationStorage::GetControlPointOfImage(caseID, imageID); + if (imageControlPoint.date == controlPoint.date) + { + return true; + } + } + + return false; +} + bool mitk::SemanticRelationsInference::InstanceExists(const DataNode* dataNode) { try { SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); SemanticTypes::ID dataNodeID = GetIDFromDataNode(dataNode); if (NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { std::vector allImageIDsOfCase = RelationStorage::GetAllImageIDsOfCase(caseID); return std::find(allImageIDsOfCase.begin(), allImageIDsOfCase.end(), dataNodeID) != allImageIDsOfCase.end(); } else if (NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { std::vector allSegmentationIDsOfCase = RelationStorage::GetAllSegmentationIDsOfCase(caseID); return std::find(allSegmentationIDsOfCase.begin(), allSegmentationIDsOfCase.end(), dataNodeID) != allSegmentationIDsOfCase.end(); } else { return false; } } catch (const SemanticRelationException&) { return false; } } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { - SemanticTypes::LesionVector allLesions = GetAllLesionsOfCase(caseID); + SemanticTypes::LesionVector allLesions = RelationStorage::GetAllLesionsOfCase(caseID); // filter all lesions: check for equality with the given lesion using a lambda function auto lambda = [&lesion](const SemanticTypes::Lesion& currentLesion) { return currentLesion.UID == lesion.UID; }; const auto existingLesion = std::find_if(allLesions.begin(), allLesions.end(), lambda); if (existingLesion != allLesions.end()) { return true; } else { return false; } } -mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { - if (InstanceExists(caseID, lesion)) + if (!InstanceExists(caseID, lesion)) { - // lesion exists, retrieve all case segmentations from the storage - SemanticTypes::IDVector allSegmentationIDs = RelationStorage::GetAllSegmentationIDsOfCase(caseID); + mitkThrowException(SemanticRelationException) << "Could not find an existing lesion instance for the given caseID " << caseID << " and lesion " << lesion.UID << "."; + } - // filter all segmentationIDs: check for semantic relation with the given lesion using a lambda function - auto lambda = [&lesion, caseID](const SemanticTypes::ID& segmentationID) + SemanticTypes::IDVector allImageIDsOfLesion; + // 1. get all segmentations that define the lesion + // 2. get the parentID (imageID) of each segmentation + // 3. guarantee uniqueness of image IDs + SemanticTypes::IDVector allSegmentationIDsOfLesion = GetAllSegmentationIDsOfLesion(caseID, lesion); + for (const auto& segmentationID : allSegmentationIDsOfLesion) + { + // get parent ID of the current segmentation ID + SemanticTypes::ID imageID = RelationStorage::GetImageIDOfSegmentation(caseID, segmentationID); + if(!imageID.empty()) { - try - { - SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); - return lesion.UID != representedLesion.UID; - } - catch (const SemanticRelationException&) - { - return true; - } - }; + allImageIDsOfLesion.push_back(imageID); + } + } - allSegmentationIDs.erase(std::remove_if(allSegmentationIDs.begin(), allSegmentationIDs.end(), lambda), allSegmentationIDs.end()); + std::sort(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()); + allImageIDsOfLesion.erase(std::unique(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()), allImageIDsOfLesion.end()); - return allSegmentationIDs; - } - else + return allImageIDsOfLesion; +} + +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) +{ + if (!InstanceExists(caseID, lesion)) { mitkThrowException(SemanticRelationException) << "Could not find an existing lesion instance for the given caseID " << caseID << " and lesion " << lesion.UID << "."; } -} -mitk::SemanticTypes::ControlPointVector mitk::SemanticRelationsInference::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID) -{ - return RelationStorage::GetAllControlPointsOfCase(caseID); + // lesion exists, retrieve all case segmentations from the storage + SemanticTypes::IDVector allSegmentationIDs = RelationStorage::GetAllSegmentationIDsOfCase(caseID); + + // filter all segmentationIDs: check for semantic relation with the given lesion using a lambda function + auto lambda = [&lesion, caseID](const SemanticTypes::ID& segmentationID) + { + SemanticTypes::Lesion representedLesion = RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); + return lesion.UID != representedLesion.UID; + }; + + allSegmentationIDs.erase(std::remove_if(allSegmentationIDs.begin(), allSegmentationIDs.end(), lambda), allSegmentationIDs.end()); + + return allSegmentationIDs; } mitk::SemanticTypes::ControlPoint mitk::SemanticRelationsInference::GetControlPointOfImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID dataNodeID = GetIDFromDataNode(imageNode); - return GetControlPointOfImage(caseID, dataNodeID); + return RelationStorage::GetControlPointOfImage(caseID, dataNodeID); } -mitk::SemanticTypes::ControlPoint mitk::SemanticRelationsInference::GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) +mitk::SemanticTypes::ControlPointVector mitk::SemanticRelationsInference::GetAllControlPointsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { - return RelationStorage::GetControlPointOfImage(caseID, imageID); -} + SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID); -mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) -{ - if (InstanceExists(caseID, controlPoint)) + // filter the control points: use only those, where the associated image data has a segmentation that refers to the given lesion using a lambda function + auto lambda = [&caseID, &lesion](const SemanticTypes::ControlPoint& controlPoint) { - // control point exists, retrieve all imageIDs from the storage - SemanticTypes::IDVector allImageIDs = RelationStorage::GetAllImageIDsOfCase(caseID); + return !SpecificImageExists(caseID, lesion, controlPoint); + }; - // filter all imageIDs to remove the ones with a different control point using a lambda function - auto lambda = [&controlPoint, &caseID](const SemanticTypes::ID& imageID) - { - return controlPoint.UID != RelationStorage::GetControlPointOfImage(caseID, imageID).UID; - }; + allControlPoints.erase(std::remove_if(allControlPoints.begin(), allControlPoints.end(), lambda), allControlPoints.end()); - allImageIDs.erase(std::remove_if(allImageIDs.begin(), allImageIDs.end(), lambda), allImageIDs.end()); + return allControlPoints; +} - return allImageIDs; - } - else +mitk::SemanticTypes::ControlPointVector mitk::SemanticRelationsInference::GetAllControlPointsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +{ + SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID); + + // filter the control points: use only those, where the associated image data refers to the given information type using a lambda function + auto lambda = [&caseID, &informationType](const SemanticTypes::ControlPoint& controlPoint) { - mitkThrowException(SemanticRelationException) << "Could not find an existing control point instance for the given caseID " << caseID << " and control point " << controlPoint.UID << "."; - } + return !SpecificImageExists(caseID, informationType, controlPoint); + }; + + allControlPoints.erase(std::remove_if(allControlPoints.begin(), allControlPoints.end(), lambda), allControlPoints.end()); + + return allControlPoints; } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { - SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); + SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID); // filter all control points: check for equality with the given control point using a lambda function auto lambda = [&controlPoint](const SemanticTypes::ControlPoint& currentControlPoint) { return currentControlPoint.UID == controlPoint.UID; }; const auto existingControlPoint = std::find_if(allControlPoints.begin(), allControlPoints.end(), lambda); if (existingControlPoint != allControlPoints.end()) { return true; } else { return false; } } mitk::SemanticTypes::ExaminationPeriodVector mitk::SemanticRelationsInference::GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID) { return RelationStorage::GetAllExaminationPeriodsOfCase(caseID); } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) { SemanticTypes::ExaminationPeriodVector allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); // filter all examination periods: check for equality with the given examination period using a lambda function auto lambda = [&examinationPeriod](const SemanticTypes::ExaminationPeriod& currentExaminationPeriod) { return currentExaminationPeriod.UID == examinationPeriod.UID; }; const auto existingExaminationPeriod = std::find_if(allExaminationPeriods.begin(), allExaminationPeriods.end(), lambda); if (existingExaminationPeriod != allExaminationPeriods.end()) { return true; } else { return false; } } -mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelationsInference::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID) -{ - return RelationStorage::GetAllInformationTypesOfCase(caseID); -} - mitk::SemanticTypes::InformationType mitk::SemanticRelationsInference::GetInformationTypeOfImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); return GetInformationTypeOfImage(caseID, imageID); } mitk::SemanticTypes::InformationType mitk::SemanticRelationsInference::GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) { return RelationStorage::GetInformationTypeOfImage(caseID, imageID); } -mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelationsInference::GetAllInformationTypesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { - if (InstanceExists(caseID, informationType)) + SemanticTypes::InformationTypeVector allInformationTypes = RelationStorage::GetAllInformationTypesOfCase(caseID); + + // filter the information types: use only those, where the associated data refers to the given control point using a lambda function + auto lambda = [&caseID, &controlPoint](const SemanticTypes::InformationType& informationType) { - // information type exists, retrieve all imageIDs from the storage - SemanticTypes::IDVector allImageIDs = RelationStorage::GetAllImageIDsOfCase(caseID); + return !SpecificImageExists(caseID, informationType, controlPoint); + }; - // filter all images to remove the ones with a different information type using a lambda function - auto lambda = [&informationType, caseID](const SemanticTypes::ID& imageID) - { - return informationType != RelationStorage::GetInformationTypeOfImage(caseID, imageID); - }; + allInformationTypes.erase(std::remove_if(allInformationTypes.begin(), allInformationTypes.end(), lambda), allInformationTypes.end()); - allImageIDs.erase(std::remove_if(allImageIDs.begin(), allImageIDs.end(), lambda), allImageIDs.end()); + return allInformationTypes; +} - return allImageIDs; - } - else +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +{ + if (InstanceExists(caseID, informationType)) { mitkThrowException(SemanticRelationException) << "Could not find an existing information type for the given caseID " << caseID << " and information type " << informationType; } + + // information type exists, retrieve all imageIDs from the storage + SemanticTypes::IDVector allImageIDs = RelationStorage::GetAllImageIDsOfCase(caseID); + + // filter all images to remove the ones with a different information type using a lambda function + auto lambda = [&informationType, caseID](const SemanticTypes::ID& imageID) + { + return informationType != RelationStorage::GetInformationTypeOfImage(caseID, imageID); + }; + + allImageIDs.erase(std::remove_if(allImageIDs.begin(), allImageIDs.end(), lambda), allImageIDs.end()); + + return allImageIDs; } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) { - SemanticTypes::InformationTypeVector allInformationTypes = GetAllInformationTypesOfCase(caseID); + SemanticTypes::InformationTypeVector allInformationTypes = RelationStorage::GetAllInformationTypesOfCase(caseID); // filter all information types: check for equality with the given information type using a lambda function auto lambda = [&informationType](const SemanticTypes::InformationType& currentInformationType) { return currentInformationType == informationType; }; const auto existingInformationType = std::find_if(allInformationTypes.begin(), allInformationTypes.end(), lambda); if (existingInformationType != allInformationTypes.end()) { return true; } else { return false; } } -std::vector mitk::SemanticRelationsInference::GetAllCaseIDs() +bool mitk::SemanticRelationsInference::SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::InformationType& informationType) +{ + SemanticTypes::IDVector allImageIDsOfLesion; + try + { + allImageIDsOfLesion = GetAllImageIDsOfLesion(caseID, lesion); + } + catch (const SemanticRelationException&) + { + return false; + } + + SemanticTypes::IDVector allImageIDsOfInformationType = RelationStorage::GetAllImageIDsOfInformationType(caseID, informationType); + + std::sort(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()); + std::sort(allImageIDsOfInformationType.begin(), allImageIDsOfInformationType.end()); + SemanticTypes::IDVector allImageIDsIntersection; + // set_intersection removes duplicated nodes, since 'GetAllImageIDsOfInformationType' only contains at most one of each node + std::set_intersection(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end(), + allImageIDsOfInformationType.begin(), allImageIDsOfInformationType.end(), + std::back_inserter(allImageIDsIntersection)); + + // if the vector of intersecting image IDs is empty, the information type does not contain the lesion + return !allImageIDsIntersection.empty(); +} + +bool mitk::SemanticRelationsInference::SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ControlPoint& controlPoint) +{ + SemanticTypes::IDVector allImageIDsOfLesion; + try + { + allImageIDsOfLesion = GetAllImageIDsOfLesion(caseID, lesion); + } + catch (const SemanticRelationException&) + { + return false; + } + + SemanticTypes::IDVector allImageIDsOfControlPoint = RelationStorage::GetAllImageIDsOfControlPoint(caseID, controlPoint); + + std::sort(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()); + std::sort(allImageIDsOfControlPoint.begin(), allImageIDsOfControlPoint.end()); + SemanticTypes::IDVector allImageIDsIntersection; + // set_intersection removes duplicated nodes, since 'GetAllImageIDsOfControlPoint' only contains at most one of each node + std::set_intersection(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end(), + allImageIDsOfControlPoint.begin(), allImageIDsOfControlPoint.end(), + std::back_inserter(allImageIDsIntersection)); + + // if the vector of intersecting image IDs is empty, the control point does not contain the lesion + return !allImageIDsIntersection.empty(); +} + +bool mitk::SemanticRelationsInference::SpecificImageExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType, const SemanticTypes::ControlPoint& controlPoint) { - return RelationStorage::GetAllCaseIDs(); + SemanticTypes::IDVector allImageIDsOfInformationType = RelationStorage::GetAllImageIDsOfInformationType(caseID, informationType); + SemanticTypes::IDVector allImageIDsOfControlPoint = RelationStorage::GetAllImageIDsOfControlPoint(caseID, controlPoint); + + std::sort(allImageIDsOfInformationType.begin(), allImageIDsOfInformationType.end()); + std::sort(allImageIDsOfControlPoint.begin(), allImageIDsOfControlPoint.end()); + SemanticTypes::IDVector allImageIDsIntersection; + // set_intersection removes duplicated nodes + std::set_intersection(allImageIDsOfInformationType.begin(), allImageIDsOfInformationType.end(), + allImageIDsOfControlPoint.begin(), allImageIDsOfControlPoint.end(), + std::back_inserter(allImageIDsIntersection)); + + // if the vector of intersecting image IDs is empty no image exists for the given information type and control point + return !allImageIDsIntersection.empty(); } void mitk::SemanticRelationsInference::ClearControlPoints(const SemanticTypes::CaseID& caseID) { - SemanticTypes::ControlPointVector allControlPointsOfCase = GetAllControlPointsOfCase(caseID); + SemanticTypes::ControlPointVector allControlPointsOfCase = RelationStorage::GetAllControlPointsOfCase(caseID); std::vector allImageIDsVectorValue = RelationStorage::GetAllImageIDsOfCase(caseID); SemanticTypes::ControlPointVector referencedControlPoints; for (const auto& imageID : allImageIDsVectorValue) { - auto controlPointOfImage = GetControlPointOfImage(caseID, imageID); + auto controlPointOfImage = RelationStorage::GetControlPointOfImage(caseID, imageID); referencedControlPoints.push_back(controlPointOfImage); } std::sort(allControlPointsOfCase.begin(), allControlPointsOfCase.end()); std::sort(referencedControlPoints.begin(), referencedControlPoints.end()); SemanticTypes::ControlPointVector nonReferencedControlPoints; std::set_difference(allControlPointsOfCase.begin(), allControlPointsOfCase.end(), referencedControlPoints.begin(), referencedControlPoints.end(), std::inserter(nonReferencedControlPoints, nonReferencedControlPoints.begin())); auto allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); for (const auto& controlPoint : nonReferencedControlPoints) { const auto& examinationPeriod = FindExaminationPeriod(controlPoint, allExaminationPeriods); RelationStorage::RemoveControlPointFromExaminationPeriod(caseID, controlPoint, examinationPeriod); RelationStorage::RemoveControlPointFromCase(caseID, controlPoint); } } diff --git a/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp index 24cd6c93c3..deee49a3ab 100644 --- a/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp @@ -1,446 +1,446 @@ /*=================================================================== 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 "mitkSemanticRelationsIntegration.h" // semantic relations module #include "mitkControlPointManager.h" #include "mitkDICOMHelper.h" #include "mitkNodePredicates.h" #include "mitkRelationStorage.h" #include "mitkSemanticRelationException.h" #include "mitkSemanticRelationsInference.h" #include "mitkUIDGeneratorBoost.h" // multi label module #include // c++ #include #include std::vector mitk::SemanticRelationsIntegration::m_ObserverVector; void mitk::SemanticRelationsIntegration::AddObserver(ISemanticRelationsObserver* observer) { std::vector::iterator existingObserver = std::find(m_ObserverVector.begin(), m_ObserverVector.end(), observer); if (existingObserver != m_ObserverVector.end()) { // no need to add the already existing observer return; } m_ObserverVector.push_back(observer); } void mitk::SemanticRelationsIntegration::RemoveObserver(ISemanticRelationsObserver* observer) { m_ObserverVector.erase(std::remove(m_ObserverVector.begin(), m_ObserverVector.end(), observer), m_ObserverVector.end()); } /************************************************************************/ /* functions to add / remove instances / attributes */ /************************************************************************/ void mitk::SemanticRelationsIntegration::AddImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } // continue with a valid data node SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID nodeID = GetIDFromDataNode(imageNode); RelationStorage::AddCase(caseID); RelationStorage::AddImage(caseID, nodeID); SemanticTypes::InformationType informationType = GetDICOMModalityFromDataNode(imageNode); AddInformationTypeToImage(imageNode, informationType); // set the correct control point for this image SemanticTypes::ControlPoint controlPoint = GenerateControlPoint(imageNode); SetControlPointOfData(imageNode, controlPoint); } void mitk::SemanticRelationsIntegration::RemoveImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } // continue with a valid data node SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID nodeID = GetIDFromDataNode(imageNode); RemoveInformationTypeFromImage(imageNode); UnlinkImageFromControlPoint(imageNode); RelationStorage::RemoveImage(caseID, nodeID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::AddLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { if (SemanticRelationsInference::InstanceExists(caseID, lesion)) { mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to add already exists for the given case."; } else { RelationStorage::AddLesion(caseID, lesion); NotifyObserver(caseID); } } void mitk::SemanticRelationsIntegration::OverwriteLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { if (SemanticRelationsInference::InstanceExists(caseID, lesion)) { RelationStorage::OverwriteLesion(caseID, lesion); NotifyObserver(caseID); } else { mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to overwrite does not exist for the given case."; } } void mitk::SemanticRelationsIntegration::AddLesionAndLinkSegmentation(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); AddLesion(caseID, lesion); LinkSegmentationToLesion(segmentationNode, lesion); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::RemoveLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { if (SemanticRelationsInference::InstanceExists(caseID, lesion)) { SemanticTypes::IDVector allSegmentationIDsOfLesion = SemanticRelationsInference::GetAllSegmentationIDsOfLesion(caseID, lesion); if (allSegmentationIDsOfLesion.empty()) { // no more segmentations are linked to the specific lesion // the lesion can be removed from the storage RelationStorage::RemoveLesion(caseID, lesion); NotifyObserver(caseID); } else { mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to remove is still referred to by a segmentation node. Lesion will not be removed."; } } else { mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to remove does not exist for the given case."; } } void mitk::SemanticRelationsIntegration::AddSegmentation(const DataNode* segmentationNode, const DataNode* parentNode) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } if (nullptr == parentNode) { mitkThrowException(SemanticRelationException) << "Not a valid parent data node."; } // continue with a valid data node SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); SemanticTypes::ID segmentationNodeID = GetIDFromDataNode(segmentationNode); SemanticTypes::ID parentNodeID = GetIDFromDataNode(parentNode); RelationStorage::AddSegmentation(caseID, segmentationNodeID, parentNodeID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::LinkSegmentationToLesion(const DataNode* segmentationNode, const SemanticTypes::Lesion& lesion) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); if (SemanticRelationsInference::InstanceExists(caseID, lesion)) { SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); RelationStorage::LinkSegmentationToLesion(caseID, segmentationID, lesion); NotifyObserver(caseID); } else { mitkThrowException(SemanticRelationException) << "The lesion " << lesion.UID << " to link does not exist for the given case."; } } void mitk::SemanticRelationsIntegration::UnlinkSegmentationFromLesion(const DataNode* segmentationNode) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); RelationStorage::UnlinkSegmentationFromLesion(caseID, segmentationID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::RemoveSegmentation(const DataNode* segmentationNode) { if (nullptr == segmentationNode) { mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; } // continue with a valid data node SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); SemanticTypes::ID segmentationNodeID = GetIDFromDataNode(segmentationNode); RelationStorage::RemoveSegmentation(caseID, segmentationNodeID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::SetControlPointOfData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); SemanticTypes::ControlPointVector allControlPoints = RelationStorage::GetAllControlPointsOfCase(caseID); // need to check if an already existing control point fits/contains the user control point SemanticTypes::ControlPoint existingControlPoint = FindExistingControlPoint(controlPoint, allControlPoints); if (!existingControlPoint.UID.empty()) { try { // found an already existing control point LinkDataToControlPoint(dataNode, existingControlPoint, false); } catch (const SemanticRelationException&) { mitkThrowException(SemanticRelationException) << "The data can not be linked. Inconsistency in the semantic relations storage assumed."; } } else { try { AddControlPointAndLinkData(dataNode, controlPoint, false); // added a new control point // find closest control point to add the new control point to the correct examination period SemanticTypes::ControlPoint closestControlPoint = FindClosestControlPoint(controlPoint, allControlPoints); SemanticTypes::ExaminationPeriodVector allExaminationPeriods = RelationStorage::GetAllExaminationPeriodsOfCase(caseID); SemanticTypes::ExaminationPeriod examinationPeriod = FindExaminationPeriod(closestControlPoint, allExaminationPeriods); if (examinationPeriod.UID.empty()) { // no closest control point (exceed threshold) or no examination period found // create a new examination period for this control point and add it to the storage examinationPeriod.UID = UIDGeneratorBoost::GenerateUID(); examinationPeriod.name = "New examination period " + std::to_string(allExaminationPeriods.size()); AddExaminationPeriod(caseID, examinationPeriod); } // add the control point to the (newly created or found / close) examination period AddControlPointToExaminationPeriod(caseID, controlPoint, examinationPeriod); } catch (const SemanticRelationException&) { mitkThrowException(SemanticRelationException) << "The data can not be linked. Inconsistency in the semantic relations storage assumed."; } } ClearControlPoints(caseID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::AddControlPointAndLinkData(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); if (SemanticRelationsInference::InstanceExists(caseID, controlPoint)) { mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to add already exists for the given case. \n Use 'LinkDataToControlPoint' instead."; } RelationStorage::AddControlPoint(caseID, controlPoint); LinkDataToControlPoint(dataNode, controlPoint, checkConsistence); } void mitk::SemanticRelationsIntegration::LinkDataToControlPoint(const DataNode* dataNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); if (SemanticRelationsInference::InstanceExists(caseID, controlPoint)) { SemanticTypes::ID dataID = GetIDFromDataNode(dataNode); - RelationStorage::LinkDataToControlPoint(caseID, dataID, controlPoint); + RelationStorage::LinkImageToControlPoint(caseID, dataID, controlPoint); } else { mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to link does not exist for the given case."; } } void mitk::SemanticRelationsIntegration::UnlinkImageFromControlPoint(const DataNode* dataNode) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); SemanticTypes::ID dataID = GetIDFromDataNode(dataNode); SemanticTypes::ControlPoint controlPoint = RelationStorage::GetControlPointOfImage(caseID, dataID); - RelationStorage::UnlinkDataFromControlPoint(caseID, dataID); + RelationStorage::UnlinkImageFromControlPoint(caseID, dataID); ClearControlPoints(caseID); } void mitk::SemanticRelationsIntegration::AddExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) { if (SemanticRelationsInference::InstanceExists(caseID, examinationPeriod)) { mitkThrowException(SemanticRelationException) << "The examination period " << examinationPeriod.UID << " to add already exists for the given case."; } else { RelationStorage::AddExaminationPeriod(caseID, examinationPeriod); } } void mitk::SemanticRelationsIntegration::AddControlPointToExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriod& examinationPeriod) { if (!SemanticRelationsInference::InstanceExists(caseID, controlPoint)) { mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to add does not exist for the given case."; } if (!SemanticRelationsInference::InstanceExists(caseID, examinationPeriod)) { mitkThrowException(SemanticRelationException) << "The examination period " << examinationPeriod.UID << " does not exist for the given case. \n Use 'AddExaminationPeriod' before."; } RelationStorage::AddControlPointToExaminationPeriod(caseID, controlPoint, examinationPeriod); } void mitk::SemanticRelationsIntegration::SetInformationType(const DataNode* imageNode, const SemanticTypes::InformationType& informationType) { RemoveInformationTypeFromImage(imageNode); AddInformationTypeToImage(imageNode, informationType); SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::AddInformationTypeToImage(const DataNode* imageNode, const SemanticTypes::InformationType& informationType) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); RelationStorage::AddInformationTypeToImage(caseID, imageID, informationType); } void mitk::SemanticRelationsIntegration::RemoveInformationTypeFromImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); SemanticTypes::InformationType originalInformationType = RelationStorage::GetInformationTypeOfImage(caseID, imageID); RelationStorage::RemoveInformationTypeFromImage(caseID, imageID); // check for further references to the removed information type std::vector allImageIDsVectorValue = RelationStorage::GetAllImageIDsOfCase(caseID); for (const auto& otherImageID : allImageIDsVectorValue) { SemanticTypes::InformationType otherInformationType = RelationStorage::GetInformationTypeOfImage(caseID, otherImageID); if (otherInformationType == originalInformationType) { // found the information type in another image -> cannot remove the information type from the case return; } } // given information type was not referred by any other image of the case -> the information type can be removed from the case RelationStorage::RemoveInformationTypeFromCase(caseID, originalInformationType); } /************************************************************************/ /* private functions */ /************************************************************************/ void mitk::SemanticRelationsIntegration::NotifyObserver(const SemanticTypes::CaseID& caseID) const { for (auto& observer : m_ObserverVector) { observer->Update(caseID); } } void mitk::SemanticRelationsIntegration::ClearControlPoints(const SemanticTypes::CaseID& caseID) { SemanticTypes::ControlPointVector allControlPointsOfCase = RelationStorage::GetAllControlPointsOfCase(caseID); std::vector allImageIDsVectorValue = RelationStorage::GetAllImageIDsOfCase(caseID); SemanticTypes::ControlPointVector referencedControlPoints; for (const auto& imageID : allImageIDsVectorValue) { auto controlPointOfImage = RelationStorage::GetControlPointOfImage(caseID, imageID); referencedControlPoints.push_back(controlPointOfImage); } std::sort(allControlPointsOfCase.begin(), allControlPointsOfCase.end()); std::sort(referencedControlPoints.begin(), referencedControlPoints.end()); SemanticTypes::ControlPointVector nonReferencedControlPoints; std::set_difference(allControlPointsOfCase.begin(), allControlPointsOfCase.end(), referencedControlPoints.begin(), referencedControlPoints.end(), std::inserter(nonReferencedControlPoints, nonReferencedControlPoints.begin())); auto allExaminationPeriods = RelationStorage::GetAllExaminationPeriodsOfCase(caseID); for (const auto& controlPoint : nonReferencedControlPoints) { const auto& examinationPeriod = FindExaminationPeriod(controlPoint, allExaminationPeriods); RelationStorage::RemoveControlPointFromExaminationPeriod(caseID, controlPoint, examinationPeriod); RelationStorage::RemoveControlPointFromCase(caseID, controlPoint); } } diff --git a/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h b/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h index 2c1abaf1ae..b2e4ac65ad 100644 --- a/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkAbstractSemanticRelationsStorageModel.h @@ -1,116 +1,119 @@ /*=================================================================== 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 QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H #define QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H // mitk semantic relations UI #include "MitkSemanticRelationsUIExports.h" // semantic relations module #include -#include +#include +#include #include // qt widgets module #include "QmitkAbstractDataStorageModel.h" /* * @brief The QmitkAbstractSemanticRelationsStorageModel is a subclass of 'QmitkAbstractDataStorageModel' and provides additional * functionality to set and store a semantic relations instance, the current case ID and the current lesion. */ class MITKSEMANTICRELATIONSUI_EXPORT QmitkAbstractSemanticRelationsStorageModel : public QmitkAbstractDataStorageModel, public mitk::ISemanticRelationsObserver { Q_OBJECT public: QmitkAbstractSemanticRelationsStorageModel(QObject* parent = nullptr); virtual ~QmitkAbstractSemanticRelationsStorageModel(); /* - * @brief Updates this model with the data from the semantic relations. + * @brief Update this model with the data from the semantic relations. * * Overridden from 'ISemanticRelationsObserver'. * In order for the Update-function to be called, this model has to be added as a observer of SemanticRelation * (e.g. m_SemanticRelations->AddObserver(m_SemanticRelationsStorageModel);) * * @par caseID The current case ID to identify the currently active patient / case. */ virtual void Update(const mitk::SemanticTypes::CaseID& caseID) override; - std::shared_ptr GetSemanticRelations() const { return m_SemanticRelations; } /** - * @brief Sets the current case ID which is needed to access the semantic relations storage. + * @brief Set the current case ID which is needed to access the semantic relations storage. * * @param caseID A case ID as string */ void SetCaseID(const mitk::SemanticTypes::CaseID& caseID); const mitk::SemanticTypes::CaseID& GetCaseID() const { return m_CaseID; } /** - * @brief Sets the current lesion which can be used to show on which images the lesion is visible. + * @brief Set the current lesion which can be used to show on which images the lesion is visible. * * @param lesion The selected lesion */ void SetLesion(const mitk::SemanticTypes::Lesion& lesion); const mitk::SemanticTypes::Lesion& GetLesion() const { return m_Lesion; } /** - * @brief Sets the current data node selection which can be used to show which lesions + * @brief Set the current data node selection which can be used to show which lesions * are visible on the node selection. * * @param dataNodeSelection The selected data nodes */ void SetDataNodeSelection(const QList& dataNodeSelection); const QList& GetSelectedDataNodes() const { return m_SelectedDataNodes; }; /* - * @brief Updates the semantic relations storage model with the current data from the semantic relations model, + * @brief Update the semantic relations storage model with the current data from the semantic relations model, * if the case ID is equal to the currently selected case ID of the table model. */ void UpdateModelData(const mitk::SemanticTypes::CaseID& caseID); /* - * @brief Updates the semantic relations storage model with the current data from the semantic relations model + * @brief Update the semantic relations storage model with the current data from the semantic relations model * and the current case ID. */ void UpdateModelData(); Q_SIGNALS: void ModelUpdated(); protected: /** - * @brief Creates a new 'SemanticRelations' instance with the new data storage and updates the model data. + * @brief Create a new 'SemanticRelationsDataStorageAccess' instance with the new data storage and + * update the model data. * This functions is called inside the 'SetDataStorage'-function from the parent class. */ virtual void DataStorageChanged() override; /** * @brief This function is called if the model data is updated. It can be used by subclasses to define * the way the data of a specific model is generated. It typically consists of access to the * semantic relations storage to retrieve certain information. */ virtual void SetData() = 0; - std::shared_ptr m_SemanticRelations; + std::unique_ptr m_SemanticRelationsDataStorageAccess; + std::unique_ptr m_SemanticRelationsIntegration; + mitk::SemanticTypes::CaseID m_CaseID; QList m_SelectedDataNodes; mitk::SemanticTypes::Lesion m_Lesion; }; #endif // QMITKABSTRACTSEMANTICRELATIONSSTORAGEMODEL_H diff --git a/Modules/SemanticRelationsUI/include/QmitkLesionTreeModel.h b/Modules/SemanticRelationsUI/include/QmitkLesionTreeModel.h index 0cb6979447..d130c4d94f 100644 --- a/Modules/SemanticRelationsUI/include/QmitkLesionTreeModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkLesionTreeModel.h @@ -1,98 +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 QMITKLESIONTREEMODEL_H #define QMITKLESIONTREEMODEL_H // mitk semantic relations UI #include "MitkSemanticRelationsUIExports.h" #include "QmitkAbstractSemanticRelationsStorageModel.h" #include "QmitkLesionTreeItem.h" // c++ #include /* * @brief */ class MITKSEMANTICRELATIONSUI_EXPORT QmitkLesionTreeModel : public QmitkAbstractSemanticRelationsStorageModel { Q_OBJECT public: /** * @brief Initialize the root item of the model. The root item does not have a parent item. */ QmitkLesionTreeModel(QObject* parent = nullptr); ~QmitkLesionTreeModel(); ////////////////////////////////////////////////////////////////////////// // overridden virtual functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// virtual QModelIndex index(int row, int column, const QModelIndex& itemIndex = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex& itemIndex) const override; virtual int rowCount(const QModelIndex& itemIndex = QModelIndex()) const override; virtual int columnCount(const QModelIndex& itemIndex = QModelIndex()) const override; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; ////////////////////////////////////////////////////////////////////////// // end override ////////////////////////////////////////////////////////////////////////// protected: // the following functions have to be overridden but are not implemented in this model - virtual void NodePredicateChanged() override; - virtual void NodeAdded(const mitk::DataNode* node) override; - virtual void NodeChanged(const mitk::DataNode* node) override; - virtual void NodeRemoved(const mitk::DataNode* node) override; + virtual void NodePredicateChanged() override { } + virtual void NodeAdded(const mitk::DataNode* node) override { } + virtual void NodeChanged(const mitk::DataNode* node) override { } + virtual void NodeRemoved(const mitk::DataNode* node) override { } /** * @brief Overridden from 'QmitkAbstractSemanticRelationsStorageModel': This function retrieves all control points * of the current case and stores them to define the header of the tree. * Furthermore all lesions are retrieved and the lesion data is stored and show in the tree view. */ virtual void SetData() override; private: void SetLesionData(); void AddLesion(const mitk::SemanticTypes::Lesion& lesion); void SetSelectedDataNodesPresence(); /** * @brief The function uses the ID of the lesion to see if a data node presence was already set. * If not, the given bool value is used and stored inside a member variable. If the lesion presence * was already set, it will be overwritten. * The function is used by the 'SetSelectedDataNodesPresence' function. * * @param lesion The lesion whose data node presence should be set * @param dataNodePresence The bool value that defines the data node presence of the given lesion */ void SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence); QmitkLesionTreeItem* GetItemByIndex(const QModelIndex& index) const; std::map m_DataNodePresence; std::shared_ptr m_RootItem; mitk::SemanticTypes::ControlPointVector m_ControlPoints; mitk::SemanticTypes::LesionVector m_CurrentLesions; }; #endif // QMITKLESIONTREEMODEL_H diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h index 1a625045f8..57d5780ce7 100644 --- a/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h +++ b/Modules/SemanticRelationsUI/include/QmitkPatientTableInspector.h @@ -1,91 +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 QMITKPATIENTTABLEINSPECTOR_H #define QMITKPATIENTTABLEINSPECTOR_H // semantic relations UI module #include "MitkSemanticRelationsUIExports.h" #include "QmitkAbstractSemanticRelationsStorageInspector.h" #include "QmitkPatientTableModel.h" #include "QmitkTableItemThumbnailDelegate.h" #include "ui_QmitkPatientTableInspector.h" // qt widgets module #include // qt #include /* * @brief The QmitkPatientTableInspector is a QmitkAbstractSemanticRelationsStorageInspector that shows the currently * available data of the semantic relations storage model in a control-point - information type matrix. * * The QmitkPatientTableInspector uses the QmitkSemanticRelationsStorageModel, a QmitkAbstractDataStorageModel that * presents the semantic relations data as a table, showing a QPixmap as thumbnail for the data nodes. */ class MITKSEMANTICRELATIONSUI_EXPORT QmitkPatientTableInspector : public QmitkAbstractSemanticRelationsStorageInspector { Q_OBJECT public: QmitkPatientTableInspector(QWidget* parent = nullptr); virtual QAbstractItemView* GetView() override; virtual const QAbstractItemView* GetView() const override; virtual void SetSelectionMode(SelectionMode mode) override; virtual SelectionMode GetSelectionMode() const override; virtual void SetCaseID(const mitk::SemanticTypes::CaseID& caseID) override; virtual void SetLesion(const mitk::SemanticTypes::Lesion& lesion) override; QItemSelectionModel* GetSelectionModel(); Q_SIGNALS: void DataNodeDoubleClicked(const mitk::DataNode*); void OnContextMenuRequested(const QPoint&); void OnNodeRemoved(const mitk::DataNode*); private Q_SLOTS: void OnModelUpdated(); void OnNodeButtonClicked(const QString&); void OnDataNodeSelectionChanged(const QList&); void OnItemDoubleClicked(const QModelIndex&); protected: virtual void Initialize() override; private: void SetUpConnections(); virtual void keyPressEvent(QKeyEvent* e) override; Ui::QmitkPatientTableInspector m_Controls; QmitkPatientTableModel* m_StorageModel; QmitkTableItemThumbnailDelegate* m_ItemDelegate; - mitk::DataNode* m_SelectedDataNode; - }; #endif // QMITKPATIENTTABLEINSPECTOR_H diff --git a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h index a63d0ab83b..b32290bf37 100644 --- a/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h +++ b/Modules/SemanticRelationsUI/include/QmitkPatientTableModel.h @@ -1,132 +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. ===================================================================*/ #ifndef QMITKPATIENTTABLEMODEL_H #define QMITKPATIENTTABLEMODEL_H // semantic relations UI module #include "QmitkAbstractSemanticRelationsStorageModel.h" // semantic relations module #include +#include // mitk core #include // qt #include #include /** * @brief The QmitkPatientTableModel is a subclass of the QmitkAbstractSemanticRelationsStorageModel and holds the semantic relations data of the currently selected case. * * The QmitkPatientTableModel uses the 'data' function to return either the data node of a table cell or the thumbnail of the underlying image. * The horizontal header of the table shows the control points of the current case and the vertical header of the table shows the information types of the current case. * Using the 'GetFilteredData'-function of the SemanticRelations-class the model is able to retrieve the correct data node for each table entry. * * Additionally the model creates and holds the QPixmaps of the known data nodes in order to return a thumbnail, if needed. */ class QmitkPatientTableModel : public QmitkAbstractSemanticRelationsStorageModel { Q_OBJECT public: QmitkPatientTableModel(QObject* parent = nullptr); ~QmitkPatientTableModel(); ////////////////////////////////////////////////////////////////////////// // overridden functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; virtual QModelIndex parent(const QModelIndex& child) const override; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override; virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; virtual Qt::ItemFlags flags(const QModelIndex& index) const override; ////////////////////////////////////////////////////////////////////////// /// end override ///////////////////////////////////////////////////////////////////////// void SetNodeType(const std::string& nodeType); protected: - // the following functions have to be overridden but are not implemented in this model + // the following functions have to be overridden... virtual void NodePredicateChanged() override; - virtual void NodeAdded(const mitk::DataNode* node) override; - virtual void NodeChanged(const mitk::DataNode* node) override; - virtual void NodeRemoved(const mitk::DataNode* node) override; + // but are not implemented in this model + virtual void NodeAdded(const mitk::DataNode* node) override { } + virtual void NodeChanged(const mitk::DataNode* node) override { } + virtual void NodeRemoved(const mitk::DataNode* node) override { } /** * @brief Overridden from 'QmitkAbstractSemanticRelationsStorageModel': This function retrieves all control points * and information types of the current case and stores them to define the header of the table. * Furthermore all images are retrieved and the pixmap of the images are generated and stored. */ virtual void SetData() override; private: void SetHeaderModel(); void SetPixmaps(); void SetLesionPresences(); /** * @brief The function uses the ID of the node to see if a pixmap was already set. If not, the given pixmap * is used and stored inside a member variable. If the pixmap was already set, it will be overwritten. * Using 'nullptr' as a pixmap will erase the entry for the given data node. * * @param dataNode The data node whose pixmap should be set * @param pixmapFromImage The pixmap that shows an image of the content of the data node */ void SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage); /** * @brief The function uses the ID of the node to see if a lesion presence was already set. If not, the given * bool value is used and stored inside a member variable. If the lesion presence was already set, it * will be overwritten. * The function is used by the 'SetLesionPresences' function. * * @param dataNode The data node whose lesion presence should be set * @param lesionPresence The bool value that defines the lesion presence of the given data node */ void SetLesionPresenceOfNode(const mitk::DataNode* dataNode, bool lesionPresence); /** * @brief Returns the data node that is associated with the given table entry (index). * * The function uses the SemanticRelations-class and the current control point data and information type data to * filter the nodes of the current case. * The index is used to access the correct row in the table (information type) and the correct column in the table (control point). * * @par index The QModelIndex of the table entry */ mitk::DataNode* GetCurrentDataNode(const QModelIndex &index) const; std::map m_PixmapMap; std::map m_LesionPresence; mitk::SemanticTypes::InformationTypeVector m_InformationTypes; mitk::SemanticTypes::ControlPointVector m_ControlPoints; mitk::SemanticTypes::ExaminationPeriodVector m_ExaminationPeriods; - mitk::SemanticRelations::DataNodeVector m_CurrentDataNodes; + mitk::SemanticRelationsDataStorageAccess::DataNodeVector m_CurrentDataNodes; std::string m_SelectedNodeType; QStandardItemModel* m_HeaderModel; }; #endif // QMITKPATIENTTABLEMODEL_H diff --git a/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp b/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp index c1b112a0e2..8b973ef1db 100644 --- a/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkAbstractSemanticRelationsStorageModel.cpp @@ -1,95 +1,90 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations UI module #include "QmitkAbstractSemanticRelationsStorageModel.h" #include "QmitkCustomVariants.h" QmitkAbstractSemanticRelationsStorageModel::QmitkAbstractSemanticRelationsStorageModel(QObject* parent /*= nullptr*/) : QmitkAbstractDataStorageModel(parent) - , m_SemanticRelations(nullptr) + , m_SemanticRelationsDataStorageAccess(nullptr) { - // nothing here + m_SemanticRelationsIntegration = std::make_unique(); + m_SemanticRelationsIntegration->AddObserver(this); } QmitkAbstractSemanticRelationsStorageModel::~QmitkAbstractSemanticRelationsStorageModel() { - if (nullptr != m_SemanticRelations) + if (nullptr != m_SemanticRelationsIntegration) { - m_SemanticRelations->RemoveObserver(this); + m_SemanticRelationsIntegration->RemoveObserver(this); } } void QmitkAbstractSemanticRelationsStorageModel::Update(const mitk::SemanticTypes::CaseID& caseID) { UpdateModelData(caseID); } void QmitkAbstractSemanticRelationsStorageModel::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) { m_CaseID = caseID; UpdateModelData(); } void QmitkAbstractSemanticRelationsStorageModel::SetLesion(const mitk::SemanticTypes::Lesion& lesion) { m_Lesion = lesion; UpdateModelData(); } void QmitkAbstractSemanticRelationsStorageModel::SetDataNodeSelection(const QList& dataNodeSelection) { m_SelectedDataNodes = dataNodeSelection; UpdateModelData(); } void QmitkAbstractSemanticRelationsStorageModel::UpdateModelData(const mitk::SemanticTypes::CaseID& caseID) { // if the case ID of updated instance is equal to the currently active caseID if (caseID == m_CaseID) { UpdateModelData(); } } void QmitkAbstractSemanticRelationsStorageModel::UpdateModelData() { - if (nullptr == m_SemanticRelations) + if (nullptr == m_SemanticRelationsDataStorageAccess) { return; } // update the model, so that the table will be filled with the new patient information beginResetModel(); SetData(); endResetModel(); emit ModelUpdated(); } void QmitkAbstractSemanticRelationsStorageModel::DataStorageChanged() { - if (nullptr != m_SemanticRelations) - { - m_SemanticRelations->RemoveObserver(this); - } - - m_SemanticRelations = std::make_shared(m_DataStorage.Lock()); - m_SemanticRelations->AddObserver(this); + m_SemanticRelationsDataStorageAccess = std::make_unique(m_DataStorage.Lock()); UpdateModelData(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp index cf39b6510c..d1a23715e0 100644 --- a/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkLesionTreeModel.cpp @@ -1,326 +1,303 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations UI module #include "QmitkLesionTreeModel.h" // semantic relations module #include #include #include +#include +#include // qt #include QmitkLesionTreeModel::QmitkLesionTreeModel(QObject* parent/* = nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_RootItem(std::make_shared(mitk::LesionData())) { // nothing here } QmitkLesionTreeModel::~QmitkLesionTreeModel() { // nothing here } ////////////////////////////////////////////////////////////////////////// // overridden virtual functions from QAbstractItemModel ////////////////////////////////////////////////////////////////////////// QModelIndex QmitkLesionTreeModel::index(int row, int column, const QModelIndex& itemIndex) const { if (!hasIndex(row, column, itemIndex)) { return QModelIndex(); } auto childItem = GetItemByIndex(itemIndex)->GetChildInRow(row); if (nullptr == childItem) { return QModelIndex(); } return createIndex(row, column, childItem.get()); } QModelIndex QmitkLesionTreeModel::parent(const QModelIndex& itemIndex) const { if (!itemIndex.isValid()) { return QModelIndex(); } auto parentItem = GetItemByIndex(itemIndex)->GetParent(); if (parentItem.expired()) { return QModelIndex(); } auto sharedParent = parentItem.lock(); if (sharedParent == m_RootItem) { return QModelIndex(); } return createIndex(sharedParent->GetRow(), 0, sharedParent.get()); } int QmitkLesionTreeModel::rowCount(const QModelIndex& itemIndex/* = QModelIndex()*/) const { return GetItemByIndex(itemIndex)->ChildCount(); } int QmitkLesionTreeModel::columnCount(const QModelIndex&/* itemIndex = QModelIndex() */) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display columns return 0; } return m_ControlPoints.size() + 1; } QVariant QmitkLesionTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.column() < 0 || index.column() > static_cast(m_ControlPoints.size())) { return QVariant(); } QmitkLesionTreeItem* currentItem = GetItemByIndex(index); if (Qt::DisplayRole == role) { if (currentItem->GetParent().expired()) { return QVariant(); } auto parentItem = currentItem->GetParent().lock(); // parent exists and is the root item -> 1. item of a lesion entry if (m_RootItem == parentItem) { // display role fills the first columns with the lesion UID / name if (0 == index.column()) { std::string itemString = currentItem->GetData().GetLesionName(); if (itemString.empty()) { itemString = currentItem->GetData().GetLesionUID(); } return QString::fromStdString(itemString); } else { // display role fills other columns with the lesion presence info const auto lesionPresence = currentItem->GetData().GetLesionPresence(); if (index.column() - 1 > static_cast(lesionPresence.size())) { return ""; } return QVariant(lesionPresence.at(index.column() - 1)); } } // parent is not the root item -> 2. item of a lesion entry else { // display role fills the first columns with the property name "Volume" if (0 == index.column()) { return "Volume"; } else { // display role fills other columns with the lesion volume info const auto lesionVolume= currentItem->GetData().GetLesionVolume(); if (index.column() - 1 > static_cast(lesionVolume.size())) { return ""; } return QVariant(lesionVolume.at(index.column() - 1)); } } } if (Qt::BackgroundColorRole == role) { auto it = m_DataNodePresence.find(currentItem->GetData().GetLesion().UID); if (it != m_DataNodePresence.end()) { return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent)); } return QVariant(QColor(Qt::transparent)); } if (Qt::UserRole == role) { return QVariant::fromValue(currentItem); } return QVariant(); } QVariant QmitkLesionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (0 == m_RootItem->ChildCount()) { // no lesion items stored, no need to display the header return QVariant(); } if (Qt::Horizontal == orientation && Qt::DisplayRole == role) { if (0 == section) { return QVariant("Lesion"); } if (m_ControlPoints.size() >= section) { mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(section-1); return QVariant(QString::fromStdString(currentControlPoint.ToString())); } } return QVariant(); } -void QmitkLesionTreeModel::NodePredicateChanged() -{ - // does not react to node predicate changes -} - -void QmitkLesionTreeModel::NodeAdded(const mitk::DataNode* node) -{ - // does not react to data storage changes -} - -void QmitkLesionTreeModel::NodeChanged(const mitk::DataNode* node) -{ - // does not react to data storage changes -} - -void QmitkLesionTreeModel::NodeRemoved(const mitk::DataNode* node) -{ - // does not react to data storage changes -} - void QmitkLesionTreeModel::SetData() { m_RootItem = std::make_shared(mitk::LesionData()); // get all control points of current case - m_ControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(m_CaseID); + m_ControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(m_CaseID); // sort the vector of control points for the timeline std::sort(m_ControlPoints.begin(), m_ControlPoints.end()); SetLesionData(); SetSelectedDataNodesPresence(); } void QmitkLesionTreeModel::SetLesionData() { - m_CurrentLesions = m_SemanticRelations->GetAllLesionsOfCase(m_CaseID); + m_CurrentLesions = mitk::RelationStorage::GetAllLesionsOfCase(m_CaseID); for (auto& lesion : m_CurrentLesions) { AddLesion(lesion); } } void QmitkLesionTreeModel::AddLesion(const mitk::SemanticTypes::Lesion& lesion) { - if (nullptr == m_SemanticRelations) - { - return; - } - // create new lesion tree item data and modify it according to the control point data mitk::LesionData lesionData(lesion); - mitk::GenerateAdditionalLesionData(lesionData, m_CaseID, m_SemanticRelations); + mitk::GenerateAdditionalLesionData(lesionData, m_CaseID); // add the 1. level lesion item to the root item std::shared_ptr newLesionTreeItem = std::make_shared(lesionData); m_RootItem->AddChild(newLesionTreeItem); // add the 2. level lesion item to the 1. level lesion item std::shared_ptr newChildItem = std::make_shared(lesionData); newLesionTreeItem->AddChild(newChildItem); } void QmitkLesionTreeModel::SetSelectedDataNodesPresence() { m_DataNodePresence.clear(); for (const auto& dataNode : m_SelectedDataNodes) { - if (!m_SemanticRelations->InstanceExists(dataNode)) + if (!mitk::SemanticRelationsInference::InstanceExists(dataNode)) { continue; } for (const auto& lesion : m_CurrentLesions) { - if (!m_SemanticRelations->InstanceExists(m_CaseID, lesion)) + if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion)) { continue; } try { // set the lesion presence for the current node - bool dataNodePresence = m_SemanticRelations->IsLesionPresentOnDataNode(lesion, dataNode); + bool dataNodePresence = mitk::SemanticRelationsInference::IsLesionPresent(lesion, dataNode); SetDataNodePresenceOfLesion(&lesion, dataNodePresence); } catch (const mitk::SemanticRelationException&) { continue; } } } } void QmitkLesionTreeModel::SetDataNodePresenceOfLesion(const mitk::SemanticTypes::Lesion* lesion, bool dataNodePresence) { std::map::iterator iter = m_DataNodePresence.find(lesion->UID); if (iter != m_DataNodePresence.end()) { // key already existing, overwrite already stored bool value iter->second = dataNodePresence; } else { m_DataNodePresence.insert(std::make_pair(lesion->UID, dataNodePresence)); } } QmitkLesionTreeItem* QmitkLesionTreeModel::GetItemByIndex(const QModelIndex& index) const { if (index.isValid()) { auto item = static_cast(index.internalPointer()); if (nullptr != item) { return item; } } return m_RootItem.get(); } diff --git a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp index 4509f76a69..1134f56d5d 100644 --- a/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp +++ b/Modules/SemanticRelationsUI/src/QmitkPatientTableModel.cpp @@ -1,358 +1,344 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations UI module #include "QmitkPatientTableModel.h" #include "QmitkPatientTableHeaderView.h" #include "QmitkSemanticRelationsUIHelper.h" // semantic relations module #include #include #include +#include +#include #include #include // qt #include // c++ #include #include QmitkPatientTableModel::QmitkPatientTableModel(QObject* parent /*= nullptr*/) : QmitkAbstractSemanticRelationsStorageModel(parent) , m_SelectedNodeType("Image") { m_HeaderModel = new QStandardItemModel(this); } QmitkPatientTableModel::~QmitkPatientTableModel() { // nothing here } QModelIndex QmitkPatientTableModel::index(int row, int column, const QModelIndex& parent/* = QModelIndex()*/) const { if (hasIndex(row, column, parent)) { return createIndex(row, column); } return QModelIndex(); } QModelIndex QmitkPatientTableModel::parent(const QModelIndex& child) const { return QModelIndex(); } int QmitkPatientTableModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const { if (parent.isValid()) { return 0; } return m_InformationTypes.size(); } int QmitkPatientTableModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const { return m_ControlPoints.size(); } QVariant QmitkPatientTableModel::data(const QModelIndex& index, int role/* = Qt::DisplayRole*/) const { // special role for returning the horizontal header if (QmitkPatientTableHeaderView::HorizontalHeaderDataRole == role) { return QVariant::fromValue(m_HeaderModel); } if (!index.isValid()) { return QVariant(); } if (index.row() < 0 || index.row() >= static_cast(m_InformationTypes.size()) || index.column() < 0 || index.column() >= static_cast(m_ControlPoints.size())) { return QVariant(); } mitk::DataNode* dataNode = GetCurrentDataNode(index); if (nullptr == dataNode) { return QVariant(); } if (Qt::DecorationRole == role) { auto it = m_PixmapMap.find(dataNode); if (it != m_PixmapMap.end()) { return QVariant(it->second); } } if (QmitkDataNodeRole == role) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } if (QmitkDataNodeRawPointerRole == role) { return QVariant::fromValue(dataNode); } if (Qt::BackgroundColorRole == role) { auto it = m_LesionPresence.find(dataNode); if (it != m_LesionPresence.end()) { return it->second ? QVariant(QColor(Qt::darkGreen)) : QVariant(QColor(Qt::transparent)); } return QVariant(QColor(Qt::transparent)); } return QVariant(); } QVariant QmitkPatientTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (Qt::Vertical == orientation && Qt::DisplayRole == role) { if (m_InformationTypes.size() > section) { mitk::SemanticTypes::InformationType currentInformationType = m_InformationTypes.at(section); return QVariant(QString::fromStdString(currentInformationType)); } } return QVariant(); } Qt::ItemFlags QmitkPatientTableModel::flags(const QModelIndex& index) const { Qt::ItemFlags flags; mitk::DataNode* dataNode = GetCurrentDataNode(index); if (nullptr != dataNode) { flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; } return flags; } void QmitkPatientTableModel::SetNodeType(const std::string& nodeType) { m_SelectedNodeType = nodeType; UpdateModelData(); } void QmitkPatientTableModel::NodePredicateChanged() { UpdateModelData(); } -void QmitkPatientTableModel::NodeAdded(const mitk::DataNode* node) -{ - // does not react to data storage changes -} - -void QmitkPatientTableModel::NodeChanged(const mitk::DataNode* node) -{ - // nothing here, since the "'NodeChanged'-event is currently sent far too often - //UpdateModelData(); -} - -void QmitkPatientTableModel::NodeRemoved(const mitk::DataNode* node) -{ - // does not react to data storage changes -} - void QmitkPatientTableModel::SetData() { // get all control points of current case - m_ControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(m_CaseID); + m_ControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(m_CaseID); // sort the vector of control points for the timeline std::sort(m_ControlPoints.begin(), m_ControlPoints.end()); // get all examination periods of current case - m_ExaminationPeriods = m_SemanticRelations->GetAllExaminationPeriodsOfCase(m_CaseID); + m_ExaminationPeriods = mitk::RelationStorage::GetAllExaminationPeriodsOfCase(m_CaseID); // sort the vector of examination periods for the timeline mitk::SortExaminationPeriods(m_ExaminationPeriods, m_ControlPoints); // get all information types points of current case - m_InformationTypes = m_SemanticRelations->GetAllInformationTypesOfCase(m_CaseID); + m_InformationTypes = mitk::RelationStorage::GetAllInformationTypesOfCase(m_CaseID); if ("Image" == m_SelectedNodeType) { - m_CurrentDataNodes = m_SemanticRelations->GetAllImagesOfCase(m_CaseID); + m_CurrentDataNodes = m_SemanticRelationsDataStorageAccess->GetAllImagesOfCase(m_CaseID); } else if ("Segmentation" == m_SelectedNodeType) { - m_CurrentDataNodes = m_SemanticRelations->GetAllSegmentationsOfCase(m_CaseID); + m_CurrentDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSegmentationsOfCase(m_CaseID); } SetHeaderModel(); SetPixmaps(); SetLesionPresences(); } void QmitkPatientTableModel::SetHeaderModel() { m_HeaderModel->clear(); QStandardItem* rootItem = new QStandardItem("Timeline"); QList standardItems; for (const auto& examinationPeriod : m_ExaminationPeriods) { QStandardItem* examinationPeriodItem = new QStandardItem(QString::fromStdString(examinationPeriod.name)); standardItems.push_back(examinationPeriodItem); rootItem->appendColumn(standardItems); standardItems.clear(); const auto& currentControlPoints = examinationPeriod.controlPointUIDs; for (const auto& controlPointUID : currentControlPoints) { const auto& controlPoint = mitk::GetControlPointByUID(controlPointUID, m_ControlPoints); QStandardItem* controlPointItem = new QStandardItem(QString::fromStdString(controlPoint.ToString())); standardItems.push_back(controlPointItem); examinationPeriodItem->appendColumn(standardItems); standardItems.clear(); } } m_HeaderModel->setItem(0, 0, rootItem); } void QmitkPatientTableModel::SetPixmaps() { m_PixmapMap.clear(); for (const auto& dataNode : m_CurrentDataNodes) { // set the pixmap for the current node QPixmap pixmapFromImage = QmitkSemanticRelationsUIHelper::GetPixmapFromImageNode(dataNode); SetPixmapOfNode(dataNode, &pixmapFromImage); } } void QmitkPatientTableModel::SetPixmapOfNode(const mitk::DataNode* dataNode, QPixmap* pixmapFromImage) { if (nullptr == dataNode) { return; } std::map::iterator iter = m_PixmapMap.find(dataNode); if (iter != m_PixmapMap.end()) { // key already existing if (nullptr != pixmapFromImage) { // overwrite already stored pixmap iter->second = pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio); } else { // remove key if no pixmap is given m_PixmapMap.erase(iter); } } else { m_PixmapMap.insert(std::make_pair(dataNode, pixmapFromImage->scaled(120, 120, Qt::IgnoreAspectRatio))); } } void QmitkPatientTableModel::SetLesionPresences() { m_LesionPresence.clear(); - if (!m_SemanticRelations->InstanceExists(m_CaseID, m_Lesion)) + if (!mitk::SemanticRelationsInference::InstanceExists(m_CaseID, m_Lesion)) { return; } for (const auto& dataNode : m_CurrentDataNodes) { - if (!m_SemanticRelations->InstanceExists(dataNode)) + if (!mitk::SemanticRelationsInference::InstanceExists(dataNode)) { continue; } try { // set the lesion presence for the current node - bool lesionPresence = m_SemanticRelations->IsLesionPresentOnDataNode(m_Lesion, dataNode); + bool lesionPresence = mitk::SemanticRelationsInference::IsLesionPresent(m_Lesion, dataNode); SetLesionPresenceOfNode(dataNode, lesionPresence); } catch (const mitk::SemanticRelationException&) { continue; } } } void QmitkPatientTableModel::SetLesionPresenceOfNode(const mitk::DataNode* dataNode, bool lesionPresence) { std::map::iterator iter = m_LesionPresence.find(dataNode); if (iter != m_LesionPresence.end()) { // key already existing, overwrite already stored bool value iter->second = lesionPresence; } else { m_LesionPresence.insert(std::make_pair(dataNode, lesionPresence)); } } mitk::DataNode* QmitkPatientTableModel::GetCurrentDataNode(const QModelIndex& index) const { if (!index.isValid()) { return nullptr; } mitk::SemanticTypes::ControlPoint currentControlPoint = m_ControlPoints.at(index.column()); mitk::SemanticTypes::InformationType currentInformationType = m_InformationTypes.at(index.row()); try { std::vector filteredDataNodes; if ("Image" == m_SelectedNodeType) { - filteredDataNodes = m_SemanticRelations->GetAllSpecificImages(m_CaseID, currentControlPoint, currentInformationType); + filteredDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSpecificImages(m_CaseID, currentControlPoint, currentInformationType); } else if ("Segmentation" == m_SelectedNodeType) { - filteredDataNodes = m_SemanticRelations->GetAllSpecificSegmentations(m_CaseID, currentControlPoint, currentInformationType); + filteredDataNodes = m_SemanticRelationsDataStorageAccess->GetAllSpecificSegmentations(m_CaseID, currentControlPoint, currentInformationType); } if (filteredDataNodes.empty()) { return nullptr; } return filteredDataNodes.front(); } catch (const mitk::SemanticRelationException&) { return nullptr; } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake index dcff75cc03..8e961c0ceb 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake +++ b/Plugins/org.mitk.gui.qt.semanticrelations/files.cmake @@ -1,42 +1,43 @@ set(INTERNAL_CPP_FILES mitkPluginActivator.cpp + QmitkAbstractSemanticRelationsAction.cpp QmitkDataNodeAddToSemanticRelationsAction.cpp QmitkDataNodeRemoveFromSemanticRelationsAction.cpp QmitkDataNodeUnlinkFromLesionAction.cpp QmitkDataNodeSetControlPointAction.cpp QmitkDataNodeSetInformationTypeAction.cpp QmitkLesionInfoWidget.cpp QmitkSemanticRelationsContextMenu.cpp QmitkSemanticRelationsNodeSelectionDialog.cpp QmitkSemanticRelationsView.cpp ) set(UI_FILES src/internal/QmitkLesionInfoWidgetControls.ui src/internal/QmitkSemanticRelationsControls.ui ) set(MOC_H_FILES src/internal/mitkPluginActivator.h src/internal/QmitkDataNodeAddToSemanticRelationsAction.h src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h src/internal/QmitkDataNodeUnlinkFromLesionAction.h src/internal/QmitkDataNodeSetControlPointAction.h src/internal/QmitkDataNodeSetInformationTypeAction.h src/internal/QmitkLesionInfoWidget.h src/internal/QmitkSemanticRelationsContextMenu.h src/internal/QmitkSemanticRelationsNodeSelectionDialog.h src/internal/QmitkSemanticRelationsView.h ) set(CACHED_RESOURCE_FILES resources/SemanticRelations_48.png plugin.xml ) set(QRC_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.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp new file mode 100644 index 0000000000..dafd7c2a72 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.cpp @@ -0,0 +1,35 @@ +/*=================================================================== + +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. + +===================================================================*/ + +// semantic relations plugin +#include "QmitkAbstractSemanticRelationsAction.h" + +QmitkAbstractSemanticRelationsAction::QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite) + : QmitkAbstractDataNodeAction(workbenchPartSite) +{ + m_SemanticRelationsIntegration = std::make_unique(); +} + +QmitkAbstractSemanticRelationsAction::QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite* workbenchPartSite) + : QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) +{ + // nothing here +} + +QmitkAbstractSemanticRelationsAction::~QmitkAbstractSemanticRelationsAction() +{ + // nothing here +} diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h new file mode 100644 index 0000000000..eb2c57cdc4 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkAbstractSemanticRelationsAction.h @@ -0,0 +1,41 @@ +/*=================================================================== + +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 QMITKABSTRACTSEMANTICRELATIONSACTION_H +#define QMITKABSTRACTSEMANTICRELATIONSACTION_H + +// mitk gui qt application plugin +#include + +// semantic relations module +#include + +class QmitkAbstractSemanticRelationsAction : public QmitkAbstractDataNodeAction +{ + +public: + + QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer workbenchPartSite); + QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite* workbenchPartSite); + + virtual ~QmitkAbstractSemanticRelationsAction() override; + +protected: + + std::unique_ptr m_SemanticRelationsIntegration; +}; + +#endif // QMITKABSTRACTSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp index 99b93f1a1a..5e91cb0ef5 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.cpp @@ -1,179 +1,171 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkDataNodeAddToSemanticRelationsAction.h" // semantic relations module +#include #include #include #include // mitk gui common plugin #include // qt #include // namespace that contains the concrete action namespace AddToSemanticRelationsAction { - void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* dataNode) + void Run(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataStorage* dataStorage, const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { - AddImage(semanticRelations, dataNode); + AddImage(semanticRelationsIntegration, dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { - AddSegmentation(semanticRelations, dataStorage, dataNode); + AddSegmentation(semanticRelationsIntegration, dataStorage, dataNode); } } - void AddImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image) + void AddImage(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* image) { if (nullptr == image) { return; } try { // add the image to the semantic relations storage - semanticRelations->AddImage(image); + semanticRelationsIntegration->AddImage(image); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not add the selected image."); msgBox.setText("The program wasn't able to correctly add the selected images.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } } - void AddSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation) + void AddSegmentation(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation) { if (nullptr == segmentation) { return; } mitk::BaseData* baseData = segmentation->GetData(); if (nullptr == baseData) { return; } // continue with valid segmentation data // get parent node of the current segmentation node with the node predicate mitk::DataStorage::SetOfObjects::ConstPointer parentNodes = dataStorage->GetSources(segmentation, mitk::NodePredicates::GetImagePredicate(), false); // check for already existing, identifying base properties mitk::BaseProperty* caseIDProperty = baseData->GetProperty("DICOM.0010.0010"); mitk::BaseProperty* nodeIDProperty = baseData->GetProperty("DICOM.0020.000E"); if (nullptr == caseIDProperty || nullptr == nodeIDProperty) { MITK_INFO << "No DICOM tags for case and node identification found. Transferring DICOM tags from the parent node to the selected segmentation node."; mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(parentNodes->front()); mitk::SemanticTypes::ID nodeID = mitk::GetIDFromDataNode(parentNodes->front()); // transfer DICOM tags to the segmentation node mitk::StringProperty::Pointer caseIDTag = mitk::StringProperty::New(caseID); baseData->SetProperty("DICOM.0010.0010", caseIDTag); // DICOM tag is "PatientName" // add UID to distinguish between different segmentations of the same parent node mitk::StringProperty::Pointer nodeIDTag = mitk::StringProperty::New(nodeID + mitk::UIDGeneratorBoost::GenerateUID()); baseData->SetProperty("DICOM.0020.000E", nodeIDTag); // DICOM tag is "SeriesInstanceUID" } try { - semanticRelations->AddSegmentation(segmentation, parentNodes->front()); + // add the segmentation with its parent image to the semantic relations storage + semanticRelationsIntegration->AddSegmentation(segmentation, parentNodes->front()); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not add the selected segmentation."); msgBox.setText("The program wasn't able to correctly add the selected segmentation.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } } } QmitkDataNodeAddToSemanticRelationsAction::QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(workbenchPartSite) + , QmitkAbstractSemanticRelationsAction(workbenchPartSite) { setText(tr("Add to semantic relations")); InitializeAction(); } QmitkDataNodeAddToSemanticRelationsAction::QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) + , QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Add to semantic relations")); InitializeAction(); } QmitkDataNodeAddToSemanticRelationsAction::~QmitkDataNodeAddToSemanticRelationsAction() { // nothing here } -void QmitkDataNodeAddToSemanticRelationsAction::SetDataStorage(mitk::DataStorage* dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // set the new data storage - m_DataStorage = dataStorage; - m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); - } -} - void QmitkDataNodeAddToSemanticRelationsAction::InitializeAction() { connect(this, &QAction::triggered, this, &QmitkDataNodeAddToSemanticRelationsAction::OnActionTriggered); } void QmitkDataNodeAddToSemanticRelationsAction::OnActionTriggered(bool checked) { - if (nullptr == m_SemanticRelations) + if (nullptr == m_SemanticRelationsIntegration) { return; } if (m_DataStorage.IsExpired()) { return; } auto dataNode = GetSelectedNode(); - AddToSemanticRelationsAction::Run(m_SemanticRelations.get(), m_DataStorage.Lock(), dataNode); + AddToSemanticRelationsAction::Run(m_SemanticRelationsIntegration.get(), m_DataStorage.Lock(), dataNode); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h index 99d8de0865..a613dd26fc 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeAddToSemanticRelationsAction.h @@ -1,64 +1,57 @@ /*=================================================================== 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 QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H #define QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H #include -// semantic relations module -#include - // mitk gui qt application plugin -#include +#include "QmitkAbstractSemanticRelationsAction.h" // qt #include namespace AddToSemanticRelationsAction { - MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* image); + MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataStorage* dataStorage, const mitk::DataNode* image); - void AddImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image); - void AddSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation); + void AddImage(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* image); + void AddSegmentation(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataStorage* dataStorage, const mitk::DataNode* segmentation); } -class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeAddToSemanticRelationsAction : public QAction, public QmitkAbstractDataNodeAction +class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeAddToSemanticRelationsAction : public QAction, public QmitkAbstractSemanticRelationsAction { Q_OBJECT public: QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeAddToSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeAddToSemanticRelationsAction() override; - void SetDataStorage(mitk::DataStorage* dataStorage); - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; - std::unique_ptr m_SemanticRelations; - }; #endif // QMITKDATANODEADDTOSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp index 4216e9f854..93e13d0576 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.cpp @@ -1,146 +1,131 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" // semantic relations module #include #include -#include // mitk gui common plugin #include // qt #include // namespace that contains the concrete action namespace RemoveFromSemanticRelationsAction { - void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* dataNode) + void Run(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { - RemoveImage(semanticRelations, dataNode); + RemoveImage(semanticRelationsIntegration, dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { - RemoveSegmentation(semanticRelations, dataNode); + RemoveSegmentation(semanticRelationsIntegration, dataNode); } } - void RemoveImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image) + void RemoveImage(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* image) { if (nullptr == image) { return; } try { // remove the image from the semantic relations storage - semanticRelations->RemoveImage(image); + semanticRelationsIntegration->RemoveImage(image); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not remove the selected image."); msgBox.setText("The program wasn't able to correctly remove the selected image.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } } - void RemoveSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* segmentation) + void RemoveSegmentation(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* segmentation) { if (nullptr == segmentation) { return; } try { - semanticRelations->RemoveSegmentation(segmentation); + // remove the segmentation from the semantic relations storage + semanticRelationsIntegration->RemoveSegmentation(segmentation); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; QMessageBox msgBox; msgBox.setWindowTitle("Could not remove the selected segmentation."); msgBox.setText("The program wasn't able to correctly remove the selected segmentation.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } } } QmitkDataNodeRemoveFromSemanticRelationsAction::QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(workbenchPartSite) + , QmitkAbstractSemanticRelationsAction(workbenchPartSite) { setText(tr("Remove from semantic relations")); InitializeAction(); } QmitkDataNodeRemoveFromSemanticRelationsAction::QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) + , QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Remove from semantic relations")); InitializeAction(); } QmitkDataNodeRemoveFromSemanticRelationsAction::~QmitkDataNodeRemoveFromSemanticRelationsAction() { // nothing here } -void QmitkDataNodeRemoveFromSemanticRelationsAction::SetDataStorage(mitk::DataStorage* dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // set the new data storage - m_DataStorage = dataStorage; - m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); - } -} - void QmitkDataNodeRemoveFromSemanticRelationsAction::InitializeAction() { connect(this, &QAction::triggered, this, &QmitkDataNodeRemoveFromSemanticRelationsAction::OnActionTriggered); } void QmitkDataNodeRemoveFromSemanticRelationsAction::OnActionTriggered(bool checked) { - if (nullptr == m_SemanticRelations) - { - return; - } - auto dataNode = GetSelectedNode(); - RemoveFromSemanticRelationsAction::Run(m_SemanticRelations.get(), dataNode); + RemoveFromSemanticRelationsAction::Run(m_SemanticRelationsIntegration.get(), dataNode); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h index 198e2bb53f..4e19e664fa 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeRemoveFromSemanticRelationsAction.h @@ -1,64 +1,57 @@ /*=================================================================== 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 QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H #define QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H #include -// semantic relations module -#include - // mitk gui qt application plugin -#include +#include "QmitkAbstractSemanticRelationsAction.h" // qt #include namespace RemoveFromSemanticRelationsAction { - MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* dataNode); + MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* dataNode); - void RemoveImage(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* image); - void RemoveSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* segmentation); + void RemoveImage(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* image); + void RemoveSegmentation(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* segmentation); } -class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeRemoveFromSemanticRelationsAction : public QAction, public QmitkAbstractDataNodeAction +class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeRemoveFromSemanticRelationsAction : public QAction, public QmitkAbstractSemanticRelationsAction { Q_OBJECT public: QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeRemoveFromSemanticRelationsAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeRemoveFromSemanticRelationsAction() override; - void SetDataStorage(mitk::DataStorage* dataStorage); - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; - std::unique_ptr m_SemanticRelations; - }; #endif // QMITKDATANODEREMOVEFROMSEMANTICRELATIONSACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.cpp index c9c1a68f59..61305de34c 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.cpp @@ -1,111 +1,102 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkDataNodeSetControlPointAction.h" // semantic relations module #include #include +#include #include // semantic relations UI module #include "QmitkControlPointDialog.h" // mitk gui common plugin #include // qt #include QmitkDataNodeSetControlPointAction::QmitkDataNodeSetControlPointAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(workbenchPartSite) + , QmitkAbstractSemanticRelationsAction(workbenchPartSite) { setText(tr("Set control point")); m_Parent = parent; InitializeAction(); } QmitkDataNodeSetControlPointAction::QmitkDataNodeSetControlPointAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) + , QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Set control point")); m_Parent = parent; InitializeAction(); } QmitkDataNodeSetControlPointAction::~QmitkDataNodeSetControlPointAction() { // nothing here } -void QmitkDataNodeSetControlPointAction::SetDataStorage(mitk::DataStorage* dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // set the new data storage - m_DataStorage = dataStorage; - m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); - } -} - void QmitkDataNodeSetControlPointAction::InitializeAction() { connect(this, &QAction::triggered, this, &QmitkDataNodeSetControlPointAction::OnActionTriggered); } void QmitkDataNodeSetControlPointAction::OnActionTriggered(bool checked) { - if (nullptr == m_SemanticRelations) + if (nullptr == m_SemanticRelationsIntegration) { return; } auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } QmitkControlPointDialog* inputDialog = new QmitkControlPointDialog(m_Parent); inputDialog->setWindowTitle("Set control point"); - inputDialog->SetCurrentDate(m_SemanticRelations->GetControlPointOfData(dataNode)); + inputDialog->SetCurrentDate(mitk::SemanticRelationsInference::GetControlPointOfImage(dataNode)); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } const QDate& userSelectedDate = inputDialog->GetCurrentDate(); mitk::SemanticTypes::ControlPoint controlPoint; controlPoint.UID = mitk::UIDGeneratorBoost::GenerateUID(); controlPoint.date = boost::gregorian::date(userSelectedDate.year(), userSelectedDate.month(), userSelectedDate.day()); try { - m_SemanticRelations->UnlinkDataFromControlPoint(dataNode); - m_SemanticRelations->SetControlPointOfData(dataNode, controlPoint); + m_SemanticRelationsIntegration->UnlinkImageFromControlPoint(dataNode); + m_SemanticRelationsIntegration->SetControlPointOfData(dataNode, controlPoint); } catch (const mitk::SemanticRelationException&) { return; } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.h index a96ae08754..2c2345cd2f 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetControlPointAction.h @@ -1,55 +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 QMITKDATANODESETCONTROLPOINTEACTION_H -#define QMITKDATANODESETCONTROLPOINTEACTION_H +#ifndef QMITKDATANODESETCONTROLPOINTACTION_H +#define QMITKDATANODESETCONTROLPOINTACTION_H -// semantic relations module -#include - -// mitk gui qt application plugin -#include +// mitk gui qt semanticrelations plugin +#include "QmitkAbstractSemanticRelationsAction.h" // qt #include -class QmitkDataNodeSetControlPointAction : public QAction, public QmitkAbstractDataNodeAction +class QmitkDataNodeSetControlPointAction : public QAction, public QmitkAbstractSemanticRelationsAction { Q_OBJECT public: QmitkDataNodeSetControlPointAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeSetControlPointAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeSetControlPointAction() override; - void SetDataStorage(mitk::DataStorage* dataStorage); - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; - QWidget *m_Parent; - std::unique_ptr m_SemanticRelations; + QWidget* m_Parent; }; -#endif // QMITKDATANODESETCONTROLPOINTEACTION_H +#endif // QMITKDATANODESETCONTROLPOINTACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.cpp index 851db448db..be533df52c 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.cpp @@ -1,100 +1,91 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkDataNodeSetInformationTypeAction.h" // semantic relations module #include +#include // mitk gui common plugin #include // qt #include QmitkDataNodeSetInformationTypeAction::QmitkDataNodeSetInformationTypeAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(workbenchPartSite) + , QmitkAbstractSemanticRelationsAction(workbenchPartSite) { setText(tr("Set information type")); m_Parent = parent; InitializeAction(); } QmitkDataNodeSetInformationTypeAction::QmitkDataNodeSetInformationTypeAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) + , QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Set information type")); m_Parent = parent; InitializeAction(); } QmitkDataNodeSetInformationTypeAction::~QmitkDataNodeSetInformationTypeAction() { // nothing here } -void QmitkDataNodeSetInformationTypeAction::SetDataStorage(mitk::DataStorage* dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // set the new data storage - m_DataStorage = dataStorage; - m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); - } -} - void QmitkDataNodeSetInformationTypeAction::InitializeAction() { connect(this, &QAction::triggered, this, &QmitkDataNodeSetInformationTypeAction::OnActionTriggered); } void QmitkDataNodeSetInformationTypeAction::OnActionTriggered(bool checked) { - if (nullptr == m_SemanticRelations) + if (nullptr == m_SemanticRelationsIntegration) { return; } auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } QInputDialog* inputDialog = new QInputDialog(m_Parent); inputDialog->setWindowTitle(tr("Set information type of selected node")); inputDialog->setLabelText(tr("Information type:")); - inputDialog->setTextValue(QString::fromStdString(m_SemanticRelations->GetInformationTypeOfImage(dataNode))); + inputDialog->setTextValue(QString::fromStdString(mitk::SemanticRelationsInference::GetInformationTypeOfImage(dataNode))); inputDialog->setMinimumSize(250, 100); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } try { - m_SemanticRelations->SetInformationType(dataNode, inputDialog->textValue().toStdString()); + m_SemanticRelationsIntegration->SetInformationType(dataNode, inputDialog->textValue().toStdString()); } catch (const mitk::SemanticRelationException&) { return; } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.h index 9df500d04c..8fa6294631 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeSetInformationTypeAction.h @@ -1,55 +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 QMITKDATANODESETINFORMATIONTYPEACTION_H #define QMITKDATANODESETINFORMATIONTYPEACTION_H -// semantic relations module -#include - // mitk gui qt application plugin -#include +#include "QmitkAbstractSemanticRelationsAction.h" // qt #include -class QmitkDataNodeSetInformationTypeAction : public QAction, public QmitkAbstractDataNodeAction +class QmitkDataNodeSetInformationTypeAction : public QAction, public QmitkAbstractSemanticRelationsAction { Q_OBJECT public: QmitkDataNodeSetInformationTypeAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeSetInformationTypeAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeSetInformationTypeAction() override; - void SetDataStorage(mitk::DataStorage* dataStorage); - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; QWidget* m_Parent; - std::unique_ptr m_SemanticRelations; }; #endif // QMITKDATANODESETINFORMATIONTYPEACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.cpp index 95985d8877..6d000d82c4 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.cpp @@ -1,126 +1,102 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkDataNodeUnlinkFromLesionAction.h" // semantic relations module #include #include #include // mitk gui common plugin #include // qt #include // namespace that contains the concrete action namespace UnlinkFromLesionAction { - void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* dataNode) + void Run(mitk::SemanticRelationsIntegration* semanticRelationsIntegration, const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { - UnlinkSegmentation(semanticRelations, dataNode); + try + { + semanticRelationsIntegration->UnlinkSegmentationFromLesion(dataNode); + } + catch (const mitk::SemanticRelationException& e) + { + std::stringstream exceptionMessage; exceptionMessage << e; + QMessageBox msgBox(QMessageBox::Warning, + "Could not unlink the selected segmentation.", + "The program wasn't able to correctly unlink the selected segmentation.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); + msgBox.exec(); + } } else { - QMessageBox msgBox; - msgBox.setWindowTitle("Could not unlink the selected data node."); - msgBox.setText("Please chose a valid segmentation to unlink from its represented lesion!"); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "Could not unlink the selected data node.", + "Please chose a valid segmentation to unlink from its represented lesion!"); msgBox.exec(); - return; - } - } - - void UnlinkSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* segmentation) - { - if (nullptr == segmentation) - { - return; - } - - try - { - semanticRelations->UnlinkSegmentationFromLesion(segmentation); - } - catch (const mitk::SemanticRelationException& e) - { - std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not unlink the selected segmentation."); - msgBox.setText("The program wasn't able to correctly unlink the selected segmentation.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; } } } QmitkDataNodeUnlinkFromLesionAction::QmitkDataNodeUnlinkFromLesionAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(workbenchPartSite) + , QmitkAbstractSemanticRelationsAction(workbenchPartSite) { setText(tr("Unlink from lesion")); InitializeAction(); } QmitkDataNodeUnlinkFromLesionAction::QmitkDataNodeUnlinkFromLesionAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) - , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) + , QmitkAbstractSemanticRelationsAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Unlink from lesion")); InitializeAction(); } QmitkDataNodeUnlinkFromLesionAction::~QmitkDataNodeUnlinkFromLesionAction() { // nothing here } -void QmitkDataNodeUnlinkFromLesionAction::SetDataStorage(mitk::DataStorage* dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // set the new data storage - m_DataStorage = dataStorage; - m_SemanticRelations = std::make_unique(m_DataStorage.Lock()); - } -} - void QmitkDataNodeUnlinkFromLesionAction::InitializeAction() { connect(this, &QAction::triggered, this, &QmitkDataNodeUnlinkFromLesionAction::OnActionTriggered); } void QmitkDataNodeUnlinkFromLesionAction::OnActionTriggered(bool checked) { - if (nullptr == m_SemanticRelations) + if (nullptr == m_SemanticRelationsIntegration) { return; } auto dataNode = GetSelectedNode(); - UnlinkFromLesionAction::Run(m_SemanticRelations.get(), dataNode); + UnlinkFromLesionAction::Run(m_SemanticRelationsIntegration.get(), dataNode); } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.h index 784816ec3b..10523c2bcc 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkDataNodeUnlinkFromLesionAction.h @@ -1,63 +1,54 @@ /*=================================================================== 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 QMITKDATANODEUNLINKFROMLESIONACTION_H #define QMITKDATANODEUNLINKFROMLESIONACTION_H #include -// semantic relations module -#include - -// mitk gui qt application plugin -#include +// mitk gui qt semanticrelations plugin +#include "QmitkAbstractSemanticRelationsAction.h" // qt #include namespace UnlinkFromLesionAction { - MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(mitk::SemanticRelations* semanticRelations, const mitk::DataStorage* dataStorage, const mitk::DataNode* dataNode); - - void UnlinkSegmentation(mitk::SemanticRelations* semanticRelations, const mitk::DataNode* segmentation); + MITK_GUI_SEMANTICRELATIONS_EXPORT void Run(const mitk::DataNode* dataNode, mitk::SemanticRelationsIntegration* semanticRelationsIntegration); } -class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeUnlinkFromLesionAction : public QAction, public QmitkAbstractDataNodeAction +class MITK_GUI_SEMANTICRELATIONS_EXPORT QmitkDataNodeUnlinkFromLesionAction : public QAction, public QmitkAbstractSemanticRelationsAction { Q_OBJECT public: QmitkDataNodeUnlinkFromLesionAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite); QmitkDataNodeUnlinkFromLesionAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite); virtual ~QmitkDataNodeUnlinkFromLesionAction() override; - void SetDataStorage(mitk::DataStorage* dataStorage); - private Q_SLOTS: void OnActionTriggered(bool); protected: virtual void InitializeAction() override; - std::unique_ptr m_SemanticRelations; - }; #endif // QMITKDATANODEUNLINKFROMLESIONACTION_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp index 3b20caedf4..327874c39f 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.cpp @@ -1,483 +1,431 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkLesionInfoWidget.h" #include "QmitkSemanticRelationsNodeSelectionDialog.h" // semantic relations UI module #include // semantic relations module #include #include #include +#include +#include // registration ontology module #include // qt #include #include #include #include #include QmitkLesionInfoWidget::QmitkLesionInfoWidget(mitk::DataStorage* dataStorage, QWidget* parent /*= nullptr*/) : QWidget(parent) , m_DataStorage(dataStorage) - , m_SemanticRelations(std::make_unique(dataStorage)) + , m_SemanticRelationsDataStorageAccess(std::make_unique(dataStorage)) + , m_SemanticRelationsIntegration(std::make_unique()) { Initialize(); } QmitkLesionInfoWidget::~QmitkLesionInfoWidget() { // nothing here } void QmitkLesionInfoWidget::Initialize() { m_Controls.setupUi(this); m_Controls.lesionTreeView->setAlternatingRowColors(true); m_Controls.lesionTreeView->setSelectionMode(QAbstractItemView::SingleSelection); m_Controls.lesionTreeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_Controls.lesionTreeView->setContextMenuPolicy(Qt::CustomContextMenu); - m_StorageModel = new QmitkLesionTreeModel(this); + m_StorageModel = new QmitkLesionTreeModel(m_Controls.lesionTreeView); if (m_DataStorage.IsExpired()) { return; } auto dataStorage = m_DataStorage.Lock(); m_StorageModel->SetDataStorage(dataStorage); m_Controls.lesionTreeView->setModel(m_StorageModel); SetUpConnections(); } void QmitkLesionInfoWidget::SetUpConnections() { connect(m_StorageModel, &QmitkLesionTreeModel::ModelUpdated, this, &QmitkLesionInfoWidget::OnModelUpdated); // connect buttons to modify semantic relations connect(m_Controls.addLesionPushButton, &QPushButton::clicked, this, &QmitkLesionInfoWidget::OnAddLesionButtonClicked); // connect each list widget with a custom slots connect(m_Controls.lesionTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &QmitkLesionInfoWidget::OnSelectionChanged); // connect context menu entries connect(m_Controls.lesionTreeView, &QTreeView::customContextMenuRequested, this, &QmitkLesionInfoWidget::OnLesionListContextMenuRequested); } void QmitkLesionInfoWidget::SetCaseID(const mitk::SemanticTypes::CaseID& caseID) { m_CaseID = caseID; m_StorageModel->SetCaseID(caseID); } void QmitkLesionInfoWidget::SetDataNodeSelection(const QList& dataNodeSelection) { m_StorageModel->SetDataNodeSelection(dataNodeSelection); } ////////////////////////////////////////////////////////////////////////// // Implementation of the QT_SLOTS ////////////////////////////////////////////////////////////////////////// void QmitkLesionInfoWidget::OnModelUpdated() { m_Controls.lesionTreeView->expandAll(); int columns = m_Controls.lesionTreeView->model()->columnCount(); for (int i = 0; i < columns; ++i) { m_Controls.lesionTreeView->resizeColumnToContents(i); } } void QmitkLesionInfoWidget::OnAddLesionButtonClicked() { if (m_CaseID.empty()) { QMessageBox msgBox; msgBox.setWindowTitle("No case ID set."); msgBox.setText("In order to add a lesion, please specify the current case / patient."); msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); return; } mitk::SemanticTypes::Lesion newLesion = mitk::GenerateNewLesion(); try { - m_SemanticRelations->AddLesion(m_CaseID, newLesion); + m_SemanticRelationsIntegration->AddLesion(m_CaseID, newLesion); } catch (mitk::SemanticRelationException& e) { MITK_INFO << "Could not add a new lesion. " << e; } } void QmitkLesionInfoWidget::OnSelectionChanged(const QModelIndex& current, const QModelIndex& previous) { - if (nullptr == m_SemanticRelations && current.isValid()) - { - return; - } - // only the UID is needed to identify a representing lesion QVariant data = m_StorageModel->data(current, Qt::UserRole); - if (data.canConvert()) - { - m_CurrentLesion = data.value()->GetData().GetLesion(); - } - else + if (!data.canConvert()) { return; } - if (false == m_SemanticRelations->InstanceExists(m_CaseID, m_CurrentLesion)) + auto lesion = data.value()->GetData().GetLesion(); + if (false == mitk::SemanticRelationsInference::InstanceExists(m_CaseID, lesion)) { // no UID of a existing lesion found; cannot create a lesion return; } // if selected data nodes are set, reset to empty list to - // the "selected data nodes presence background highlighting" in the model + // hide "selected data nodes presence background highlighting" in the model if (!m_StorageModel->GetSelectedDataNodes().isEmpty()) { m_StorageModel->SetDataNodeSelection(QList()); } - emit LesionSelectionChanged(m_CurrentLesion); + emit LesionSelectionChanged(lesion); } void QmitkLesionInfoWidget::OnLesionListContextMenuRequested(const QPoint& pos) { + if (nullptr == m_SemanticRelationsIntegration) + { + return; + } + + if (m_CaseID.empty()) + { + QMessageBox msgBox(QMessageBox::Warning, + "No case ID set.", + "In order to access the context menu entries a case ID has to be set."); + msgBox.exec(); + return; + } + QModelIndex index = m_Controls.lesionTreeView->indexAt(pos); if (!index.isValid()) { // no item clicked; cannot retrieve the current lesion return; } QVariant data = m_StorageModel->data(index, Qt::UserRole); mitk::SemanticTypes::Lesion selectedLesion; if (data.canConvert()) { selectedLesion = data.value()->GetData().GetLesion(); } else { return; } QMenu* menu = new QMenu(m_Controls.lesionTreeView); QAction* linkToSegmentation = new QAction("Link to segmentation", this); linkToSegmentation->setEnabled(true); connect(linkToSegmentation, &QAction::triggered, [this, selectedLesion] { OnLinkToSegmentation(selectedLesion); }); menu->addAction(linkToSegmentation); QAction* setLesionName = new QAction("Set lesion name", this); setLesionName->setEnabled(true); connect(setLesionName, &QAction::triggered, [this, selectedLesion] { OnSetLesionName(selectedLesion); }); menu->addAction(setLesionName); QAction* setLesionClass = new QAction("Set lesion class", this); setLesionClass->setEnabled(true); connect(setLesionClass, &QAction::triggered, [this, selectedLesion] { OnSetLesionClass(selectedLesion); }); menu->addAction(setLesionClass); QAction* propageLesionToImage = new QAction("Propagate lesion to image", this); propageLesionToImage->setEnabled(true); connect(propageLesionToImage, &QAction::triggered, [this, selectedLesion] { OnPropagateLesion(selectedLesion); }); menu->addAction(propageLesionToImage); QAction* removeLesion = new QAction("Remove lesion", this); removeLesion->setEnabled(true); connect(removeLesion, &QAction::triggered, [this, selectedLesion] { OnRemoveLesion(selectedLesion); }); menu->addAction(removeLesion); menu->popup(QCursor::pos()); } void QmitkLesionInfoWidget::OnLinkToSegmentation(mitk::SemanticTypes::Lesion selectedLesion) { - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to link a lesion to a segmentation, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - if (m_DataStorage.IsExpired()) { return; } auto dataStorage = m_DataStorage.Lock(); QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select segmentation to link to the selected lesion.", ""); - dialog->SetDataStorage(dataStorage); dialog->setWindowTitle("Select segmentation node"); + dialog->SetDataStorage(dataStorage); dialog->SetNodePredicate(mitk::NodePredicates::GetSegmentationPredicate()); dialog->SetSelectOnlyVisibleNodes(true); - dialog->SetSelectionMode(QAbstractItemView::SingleSelection); dialog->SetCaseID(m_CaseID); int dialogReturnValue = dialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } auto nodes = dialog->GetSelectedNodes(); mitk::DataNode::Pointer selectedDataNode = nullptr; if (!nodes.isEmpty()) { // only single selection allowed selectedDataNode = nodes.front(); } if (nullptr == selectedDataNode || false == mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(selectedDataNode)) { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid segmentation node selected."); - msgBox.setText("In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "No valid segmentation node selected.", + "In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); msgBox.exec(); return; } mitk::BaseData* baseData = selectedDataNode->GetData(); if (nullptr == baseData) { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid base data."); - msgBox.setText("In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "No valid base data.", + "In order to link the selected lesion to a segmentation, please specify a valid segmentation node."); msgBox.exec(); return; } try { - m_SemanticRelations->LinkSegmentationToLesion(selectedDataNode, selectedLesion); + m_SemanticRelationsIntegration->LinkSegmentationToLesion(selectedDataNode, selectedLesion); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not link the selected lesion."); - msgBox.setText("The program wasn't able to correctly link the selected lesion with the selected segmentation.\n" + QMessageBox msgBox(QMessageBox::Warning, + "Could not link the selected lesion.", + "The program wasn't able to correctly link the selected lesion with the selected segmentation.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } void QmitkLesionInfoWidget::OnSetLesionName(mitk::SemanticTypes::Lesion selectedLesion) { - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to set a lesion name, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - // use the lesion information to set the input text for the dialog QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this); inputDialog->setWindowTitle("Set lesion name"); inputDialog->SetLineEditText(selectedLesion.name); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } - std::string newLesionName = inputDialog->GetLineEditText().toStdString(); - - selectedLesion.name = newLesionName; - m_SemanticRelations->OverwriteLesion(m_CaseID, selectedLesion); + selectedLesion.name = inputDialog->GetLineEditText().toStdString(); + m_SemanticRelationsIntegration->OverwriteLesion(m_CaseID, selectedLesion); } void QmitkLesionInfoWidget::OnSetLesionClass(mitk::SemanticTypes::Lesion selectedLesion) { - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to set a lesion class, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - // use the lesion information to set the input text for the dialog QmitkLesionTextDialog* inputDialog = new QmitkLesionTextDialog(this); inputDialog->setWindowTitle("Set lesion class"); inputDialog->SetLineEditText(selectedLesion.lesionClass.classType); // prepare the completer for the dialogs input text field - mitk::LesionClassVector allLesionClasses = m_SemanticRelations->GetAllLesionClassesOfCase(m_CaseID); + mitk::LesionClassVector allLesionClasses = mitk::SemanticRelationsInference::GetAllLesionClassesOfCase(m_CaseID); QStringList wordList; for (const auto& lesionClass : allLesionClasses) { wordList << QString::fromStdString(lesionClass.classType); } QCompleter* completer = new QCompleter(wordList, this); completer->setCaseSensitivity(Qt::CaseInsensitive); inputDialog->GetLineEdit()->setCompleter(completer); int dialogReturnValue = inputDialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } // retrieve the new input lesion class type and check for an already existing lesion class types std::string newLesionClassType = inputDialog->GetLineEditText().toStdString(); mitk::SemanticTypes::LesionClass existingLesionClass = mitk::FindExistingLesionClass(newLesionClassType, allLesionClasses); if (existingLesionClass.UID.empty()) { // could not find lesion class information for the new lesion class type // create a new lesion class for the selected lesion existingLesionClass = mitk::GenerateNewLesionClass(newLesionClassType); } selectedLesion.lesionClass = existingLesionClass; - m_SemanticRelations->OverwriteLesion(m_CaseID, selectedLesion); + m_SemanticRelationsIntegration->OverwriteLesion(m_CaseID, selectedLesion); } void QmitkLesionInfoWidget::OnPropagateLesion(mitk::SemanticTypes::Lesion selectedLesion) { - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to propagate a lesion to an image, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - if (m_DataStorage.IsExpired()) { return; } auto dataStorage = m_DataStorage.Lock(); QmitkSemanticRelationsNodeSelectionDialog* dialog = new QmitkSemanticRelationsNodeSelectionDialog(this, "Select data node to propagate the selected lesion.", ""); - dialog->SetDataStorage(dataStorage); dialog->setWindowTitle("Select image node"); + dialog->SetDataStorage(dataStorage); dialog->SetNodePredicate(mitk::NodePredicates::GetImagePredicate()); dialog->SetSelectOnlyVisibleNodes(true); - dialog->SetSelectionMode(QAbstractItemView::SingleSelection); dialog->SetCaseID(m_CaseID); dialog->SetLesion(selectedLesion); int dialogReturnValue = dialog->exec(); if (QDialog::Rejected == dialogReturnValue) { return; } auto nodes = dialog->GetSelectedNodes(); mitk::DataNode::Pointer selectedDataNode = nullptr; if (!nodes.isEmpty()) { // only single selection allowed selectedDataNode = nodes.front(); } if (nullptr == selectedDataNode || false == mitk::NodePredicates::GetImagePredicate()->CheckNode(selectedDataNode)) { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid image node selected."); - msgBox.setText("In order to propagate the selected lesion to an image, please specify a valid image node."); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "No valid image node selected.", + "In order to propagate the selected lesion to an image, please specify a valid image node."); msgBox.exec(); return; } mitk::BaseData* baseData = selectedDataNode->GetData(); if (nullptr == baseData) { - QMessageBox msgBox; - msgBox.setWindowTitle("No valid base data."); - msgBox.setText("In order to propagate the selected lesion to an image, please specify a valid image node."); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "No valid base data.", + "In order to propagate the selected lesion to an image, please specify a valid image node."); msgBox.exec(); return; } try { - auto allSegmentationsOfLesion = m_SemanticRelations->GetAllSegmentationsOfLesion(m_CaseID, selectedLesion); - mitk::FindClosestSegmentationMask(); + auto allSegmentationsOfLesion = m_SemanticRelationsDataStorageAccess->GetAllSegmentationsOfLesion(m_CaseID, selectedLesion); + mitk::LesionPropagation::FindClosestSegmentationMask(); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not propagate the selected lesion."); - msgBox.setText("The program wasn't able to correctly propagate the selected lesion to the selected image.\n" + QMessageBox msgBox(QMessageBox::Warning, + "Could not propagate the selected lesion.", + "The program wasn't able to correctly propagate the selected lesion to the selected image.\n" "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); msgBox.exec(); } } void QmitkLesionInfoWidget::OnRemoveLesion(mitk::SemanticTypes::Lesion selectedLesion) { - if (m_CaseID.empty()) - { - QMessageBox msgBox; - msgBox.setWindowTitle("No case ID set."); - msgBox.setText("In order to remove a lesion, please specify the current case / patient."); - msgBox.setIcon(QMessageBox::Warning); - msgBox.exec(); - return; - } - try { - m_SemanticRelations->RemoveLesion(m_CaseID, selectedLesion); + m_SemanticRelationsIntegration->RemoveLesion(m_CaseID, selectedLesion); } catch (const mitk::SemanticRelationException& e) { std::stringstream exceptionMessage; exceptionMessage << e; - QMessageBox msgBox; - msgBox.setWindowTitle("Could not remove the selected lesion."); - msgBox.setText("The program wasn't able to correctly remove the selected lesion from the semantic relations model.\n" - "Reason:\n" + QString::fromStdString(exceptionMessage.str())); - msgBox.setIcon(QMessageBox::Warning); + QMessageBox msgBox(QMessageBox::Warning, + "Could not remove the selected lesion.", + "The program wasn't able to correctly remove the selected lesion from the semantic relations model.\n" + "Reason:\n" + QString::fromStdString(exceptionMessage.str())); msgBox.exec(); } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h index a26a97569b..15f3d95930 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkLesionInfoWidget.h @@ -1,102 +1,102 @@ /*=================================================================== 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 QMITKLESIONINFOWIDGET_H #define QMITKLESIONINFOWIDGET_H // semantic relations plugin #include // semantic relations UI module #include // semantic relations module -#include +#include +#include // mitk #include // qt #include /* * @brief The QmitkLesionInfoWidget is a widget that shows and modifies the currently available lesion data of the semantic relations model. * * The widget provides a dialogs to add nodes from the data storage to the semantic relations model. * It provides functionality to create new lesions and link them with segmentation nodes. * * The QmitkLesionInfoWidget provides three QListWidgets, that show the lesion data and the referenced segmentation data, as * well as the connected image data, depending on the selected lesion. */ class QmitkLesionInfoWidget : public QWidget { Q_OBJECT public: static const QBrush DEFAULT_BACKGROUND_COLOR; static const QBrush SELECTED_BACKGROUND_COLOR; static const QBrush CONNECTED_BACKGROUND_COLOR; QmitkLesionInfoWidget::QmitkLesionInfoWidget(mitk::DataStorage* dataStorage, QWidget* parent = nullptr); ~QmitkLesionInfoWidget(); void SetCaseID(const mitk::SemanticTypes::CaseID& caseID); void SetDataNodeSelection(const QList& dataNodeSelection); - const mitk::SemanticTypes::Lesion& GetSelectedLesion() const { return m_CurrentLesion; } - Q_SIGNALS: void LesionSelectionChanged(const mitk::SemanticTypes::Lesion&); private Q_SLOTS: void OnModelUpdated(); /* * @brief Generates a new, empty lesion to add to the semantic relations model for the current case ID. */ void OnAddLesionButtonClicked(); // slots for the mouse click events of tree view's selection model void OnSelectionChanged(const QModelIndex& current, const QModelIndex& previous); void OnLesionListContextMenuRequested(const QPoint&); // slots for the context menu actions of the lesion list widget void OnLinkToSegmentation(mitk::SemanticTypes::Lesion); void OnSetLesionName(mitk::SemanticTypes::Lesion); void OnSetLesionClass(mitk::SemanticTypes::Lesion); void OnPropagateLesion(mitk::SemanticTypes::Lesion); void OnRemoveLesion(mitk::SemanticTypes::Lesion); private: void Initialize(); void SetUpConnections(); Ui::QmitkLesionInfoWidgetControls m_Controls; QmitkLesionTreeModel* m_StorageModel; - mitk::WeakPointer m_DataStorage; - std::unique_ptr m_SemanticRelations; mitk::SemanticTypes::CaseID m_CaseID; - mitk::SemanticTypes::Lesion m_CurrentLesion; + mitk::WeakPointer m_DataStorage; + std::unique_ptr m_SemanticRelationsDataStorageAccess; + std::unique_ptr m_SemanticRelationsIntegration; + }; #endif // QMITKLESIONINFOWIDGET_H diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp index 64bc9c6194..8166a94d17 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.cpp @@ -1,276 +1,280 @@ /*=================================================================== 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. ===================================================================*/ // semantic relations plugin #include "QmitkSemanticRelationsView.h" #include "QmitkDataNodeAddToSemanticRelationsAction.h" #include "QmitkDataNodeRemoveFromSemanticRelationsAction.h" // semantic relations module +#include #include #include +#include +#include // mitk qt widgets module #include #include // mitk multi label module #include // berry #include #include // qt #include #include const std::string QmitkSemanticRelationsView::VIEW_ID = "org.mitk.views.semanticrelations"; void QmitkSemanticRelationsView::SetFocus() { // nothing here } void QmitkSemanticRelationsView::CreateQtPartControl(QWidget* parent) { // create GUI widgets m_Controls.setupUi(parent); - // initialize the semantic relations - m_SemanticRelations = std::make_unique(GetDataStorage()); - m_LesionInfoWidget = new QmitkLesionInfoWidget(GetDataStorage(), parent); m_Controls.gridLayout->addWidget(m_LesionInfoWidget); m_PatientTableInspector = new QmitkPatientTableInspector(parent); m_PatientTableInspector->SetDataStorage(GetDataStorage()); m_Controls.gridLayout->addWidget(m_PatientTableInspector); QGridLayout* dndDataNodeWidgetLayout = new QGridLayout; dndDataNodeWidgetLayout->addWidget(m_PatientTableInspector, 0, 0); dndDataNodeWidgetLayout->setContentsMargins(0, 0, 0, 0); m_DnDDataNodeWidget = new QmitkDnDDataNodeWidget(parent); m_DnDDataNodeWidget->setLayout(dndDataNodeWidgetLayout); m_Controls.gridLayout->addWidget(m_DnDDataNodeWidget); m_ContextMenu = new QmitkSemanticRelationsContextMenu(GetSite(), m_PatientTableInspector); m_ContextMenu->SetDataStorage(GetDataStorage()); mitk::IRenderWindowPart* renderWindowPart = GetRenderWindowPart(); if (nullptr != renderWindowPart) { RenderWindowPartActivated(renderWindowPart); } SetUpConnections(); - const auto& allCaseIDs = m_SemanticRelations->GetAllCaseIDs(); + const auto& allCaseIDs = mitk::RelationStorage::GetAllCaseIDs(); for (const auto& caseID : allCaseIDs) { AddToComboBox(caseID); } } void QmitkSemanticRelationsView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { // connect QmitkRenderWindows - underlying vtkRenderWindow is the same as "mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows()" QHash windowMap = renderWindowPart->GetQmitkRenderWindows(); QHash::Iterator it; mitk::BaseRenderer* baseRenderer = nullptr; RenderWindowLayerUtilities::RendererVector controlledRenderer; for (it = windowMap.begin(); it != windowMap.end(); ++it) { baseRenderer = mitk::BaseRenderer::GetInstance(it.value()->GetVtkRenderWindow()); if (nullptr != baseRenderer) { controlledRenderer.push_back(baseRenderer); } } m_ContextMenu->SetControlledRenderer(controlledRenderer); } void QmitkSemanticRelationsView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) { // nothing here } void QmitkSemanticRelationsView::SetUpConnections() { connect(m_Controls.caseIDComboBox, static_cast(&QComboBox::currentIndexChanged), this, &QmitkSemanticRelationsView::OnCaseIDSelectionChanged); connect(m_LesionInfoWidget, &QmitkLesionInfoWidget::LesionSelectionChanged, this, &QmitkSemanticRelationsView::OnLesionSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::CurrentSelectionChanged, this, &QmitkSemanticRelationsView::OnDataNodeSelectionChanged); connect(m_PatientTableInspector, &QmitkPatientTableInspector::DataNodeDoubleClicked, this, &QmitkSemanticRelationsView::OnDataNodeDoubleClicked); connect(m_DnDDataNodeWidget, &QmitkDnDDataNodeWidget::NodesDropped, this, &QmitkSemanticRelationsView::OnNodesAdded); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnContextMenuRequested, m_ContextMenu, &QmitkSemanticRelationsContextMenu::OnContextMenuRequested); connect(m_PatientTableInspector, &QmitkPatientTableInspector::OnNodeRemoved, this, &QmitkSemanticRelationsView::NodeRemoved); } QItemSelectionModel* QmitkSemanticRelationsView::GetDataNodeSelectionModel() const { return m_PatientTableInspector->GetSelectionModel(); } void QmitkSemanticRelationsView::NodeRemoved(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } - if (m_SemanticRelations->InstanceExists(dataNode)) + if (mitk::SemanticRelationsInference::InstanceExists(dataNode)) { - RemoveFromSemanticRelationsAction::Run(m_SemanticRelations.get(), dataNode); + // no observer needed for the integration; simply use a temporary instance for removing + mitk::SemanticRelationsIntegration semanticRelationsIntegration; + RemoveFromSemanticRelationsAction::Run(&semanticRelationsIntegration, dataNode); mitk::SemanticTypes::CaseID caseID = mitk::GetCaseIDFromDataNode(dataNode); RemoveFromComboBox(caseID); } } void QmitkSemanticRelationsView::OnLesionSelectionChanged(const mitk::SemanticTypes::Lesion& lesion) { m_PatientTableInspector->SetLesion(lesion); } void QmitkSemanticRelationsView::OnDataNodeSelectionChanged(const QList& dataNodeSelection) { m_LesionInfoWidget->SetDataNodeSelection(dataNodeSelection); } void QmitkSemanticRelationsView::OnDataNodeDoubleClicked(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } if (mitk::NodePredicates::GetImagePredicate()->CheckNode(dataNode)) { OpenInEditor(dataNode); } else if (mitk::NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) { JumpToPosition(dataNode); } } void QmitkSemanticRelationsView::OnCaseIDSelectionChanged(const QString& caseID) { m_LesionInfoWidget->SetCaseID(caseID.toStdString()); m_PatientTableInspector->SetCaseID(caseID.toStdString()); } void QmitkSemanticRelationsView::OnNodesAdded(QmitkDnDDataNodeWidget* dnDDataNodeWidget, std::vector nodes) { mitk::SemanticTypes::CaseID caseID = ""; for (mitk::DataNode* dataNode : nodes) { - AddToSemanticRelationsAction::Run(m_SemanticRelations.get(), GetDataStorage(), dataNode); + // no observer needed for the integration; simply use a temporary instance for adding + mitk::SemanticRelationsIntegration semanticRelationsIntegration; + AddToSemanticRelationsAction::Run(&semanticRelationsIntegration, GetDataStorage(), dataNode); caseID = mitk::GetCaseIDFromDataNode(dataNode); AddToComboBox(caseID); } } void QmitkSemanticRelationsView::OnNodeRemoved(const mitk::DataNode* dataNode) { NodeRemoved(dataNode); } void QmitkSemanticRelationsView::AddToComboBox(const mitk::SemanticTypes::CaseID& caseID) { int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (-1 == foundIndex) { // add the caseID to the combo box, as it is not already contained m_Controls.caseIDComboBox->addItem(QString::fromStdString(caseID)); } } void QmitkSemanticRelationsView::RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID) { - std::vector allControlPoints = m_SemanticRelations->GetAllControlPointsOfCase(caseID); + std::vector allControlPoints = mitk::RelationStorage::GetAllControlPointsOfCase(caseID); int foundIndex = m_Controls.caseIDComboBox->findText(QString::fromStdString(caseID)); if (allControlPoints.empty() && -1 != foundIndex) { // TODO: find new way to check for empty case id // caseID does not contain any control points and therefore no data // remove the caseID, if it is still contained m_Controls.caseIDComboBox->removeItem(foundIndex); } } void QmitkSemanticRelationsView::OpenInEditor(const mitk::DataNode* dataNode) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::BRING_TO_FRONT | mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto image = dynamic_cast(dataNode->GetData()); if (nullptr != image) { mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkSemanticRelationsView::JumpToPosition(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { return; } mitk::LabelSetImage* labelSetImage = dynamic_cast(dataNode->GetData()); if (nullptr == labelSetImage) { return; } int activeLayer = labelSetImage->GetActiveLayer(); mitk::Label* activeLabel = labelSetImage->GetActiveLabel(activeLayer); labelSetImage->UpdateCenterOfMass(activeLabel->GetValue(), activeLayer); const mitk::Point3D& centerPosition = activeLabel->GetCenterOfMassCoordinates(); if (centerPosition.GetVnlVector().max_value() > 0.0) { auto renderWindowPart = GetRenderWindowPart(); if (nullptr == renderWindowPart) { renderWindowPart = GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::BRING_TO_FRONT | mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); if (nullptr == renderWindowPart) { // no render window available return; } } auto segmentation = dynamic_cast(dataNode->GetData()); if (nullptr != segmentation) { renderWindowPart->SetSelectedPosition(centerPosition); mitk::RenderingManager::GetInstance()->InitializeViews(segmentation->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } } diff --git a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h index 805dc045bf..68341a9722 100644 --- a/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h +++ b/Plugins/org.mitk.gui.qt.semanticrelations/src/internal/QmitkSemanticRelationsView.h @@ -1,108 +1,105 @@ /*=================================================================== 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 QMITKSEMANTICRELATIONSVIEW_H #define QMITKSEMANTICRELATIONSVIEW_H // semantic relations plugin #include "ui_QmitkSemanticRelationsControls.h" #include "QmitkLesionInfoWidget.h" #include "QmitkSemanticRelationsContextMenu.h" // semantic relations module -#include #include // semantic relations UI module #include // mitk gui common plugin #include // berry #include // mitk qt #include class QmitkDnDDataNodeWidget; class QMenu; /* * @brief The QmitkSemanticRelationsView is an MITK view to combine and show the widgets of the 'SemanticRelationsUI'-module and this semantic relations plugin. * * It allows the MITK user to see and modify the content of the SemanticRelations-session. * A combo box is used to select and show the current patient. */ class QmitkSemanticRelationsView : public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; private Q_SLOTS: void OnLesionSelectionChanged(const mitk::SemanticTypes::Lesion&); void OnDataNodeSelectionChanged(const QList&); void OnDataNodeDoubleClicked(const mitk::DataNode*); void OnCaseIDSelectionChanged(const QString&); void OnNodesAdded(QmitkDnDDataNodeWidget*, std::vector); void OnNodeRemoved(const mitk::DataNode*); private: void SetUpConnections(); /** * @brief Provide a QItemSelectionModel, which supports the data role 'QmitkDataNodeRole' (\see QmitkRenderWindowDataModel). * * The provided QItemSelectionModel is used in the QmitkAbstractView-base class as the selection model of * the selection provider (\see QmitkAbstractView::SetSelectionProvider()). * The default selection provider is a QmitkDataNodeSelectionProvider. Each time a selection in the provided * QItemSeletionModel is changed, a selection changed event is fired. All plugins (views), that subclass the * QmitkAbstractView will be informed about the selection changed via the OnSelectionChanged-function. */ virtual QItemSelectionModel* GetDataNodeSelectionModel() const override; virtual void NodeRemoved(const mitk::DataNode* dataNode) override; void AddToComboBox(const mitk::SemanticTypes::CaseID& caseID); void RemoveFromComboBox(const mitk::SemanticTypes::CaseID& caseID); void OpenInEditor(const mitk::DataNode* dataNode); void JumpToPosition(const mitk::DataNode* dataNode); Ui::QmitkSemanticRelationsControls m_Controls; QmitkLesionInfoWidget* m_LesionInfoWidget; QmitkPatientTableInspector* m_PatientTableInspector; QmitkDnDDataNodeWidget* m_DnDDataNodeWidget; QmitkSemanticRelationsContextMenu* m_ContextMenu; - - std::unique_ptr m_SemanticRelations; }; #endif // QMITKSEMANTICRELATIONSVIEW_H