diff --git a/Modules/SemanticRelations/Test/mitkSemanticRelationsTestHelper.h b/Modules/SemanticRelations/Test/mitkSemanticRelationsTestHelper.h index 3a6835e4fc..628b087f64 100644 --- a/Modules/SemanticRelations/Test/mitkSemanticRelationsTestHelper.h +++ b/Modules/SemanticRelations/Test/mitkSemanticRelationsTestHelper.h @@ -1,71 +1,71 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // mitk core #include namespace mitk { namespace SemanticRelationsTestHelper { ////////////////////////////////////////////////////////////////////////// // VALID DATA NODES ////////////////////////////////////////////////////////////////////////// DataNode::Pointer GetPatientOneCTImage(); DataNode::Pointer GetPatientOneMRImage(); DataNode::Pointer GetPatientOneOtherCTImage(); DataNode::Pointer GetPatientTwoPETImage(); DataNode::Pointer GetPatientTwoSegmentation(); DataNode::Pointer GetPatientThreeCTImage(); DataNode::Pointer GetPatientThreeCTSegmentation(); DataNode::Pointer GetPatientThreeMRImage(); DataNode::Pointer GetPatientThreeMRSegmentation(); ////////////////////////////////////////////////////////////////////////// // INVALID DATA NODES ////////////////////////////////////////////////////////////////////////// /** * @brief Date is 0x0008, 0x0022 (AcquisitionDate) */ DataNode::Pointer GetInvalidDate(); /** * @brief Modality is 0x0008, 0x0060(Modality) */ DataNode::Pointer GetInvalidModality(); /** * @brief ID is 0x0020, 0x000e (SeriesInstanceUID) */ DataNode::Pointer GetInvalidID(); /** * @brief CaseID is 0x0010, 0x0010 (PatientName) */ DataNode::Pointer GetInvalidCaseID(); ////////////////////////////////////////////////////////////////////////// // AUXILIARY FUNCTIONS ////////////////////////////////////////////////////////////////////////// void ClearRelationStorage(); } // end SemanticRelationsTestHelper -} // end mitk \ No newline at end of file +} // end mitk diff --git a/Modules/SemanticRelations/include/mitkRelationStorage.h b/Modules/SemanticRelations/include/mitkRelationStorage.h index 1ba900ea77..08f6aecc12 100644 --- a/Modules/SemanticRelations/include/mitkRelationStorage.h +++ b/Modules/SemanticRelations/include/mitkRelationStorage.h @@ -1,81 +1,82 @@ /*=================================================================== 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 { 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); MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID); + SemanticTypes::ControlPoint GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID); - SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID); + SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); - SemanticTypes::IDVector GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID); - 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); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfCase(const SemanticTypes::CaseID& caseID); + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + MITKSEMANTICRELATIONS_EXPORT 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(); + MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID); void AddCase(const SemanticTypes::CaseID& caseID); 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 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 RemoveControlPoint(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 RemoveExaminationPeriod(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); 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 RemoveInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); } // namespace RelationStorage } // namespace mitk #endif // MITKRELATIONSTORAGE_H diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationException.h b/Modules/SemanticRelations/include/mitkSemanticRelationException.h index 4def6f9420..8ea55b2d3e 100644 --- a/Modules/SemanticRelations/include/mitkSemanticRelationException.h +++ b/Modules/SemanticRelations/include/mitkSemanticRelationException.h @@ -1,35 +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. ===================================================================*/ #ifndef MITKSEMANTICRELATIONEXCEPTION_H #define MITKSEMANTICRELATIONEXCEPTION_H // mitk core -#include +#include namespace mitk { class SemanticRelationException : public Exception { public: mitkExceptionClassMacro(SemanticRelationException, Exception); }; } // namespace mitk #endif // MITKSEMANTICRELATIONEXCEPTION_H diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h index 0d161c81c1..fa9faeda4d 100644 --- a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h +++ b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h @@ -1,300 +1,292 @@ /*=================================================================== 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 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. * * @pre The given segmentation data node has to be valid (!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 GetLesionOfSegmentation(const DataNode* segmentationNode); /** * @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. * * @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 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::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 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 '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. */ 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 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 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. */ MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); /** * @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. */ 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 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 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 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 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 Check if the given information type exists. * * @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 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 True, if the given control point contains data that is related to the given information type; false otherwise. */ 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. - */ - MITKSEMANTICRELATIONS_EXPORT void ClearControlPoints(const SemanticTypes::CaseID& caseID); } // namespace SemanticRelationsInference } // namespace mitk #endif // MITKSEMANTICRELATIONSINFERENCE_H diff --git a/Modules/SemanticRelations/include/mitkSemanticTypes.h b/Modules/SemanticRelations/include/mitkSemanticTypes.h index 2f12a09fff..2731adb52e 100644 --- a/Modules/SemanticRelations/include/mitkSemanticTypes.h +++ b/Modules/SemanticRelations/include/mitkSemanticTypes.h @@ -1,129 +1,129 @@ /*=================================================================== 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 MITKSEMANTICTYPES_H #define MITKSEMANTICTYPES_H #define BOOST_DATE_TIME_NO_LIB #if defined(BOOST_ALL_DYN_LINK) #undef BOOST_ALL_DYN_LINK #endif // boost #include // c++ #include #include #include namespace mitk { namespace SemanticTypes { using ID = std::string; - using CaseID = std::string; // an ID of the current case (e.g. the DICOM PatientID) + using CaseID = std::string; using InformationType = std::string; /* * @brief The concept of a control point. */ struct ControlPoint { ID UID; boost::gregorian::date date; ControlPoint() { date = boost::gregorian::date(boost::gregorian::min_date_time); } // less comparison to sort containers of control points bool operator<(const ControlPoint& other) const { return date < other.date; } std::string ToString() const { std::stringstream controlPointAsString; if (date.is_not_a_date()) { return ""; } controlPointAsString << std::to_string(date.year()) << "-" << std::setfill('0') << std::setw(2) << std::to_string(date.month()) << "-" << std::setfill('0') << std::setw(2) << std::to_string(date.day()); return controlPointAsString.str(); } void SetDateFromString(const std::string& dateAsString) { date = boost::gregorian::from_undelimited_string(dateAsString); } int DistanceInDays(const ControlPoint& other) const { boost::gregorian::date_duration duration = date - other.date; return std::abs(duration.days()); } }; /** * @brief The concept of an examination period. * An examination period holds a vector of control point UIDs. * The semantic relation storage stores the UIDs such that * the represented control points are in chronological order. */ struct ExaminationPeriod { ID UID; std::string name = ""; std::vector controlPointUIDs; }; /* * @brief The concept of a lesion class. */ struct LesionClass { ID UID; std::string classType = ""; }; /* * @brief The concept of a lesion. */ struct Lesion { ID UID; std::string name = ""; LesionClass lesionClass; }; using IDVector = std::vector; using LesionVector = std::vector; using LesionClassVector = std::vector; using ControlPointVector = std::vector; using ExaminationPeriodVector = std::vector; using InformationTypeVector = std::vector; } // namespace SemanticTypes } // namespace mitk #endif // MITKSEMANTICTYPES_H diff --git a/Modules/SemanticRelations/src/mitkControlPointManager.cpp b/Modules/SemanticRelations/src/mitkControlPointManager.cpp index e08a3fe44a..16dc2a314b 100644 --- a/Modules/SemanticRelations/src/mitkControlPointManager.cpp +++ b/Modules/SemanticRelations/src/mitkControlPointManager.cpp @@ -1,170 +1,170 @@ /*=================================================================== 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 "mitkControlPointManager.h" #include "mitkDICOMHelper.h" #include "mitkUIDGeneratorBoost.h" // mitk core #include mitk::SemanticTypes::ControlPoint mitk::GenerateControlPoint(const DataNode* datanode) { SemanticTypes::ControlPoint controlPoint = GetDICOMDateFromDataNode(datanode); controlPoint.UID = UIDGeneratorBoost::GenerateUID(); return controlPoint; } mitk::SemanticTypes::ControlPoint mitk::GetControlPointByUID(const SemanticTypes::ID& controlPointUID, const std::vector& allControlPoints) { auto lambda = [&controlPointUID](const SemanticTypes::ControlPoint& currentControlPoint) { return currentControlPoint.UID == controlPointUID; }; const auto existingControlPoint = std::find_if(allControlPoints.begin(), allControlPoints.end(), lambda); mitk::SemanticTypes::ControlPoint controlPoint; if (existingControlPoint != allControlPoints.end()) { controlPoint = *existingControlPoint; } return controlPoint; } mitk::SemanticTypes::ControlPoint mitk::FindExistingControlPoint(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ControlPointVector& allControlPoints) { for (const auto& currentControlPoint : allControlPoints) { if (controlPoint.date == currentControlPoint.date) { return currentControlPoint; } } return SemanticTypes::ControlPoint(); } mitk::SemanticTypes::ControlPoint mitk::FindClosestControlPoint(const SemanticTypes::ControlPoint& controlPoint, SemanticTypes::ControlPointVector& allControlPoints) { if (allControlPoints.empty()) { return SemanticTypes::ControlPoint(); } // sort the vector of control points for easier lookup std::sort(allControlPoints.begin(), allControlPoints.end()); // new control point does not match an existing control point // check if the control point is close to an already existing control point std::vector::const_iterator it; for (it = allControlPoints.begin(); it != allControlPoints.end(); ++it) { if (controlPoint.date < it->date) { break; } } SemanticTypes::ControlPoint nextControlPoint; SemanticTypes::ControlPoint previousControlPoint; if (it == allControlPoints.begin()) { // new date is smaller ("older") than the smallest already existing control point nextControlPoint = *it; } else if (it != allControlPoints.end()) { // new date is greater ("newer") than an already existing control point, // but smaller ("older") than another already existing control point nextControlPoint = *it; previousControlPoint = *(--it); } else { // new date is greater ("newer") than the greatest already existing control point previousControlPoint = *(--it); } // test distance to next and previous time period double distanceToNextExaminationPeriod = nextControlPoint.DistanceInDays(controlPoint); double distanceToPreviousExaminationPeriod = previousControlPoint.DistanceInDays(controlPoint); SemanticTypes::ControlPoint closestControlPoint; int closestDistanceInDays = 0; if (distanceToNextExaminationPeriod < distanceToPreviousExaminationPeriod) { // control point is closer to the next control point closestControlPoint = nextControlPoint; closestDistanceInDays = distanceToNextExaminationPeriod; } else { // control point is closer to the previous control point closestControlPoint = previousControlPoint; closestDistanceInDays = distanceToPreviousExaminationPeriod; } int THRESHOLD_DISTANCE_IN_DAYS = 30; - if (closestDistanceInDays < THRESHOLD_DISTANCE_IN_DAYS) + if (closestDistanceInDays <= THRESHOLD_DISTANCE_IN_DAYS) { return closestControlPoint; } return SemanticTypes::ControlPoint(); } mitk::SemanticTypes::ExaminationPeriod mitk::FindExaminationPeriod(const SemanticTypes::ControlPoint& controlPoint, const SemanticTypes::ExaminationPeriodVector& allExaminationPeriods) { for (const auto& examinationPeriod : allExaminationPeriods) { for (const auto& UID : examinationPeriod.controlPointUIDs) { if (controlPoint.UID == UID) { return examinationPeriod; } } } return SemanticTypes::ExaminationPeriod(); } void mitk::SortExaminationPeriods(SemanticTypes::ExaminationPeriodVector& allExaminationPeriods, const SemanticTypes::ControlPointVector& allControlPoints) { auto lambda = [allControlPoints](const SemanticTypes::ExaminationPeriod& leftExaminationPeriod, const SemanticTypes::ExaminationPeriod& rightExaminationPeriod) { if (leftExaminationPeriod.controlPointUIDs.empty()) { return true; } if (rightExaminationPeriod.controlPointUIDs.empty()) { return false; } const auto leftUID = leftExaminationPeriod.controlPointUIDs.front(); const auto rightUID = rightExaminationPeriod.controlPointUIDs.front(); const auto& leftControlPoint = GetControlPointByUID(leftUID, allControlPoints); const auto& rightControlPoint = GetControlPointByUID(rightUID, allControlPoints); return leftControlPoint.date < rightControlPoint.date; }; std::sort(allExaminationPeriods.begin(), allExaminationPeriods.end(), lambda); } diff --git a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp index 7dffde337f..aeb41fdc8b 100644 --- a/Modules/SemanticRelations/src/mitkDICOMHelper.cpp +++ b/Modules/SemanticRelations/src/mitkDICOMHelper.cpp @@ -1,161 +1,170 @@ /*=================================================================== 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 "mitkDICOMHelper.h" #include "mitkSemanticRelationException.h" #include "mitkUIDGeneratorBoost.h" // mitk core #include // c++ #include -mitk::SemanticTypes::ControlPoint GetControlPointFromString(const std::string& dateAsString); +mitk::SemanticTypes::ControlPoint GetControlPointFromString(const std::string& dateAsString) +{ + // date expected to be YYYYMMDD (8 characters) + if (dateAsString.size() != 8) + { + // string does not represent a DICOM date + mitkThrowException(mitk::SemanticRelationException) << "Not a valid DICOM date format."; + } + + mitk::SemanticTypes::ControlPoint controlPoint; + controlPoint.SetDateFromString(dateAsString); + + return controlPoint; +} mitk::SemanticTypes::CaseID mitk::GetCaseIDFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrowException(SemanticRelationException) << "No valid base data."; } // extract suitable DICOM tag to use as the case id // two alternatives can be used: // - DICOM tag "0x0010, 0x0010" is PatientName // - DICOM tag "0x0010, 0x0020" is PatientID // in the current implementation the PatientID (0x0010, 0x0010) is used mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str()); if (nullptr == dicomTag) { mitkThrowException(SemanticRelationException) << "Not a valid DICOM property."; } std::string dicomTagAsString = dicomTag->GetValueAsString(); return dicomTagAsString; } mitk::SemanticTypes::ID mitk::GetIDFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrowException(SemanticRelationException) << "No valid base data."; } // extract suitable DICOM tag to use as the data node id // DICOM tag "0x0020, 0x000e" is SeriesInstanceUID mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0020, 0x000e).c_str()); if (nullptr == dicomTag) { mitkThrowException(SemanticRelationException) << "Not a valid DICOM property."; } std::string dicomTagAsString = dicomTag->GetValueAsString(); return dicomTagAsString; } mitk::SemanticTypes::ControlPoint mitk::GetDICOMDateFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrowException(SemanticRelationException) << "No valid base data."; } // extract suitable DICOM tag to use as the data node id // DICOM tag "0x0008, 0x0022" is AcquisitionDate mitk::BaseProperty* acquisitionDateProperty = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0022).c_str()); if (nullptr == acquisitionDateProperty) { mitkThrowException(SemanticRelationException) << "Not a valid DICOM property."; } std::string acquisitionDateAsString = acquisitionDateProperty->GetValueAsString(); - return GetControlPointFromString(acquisitionDateAsString); + + SemanticTypes::ControlPoint controlPoint; + try + { + controlPoint = GetControlPointFromString(acquisitionDateAsString); + } + catch (SemanticRelationException &e) + { + mitkReThrow(e) << "Cannot retrieve a valid DICOM date."; + } + + return controlPoint; } mitk::SemanticTypes::InformationType mitk::GetDICOMModalityFromDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { mitkThrowException(SemanticRelationException) << "Not a valid data node."; } mitk::BaseData* baseData = dataNode->GetData(); if (nullptr == baseData) { mitkThrowException(SemanticRelationException) << "No valid base data."; } // extract suitable DICOM tag to use as the information type // DICOM tag "0x0008, 0x0060" is Modality mitk::BaseProperty* dicomTag = baseData->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str()); if (nullptr == dicomTag) { mitkThrowException(SemanticRelationException) << "Not a valid DICOM property."; } std::string dicomTagAsString = dicomTag->GetValueAsString(); return dicomTagAsString; } std::string mitk::TrimDICOM(const std::string& identifier) { if (identifier.empty()) { return identifier; } // leading whitespace std::size_t first = identifier.find_first_not_of(' '); if (std::string::npos == first) { return ""; } // trailing whitespace std::size_t last = identifier.find_last_not_of(' '); return identifier.substr(first, last - first + 1); } - -mitk::SemanticTypes::ControlPoint GetControlPointFromString(const std::string& dateAsString) -{ - // date expected to be YYYYMMDD (8 characters) - if (dateAsString.size() != 8) - { - // string does not represent a DICOM date - return mitk::SemanticTypes::ControlPoint(); - } - - mitk::SemanticTypes::ControlPoint controlPoint; - controlPoint.SetDateFromString(dateAsString); - - return controlPoint; -} diff --git a/Modules/SemanticRelations/src/mitkRelationStorage.cpp b/Modules/SemanticRelations/src/mitkRelationStorage.cpp index 3a9dd560e1..b22522c728 100644 --- a/Modules/SemanticRelations/src/mitkRelationStorage.cpp +++ b/Modules/SemanticRelations/src/mitkRelationStorage.cpp @@ -1,1498 +1,1539 @@ /*=================================================================== 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 { + std::vector GetCaseIDs() + { + 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"; + mitk::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 + mitk::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(); + } + + bool CaseIDExists(const mitk::SemanticTypes::CaseID& caseID) + { + auto allCaseIDs = GetCaseIDs(); + auto existingCase = std::find(allCaseIDs.begin(), allCaseIDs.end(), caseID); + if (existingCase == allCaseIDs.end()) + { + return false; + } + + return true; + } + 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; - } + if (nullptr == persistenceService) + { + MITK_DEBUG << "Persistence service could not be loaded"; + return nullptr; + } + + // The persistence service may create a new property list with the given ID, if no property list is found. + // Since we don't want to return a new property list but rather inform the user that the given case + // is not a valid, stored case, we will return nullptr in that case. + if (CaseIDExists(caseID)) + { + // the property list is valid for a whole case and contains all the properties for the current case + return persistenceService->GetPropertyList(const_cast(caseID)); + } - // 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)); + return nullptr; } 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 controlPointVectorPropertyValue = controlPointVectorProperty->GetValue(); // a control point has to have exactly three integer values (year, month and day) 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(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* lesionsVectorProperty = dynamic_cast*>(propertyList->GetProperty("lesions")); if (nullptr == lesionsVectorProperty) { MITK_DEBUG << "Could not find any lesion in the storage."; return SemanticTypes::LesionVector(); } std::vector lesionsVectorPropertyValue = lesionsVectorProperty->GetValue(); SemanticTypes::LesionVector allLesionsOfCase; 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::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 " << segmentationID << " in the storage."; return SemanticTypes::Lesion(); } 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::Lesion(); } 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::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* 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 controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); + SemanticTypes::ControlPointVector allControlPointsOfCase; + for (const auto& controlPointUID : controlPointsVectorPropertyValue) + { + SemanticTypes::ControlPoint generatedControlPoint = GenerateControlpoint(caseID, controlPointUID); + if (!generatedControlPoint.UID.empty()) + { + allControlPointsOfCase.push_back(generatedControlPoint); + } + } + + return allControlPointsOfCase; +} + 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* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); if (nullptr == imageVectorProperty) { MITK_DEBUG << "Could not find the image " << imageID << " in the storage."; return SemanticTypes::ControlPoint(); } std::vector imageVectorPropertyValue = imageVectorProperty->GetValue(); SemanticTypes::ControlPoint controlPoint; // 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 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 controlPointVectorPropertyValue = controlPointVectorProperty->GetValue(); // a control point has to have exactly three integer values (year, month and day) 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(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* 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 controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); - SemanticTypes::ControlPointVector allControlPointsOfCase; - 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 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 examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue(); SemanticTypes::ExaminationPeriodVector allExaminationPeriods; 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 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 (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 = examinationPeriodVectorPropertyValue[0]; for (int i = 1; i < examinationPeriodVectorPropertyValue.size(); ++i) { generatedExaminationPeriod.controlPointUIDs.push_back(examinationPeriodVectorPropertyValue[i]); } allExaminationPeriods.push_back(generatedExaminationPeriod); } } return allExaminationPeriods; } +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* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); + if (nullptr == informationTypesVectorProperty) + { + MITK_DEBUG << "Could not find any information types in the storage."; + return SemanticTypes::InformationTypeVector(); + } + + return informationTypesVectorProperty->GetValue(); +} + 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 (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 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 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* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); - if (nullptr == informationTypesVectorProperty) - { - MITK_DEBUG << "Could not find any information types in the storage."; - return SemanticTypes::InformationTypeVector(); - } - - 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::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(); } 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); + allSegmentationIDsOfImage.push_back(segmentationID); } } 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(); } 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 GetCaseIDs(); +} - return caseIDsVectorProperty->GetValue(); +bool mitk::RelationStorage::InstanceExists(const SemanticTypes::CaseID& caseID) +{ + return CaseIDExists(caseID); } 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 caseIDsVectorPropertyValue; if (nullptr == caseIDsVectorProperty) { caseIDsVectorProperty = VectorProperty::New(); } else { caseIDsVectorPropertyValue = caseIDsVectorProperty->GetValue(); } auto existingCase = std::find(caseIDsVectorPropertyValue.begin(), caseIDsVectorPropertyValue.end(), caseID); if (existingCase != caseIDsVectorPropertyValue.end()) { return; } // add case to the "caseIDs" property list caseIDsVectorPropertyValue.push_back(caseID); caseIDsVectorProperty->SetValue(caseIDsVectorPropertyValue); propertyList->SetProperty(listIdentifier, caseIDsVectorProperty); } 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 imagesVectorProperty = dynamic_cast*>(propertyList->GetProperty("images")); std::vector imagesVectorPropertyValue; if (nullptr == imagesVectorProperty) { imagesVectorProperty = VectorProperty::New(); } else { imagesVectorPropertyValue = imagesVectorProperty->GetValue(); } auto existingImage = std::find(imagesVectorPropertyValue.begin(), imagesVectorPropertyValue.end(), imageID); if (existingImage != imagesVectorPropertyValue.end()) { return; } // add image to the "images" property list imagesVectorPropertyValue.push_back(imageID); imagesVectorProperty->SetValue(imagesVectorPropertyValue); propertyList->SetProperty("images", imagesVectorProperty); // add the image itself 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& 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 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 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 imagesVectorProperty->SetValue(imagesVectorPropertyValue); } // remove the image instance itself propertyList->DeleteProperty(imageID); } 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 segmentationsVectorProperty = dynamic_cast*>(propertyList->GetProperty("segmentations")); std::vector segmentationsVectorPropertyValue; if (nullptr == segmentationsVectorProperty) { segmentationsVectorProperty = VectorProperty::New(); } else { segmentationsVectorPropertyValue = segmentationsVectorProperty->GetValue(); } - auto existingImage = std::find(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID); - if (existingImage != segmentationsVectorPropertyValue.end()) + auto existingSegmentation = std::find(segmentationsVectorPropertyValue.begin(), segmentationsVectorPropertyValue.end(), segmentationID); + if (existingSegmentation != segmentationsVectorPropertyValue.end()) { return; } // add segmentation to the "segmentations" property list segmentationsVectorPropertyValue.push_back(segmentationID); segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue); propertyList->SetProperty("segmentations", segmentationsVectorProperty); // add the segmentation itself 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& 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 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 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 segmentationsVectorProperty->SetValue(segmentationsVectorPropertyValue); } // remove the lesion instance itself 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 lesionsVectorPropertyValue; if (nullptr == lesionsVectorProperty) { lesionsVectorProperty = VectorProperty::New(); } else { lesionsVectorPropertyValue = lesionsVectorProperty->GetValue(); } 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 lesionsVectorPropertyValue.push_back(lesion.UID); // overwrite the current vector property with the new, extended string vector 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 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 in the storage."; return; } 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 " << segmentationID << " in the storage. Cannot link segmentation to lesion."; return; } 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 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 " << segmentationID << " in the storage. Cannot unlink lesion from segmentation."; return; } 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 (segmentationVectorPropertyValue.size() != 2) { MITK_DEBUG << "Incorrect data storage. Not two (2) values stored."; return; } // the second value of the segmentation vector is the ID of the referenced lesion // set the lesion reference to an empty string for removal 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 in the storage."; return; } // remove the lesion reference from the list of all lesions of the current case 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(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 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 == 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 controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); std::vector controlPointsVectorPropertyValue; if (nullptr == controlPointsVectorProperty) { controlPointsVectorProperty = VectorProperty::New(); } else { controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); } 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 controlPointsVectorPropertyValue.push_back(controlPoint.UID); // overwrite the current vector property with the new, extended string vector 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::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* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); if (nullptr == controlPointsVectorProperty) { MITK_DEBUG << "Could not find any control point in the storage."; return; } 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 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. Cannot link data to control point."; return; } 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 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::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* imageVectorProperty = dynamic_cast*>(propertyList->GetProperty(imageID)); if (nullptr == imageVectorProperty) { MITK_DEBUG << "Could not find the date " << imageID << " in the storage. Cannot unlink control point from date."; return; } 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 image vector is the ID of the referenced control point // set the control point reference to an empty string for removal imageVectorPropertyValue[1] = ""; imageVectorProperty->SetValue(imageVectorPropertyValue); } -void mitk::RelationStorage::RemoveControlPointFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) +void mitk::RelationStorage::RemoveControlPoint(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* controlPointsVectorProperty = dynamic_cast*>(propertyList->GetProperty("controlpoints")); if (nullptr == controlPointsVectorProperty) { 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 controlPointsVectorPropertyValue = controlPointsVectorProperty->GetValue(); controlPointsVectorPropertyValue.erase(std::remove(controlPointsVectorPropertyValue.begin(), controlPointsVectorPropertyValue.end(), controlPoint.UID), controlPointsVectorPropertyValue.end()); - controlPointsVectorProperty->SetValue(controlPointsVectorPropertyValue); + if (controlPointsVectorPropertyValue.empty()) + { + // no more control points stored -> remove the control point property list + propertyList->DeleteProperty("controlpoints"); + } + else + { + // or store the modified vector value + 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 examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); std::vector examinationPeriodsVectorPropertyValue; if (nullptr == examinationPeriodsVectorProperty) { examinationPeriodsVectorProperty = VectorProperty::New(); } else { examinationPeriodsVectorPropertyValue = examinationPeriodsVectorProperty->GetValue(); } 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 examinationPeriodsVectorPropertyValue.push_back(examinationPeriod.UID); // overwrite the current vector property with the new, extended string vector 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) { 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 controlPointUIDsVectorPropertyValue = controlPointUIDsVectorProperty->GetValue(); // store the control point 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(controlPointUIDsVectorPropertyValue.begin(), controlPointUIDsVectorPropertyValue.end(), lambda); // store the modified and sorted control point UID vector of this examination period controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorPropertyValue); } 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 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 (controlPointUIDsVectorPropertyValue.size() < 2) { MITK_DEBUG << "Incorrect examination period storage. At least one (1) control point ID has to be stored."; return; } else { controlPointUIDsVectorPropertyValue.erase(std::remove(controlPointUIDsVectorPropertyValue.begin(), controlPointUIDsVectorPropertyValue.end(), controlPoint.UID), controlPointUIDsVectorPropertyValue.end()); if (controlPointUIDsVectorPropertyValue.size() < 2) { - RemoveExaminationPeriodFromCase(caseID, examinationPeriod); + RemoveExaminationPeriod(caseID, examinationPeriod); } else { // store the modified vector value controlPointUIDsVectorProperty->SetValue(controlPointUIDsVectorPropertyValue); } } } -void mitk::RelationStorage::RemoveExaminationPeriodFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) +void mitk::RelationStorage::RemoveExaminationPeriod(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 examinationPeriodsVectorProperty = dynamic_cast*>(propertyList->GetProperty("examinationperiods")); if (nullptr == examinationPeriodsVectorProperty) { MITK_DEBUG << "Could not find any examination periods in the storage."; return; } 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 examinationPeriodsVectorProperty->SetValue(examinationPeriodsVectorPropertyValue); } + + // remove the examination period instance itself + propertyList->DeleteProperty(examinationPeriod.UID); } 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 informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); std::vector informationTypesVectorPropertyValue; if (nullptr == informationTypesVectorProperty) { informationTypesVectorProperty = VectorProperty::New(); } else { informationTypesVectorPropertyValue = informationTypesVectorProperty->GetValue(); } const auto existingInformationType = std::find(informationTypesVectorPropertyValue.begin(), informationTypesVectorPropertyValue.end(), informationType); if (existingInformationType == informationTypesVectorPropertyValue.end()) { // at first: add the information type to the storage 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* 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 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 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* 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 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 image vector is the information type // set the information type to an empty string for removal imageVectorPropertyValue[0] = ""; imageVectorProperty->SetValue(imageVectorPropertyValue); } -void mitk::RelationStorage::RemoveInformationTypeFromCase(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +void mitk::RelationStorage::RemoveInformationType(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* informationTypesVectorProperty = dynamic_cast*>(propertyList->GetProperty("informationtypes")); if (nullptr == informationTypesVectorProperty) { MITK_DEBUG << "Could not find any information type in the storage."; return; } 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 informationTypesVectorProperty->SetValue(informationTypesVectorPropertyValue); } } diff --git a/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp index c94087ca89..f8919d2c8d 100644 --- a/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp @@ -1,508 +1,479 @@ /*=================================================================== 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::LesionClassVector mitk::SemanticRelationsInference::GetAllLesionClassesOfCase(const SemanticTypes::CaseID& 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::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); return RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); } mitk::SemanticTypes::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfImage(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::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) { // 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::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { SemanticTypes::LesionVector allLesions = RelationStorage::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](const SemanticTypes::Lesion& lesion) { 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 = 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) { SemanticTypes::Lesion representedLesion = RelationStorage::GetLesionOfSegmentation(caseID, segmentationID); if (representedLesion.UID.empty()) { return false; } return true; } bool mitk::SemanticRelationsInference::IsLesionPresent(const SemanticTypes::Lesion& lesion, const DataNode* dataNode) { try { 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 = 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::GetAllImageIDsOfLesion(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 << "."; } 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 = RelationStorage::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()) { allImageIDsOfLesion.push_back(imageID); } } std::sort(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()); allImageIDsOfLesion.erase(std::unique(allImageIDsOfLesion.begin(), allImageIDsOfLesion.end()), allImageIDsOfLesion.end()); return allImageIDsOfLesion; } 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 RelationStorage::GetControlPointOfImage(caseID, dataNodeID); } mitk::SemanticTypes::ControlPointVector mitk::SemanticRelationsInference::GetAllControlPointsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) { SemanticTypes::ControlPointVector allControlPoints = RelationStorage::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](const SemanticTypes::ControlPoint& controlPoint) { return !SpecificImageExists(caseID, lesion, controlPoint); }; allControlPoints.erase(std::remove_if(allControlPoints.begin(), allControlPoints.end(), lambda), allControlPoints.end()); return allControlPoints; } 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) { 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 = 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; } } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) { SemanticTypes::ExaminationPeriodVector allExaminationPeriods = RelationStorage::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::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 RelationStorage::GetInformationTypeOfImage(caseID, imageID); } mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelationsInference::GetAllInformationTypesOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) { 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) { return !SpecificImageExists(caseID, informationType, controlPoint); }; allInformationTypes.erase(std::remove_if(allInformationTypes.begin(), allInformationTypes.end(), lambda), allInformationTypes.end()); return allInformationTypes; } bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) { 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; } } 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) { 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 = 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/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp index e2b6060bbd..389187c215 100644 --- a/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsIntegration.cpp @@ -1,442 +1,442 @@ /*=================================================================== 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 image 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); SetControlPointOfImage(imageNode, controlPoint); } void mitk::SemanticRelationsIntegration::RemoveImage(const DataNode* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image 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 = RelationStorage::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."; } 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."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); SemanticTypes::ID segmentationNodeID = GetIDFromDataNode(segmentationNode); RelationStorage::RemoveSegmentation(caseID, segmentationNodeID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::SetControlPointOfImage(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); 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 LinkImageToControlPoint(imageNode, existingControlPoint, false); } catch (const SemanticRelationException&) { mitkThrowException(SemanticRelationException) << "The image data node can not be linked. Inconsistency in the semantic relations storage assumed."; } } else { try { AddControlPointAndLinkImage(imageNode, 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 image data node can not be linked. Inconsistency in the semantic relations storage assumed."; } } ClearControlPoints(caseID); NotifyObserver(caseID); } void mitk::SemanticRelationsIntegration::AddControlPointAndLinkImage(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); if (SemanticRelationsInference::InstanceExists(caseID, controlPoint)) { mitkThrowException(SemanticRelationException) << "The control point " << controlPoint.UID << " to add already exists for the given case. \n Use 'LinkImageToControlPoint' instead."; } RelationStorage::AddControlPoint(caseID, controlPoint); LinkImageToControlPoint(imageNode, controlPoint, checkConsistence); } void mitk::SemanticRelationsIntegration::LinkImageToControlPoint(const DataNode* imageNode, const SemanticTypes::ControlPoint& controlPoint, bool checkConsistence) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); if (SemanticRelationsInference::InstanceExists(caseID, controlPoint)) { SemanticTypes::ID dataID = GetIDFromDataNode(imageNode); 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* imageNode) { if (nullptr == imageNode) { mitkThrowException(SemanticRelationException) << "Not a valid image data node."; } SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); SemanticTypes::ID dataID = GetIDFromDataNode(imageNode); SemanticTypes::ControlPoint controlPoint = RelationStorage::GetControlPointOfImage(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); + RelationStorage::RemoveInformationType(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); + RelationStorage::RemoveControlPoint(caseID, controlPoint); } }