diff --git a/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h new file mode 100644 index 0000000000..857caff09e --- /dev/null +++ b/Modules/SemanticRelations/include/mitkSemanticRelationsInference.h @@ -0,0 +1,278 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef MITKSEMANTICRELATIONSINFERENCE_H +#define MITKSEMANTICRELATIONSINFERENCE_H + +#include + +// semantic relations module +#include "mitkSemanticTypes.h" + +// mitk core +#include + +namespace mitk +{ + /** + * @brief The API provides functions to query image relations and instances + * that are helpful during follow-up examination, like control-points (time period), + * types of the images or lesions that may be visible on multiple images. + * + * The class is able to generate IDs from given data nodes using DICOM information. + * These IDs are used to identify the corresponding instances of a specific case. + * The case can also be directly identified by the given case ID. + * + * In order for most functions to work the case ID has to be used as a parameter. + * If not, these functions do nothing. + */ + namespace SemanticRelationsInference + { + + /************************************************************************/ + /* functions to get instances / attributes */ + /************************************************************************/ + /** + * @brief Return a vector of all lesions that are currently available for the given case. + * The lesions may be marked by a segmentation or may be empty - with no connection to a specific image / segmentation of the case data. + * If no lesions are stored for the current case, an empty vector is returned. + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of lesions. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionVector GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID); + /** + * @brief Return a vector of lesion classes that are currently available for the given case. + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of lesion classes. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::LesionClassVector GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID); + /** + * @brief Return the lesion that is defined by the given segmentation data. + * + * @pre The given segmentation data node has to be valid (!nullptr). + * @throw SemanticRelationException, if the given segmentation data node is invalid (==nullptr). + * @pre The segmentation data node has to represent a lesion. If not, the retrieved lesion will be empty, which leads to an exception. + * @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion'). + * + * @param segmentationNode The segmentation identifier is extracted from the given data node. + * @return The represented lesion. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetRepresentedLesion(const DataNode* segmentationNode); + /** + * @brief Returns the lesion that is defined by the segmentation identified by the segmentation ID. + * + * @throw SemanticRelationException, if the segmentation does not represent an existing lesion (this can be checked via 'IsRepresentingALesion'). + * + * @param caseID The current case identifier is defined by the given string. + * @param segmentationID The segmentation node identifier is defined by the given string. + * @return The represented lesion. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::Lesion GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID); + /** + * @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 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 data node exists in the relation storage. + * The function receives the case- and the node-ID from the DICOM tags of the node itself. + * It uses node predicates to decide if the node is an image or a segmentation node and searches + * through the corresponding relations. + * + * @param dataNode A data node to check. + * @return True, if the data node exists; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const DataNode* dataNode); + /** + * @brief Check if the given lesion instance exists. + * This function can be used before calling 'GetAllSegmentationsOfLesion' in order to avoid a possible exception. + * This function can be used before calling 'AddLesionInstance' in order to avoid a possible exception. + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @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 segmentation IDs that identify segmentations that define the given lesion. + * These segmentations don't have to be linked to the same image. + * If the lesion is not referred to by any segmentation, an empty vector is returned. + * + * @pre The UID of the lesion has to exist for a lesion instance. + * @throw SemanticRelationException, if UID of the lesion does not exist for a lesion instance (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param lesion A Lesion with a UID that identifies the corresponding lesion instance. + * @return A vector of IDs identifying segmentations that define the given lesion. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion); + /** + * @brief Return a vector of all control points that are valid for the given case. + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of control points. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPointVector GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID); + /** + * @brief Return the control point of a data node. + * If the data node is not linked to a control point or the data node refers to a non-existing control point, + * a control point with an empty UID is returned. + * + * @pre The given image data node has to be valid (!nullptr). + * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). + * + * @param dataNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. + * @return The control point of the given data node. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointOfImage(const DataNode* dataNode); + /** + * @brief Return the control point of a data node identified by the image ID. + * If the data node is not linked to a control point or the data node refers to a non-existing control point, + * a control point with an empty UID is returned. + * + * @param caseID The current case identifier is defined by the given string. + * @param imageID The image node identifier is defined by the given string. + * @return The control point of the image node, defined by the image node ID. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ControlPoint GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + /** + * @brief Return a vector of all image IDs that identify images that link to the given control point. + * If the control point is not referred to by any image, an empty vector is returned. + * + * @pre The UID of the control point has to exist for a control point instance. + * @throw SemanticRelationException, if the UID of the control point does not exist for a control point instance (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * @return A vector of IDs identifying images that link to the given control point. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + /** + * @brief Check if the given control point instance exists. + * This function can be used before calling 'GetAllDataOfControlPoint' in order to avoid a possible exception. + * This function can be used before adding, linking and unlinking control points to avoid a possible exception. + * + * @param caseID The current case identifier is defined by the given string. + * @param controlPoint A control point with a UID that identifies the corresponding control point instance. + * @return True, if the control point instance exists; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint); + /** + * @brief Return a vector of all examination periods nodes that are valid for the given case. + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of examination periods. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::ExaminationPeriodVector GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID); + /** + * @brief Check if the given examination period instance exists. + * This function can be used before calling 'AddExaminationPeriod' in order to avoid a possible exception. + * + * @param caseID The current case identifier is defined by the given string. + * @param examinationPeriod An examination period with a UID that identifies the corresponding examination period instance. + * @return True, if the examination period instance exists; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod); + /** + * @brief Return a vector of all information types that are valid for the given case. + * + * @param caseID The current case identifier is defined by the given string. + * @return A vector of information types. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationTypeVector GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID); + /** + * @brief Return the information type of the given image. + * If the image does not contain any information type, an empty information type is returned. + * + * @pre The given image data node has to be valid (!nullptr). + * @throw SemanticRelationException, if the given image data node is invalid (==nullptr). + * + * @param imageNode The current case identifier is extracted from the given data node, which contains DICOM information about the case. + * @return The information type of the given data node. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationType GetInformationTypeOfImage(const DataNode* imageNode); + /** + * @brief Return the information type of the given image. + * If the image does not contain any information type, an empty information type is returned. + * + * @param caseID The current case identifier is defined by the given string. + * @param imageID The image node identifier is defined by the given string. + * @return The information type of the image node, defined by the image node ID. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::InformationType GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID); + /** + * @brief Return a vector of all image IDs that identify images that are of the given information type. + * If the information type is not used by any image, an empty vector is returned. + * + * @pre The information type has to exist. + * @throw SemanticRelationException, if the information type does not exist (this can be checked via 'InstanceExists'). + * + * @param caseID The current case identifier is defined by the given string. + * @param informationType An information type. + * @return A vector of IDs identifying images that are of the given information type. + */ + MITKSEMANTICRELATIONS_EXPORT SemanticTypes::IDVector GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); + /** + * @brief Check if the given information type exists. + * This function can be used before calling 'GetAllDataOfInformationType' in order to avoid a possible exception. + * + * @param caseID The current case identifier is defined by the given string. + * @param informationType An information type. + * @return True, if the information type exists; false otherwise. + */ + MITKSEMANTICRELATIONS_EXPORT bool InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType); + /** + * @brief Return a vector of all CaseIDs that are currently available. + * + * @return A vector of CaseIDs as strings. + */ + MITKSEMANTICRELATIONS_EXPORT std::vector GetAllCaseIDs(); + /** + * @brief Remove all control points from the storage that are not referenced by any image anymore. + * This might happen if an image has been removed (and unlinked from the corresponding control point) + * or if the user sets a new control point for an image manually in the GUI. + * + * @param caseID The current case identifier is defined by the given string. + */ + void ClearControlPoints(const SemanticTypes::CaseID& caseID); + + } // namespace SemanticRelationsInference +} // namespace mitk + +#endif // MITKSEMANTICRELATIONSINFERENCE_H diff --git a/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp new file mode 100644 index 0000000000..9f3bdf1d59 --- /dev/null +++ b/Modules/SemanticRelations/src/mitkSemanticRelationsInference.cpp @@ -0,0 +1,394 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkSemanticRelationsInference.h" + +// semantic relations module +#include "mitkControlPointManager.h" +#include "mitkDICOMHelper.h" +#include "mitkNodePredicates.h" +#include "mitkRelationStorage.h" +#include "mitkSemanticRelationException.h" + +/************************************************************************/ +/* functions to get instances / attributes */ +/************************************************************************/ + +mitk::SemanticTypes::LesionVector mitk::SemanticRelationsInference::GetAllLesionsOfCase(const SemanticTypes::CaseID& caseID) +{ + return RelationStorage::GetAllLesionsOfCase(caseID); +} + +mitk::SemanticTypes::LesionClassVector mitk::SemanticRelationsInference::GetAllLesionClassesOfCase(const SemanticTypes::CaseID& caseID) +{ + SemanticTypes::LesionVector allLesionsOfCase = GetAllLesionsOfCase(caseID); + SemanticTypes::LesionClassVector allLesionClassesOfCase; + + for (const auto& lesion : allLesionsOfCase) + { + allLesionClassesOfCase.push_back(lesion.lesionClass); + } + + // remove duplicate entries + auto lessThan = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) + { + return lesionClassLeft.UID < lesionClassRight.UID; + }; + + auto equal = [](const SemanticTypes::LesionClass& lesionClassLeft, const SemanticTypes::LesionClass& lesionClassRight) + { + return lesionClassLeft.UID == lesionClassRight.UID; + }; + + std::sort(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), lessThan); + allLesionClassesOfCase.erase(std::unique(allLesionClassesOfCase.begin(), allLesionClassesOfCase.end(), equal), allLesionClassesOfCase.end()); + + return allLesionClassesOfCase; +} + +mitk::SemanticTypes::Lesion mitk::SemanticRelationsInference::GetRepresentedLesion(const DataNode* segmentationNode) +{ + if (nullptr == segmentationNode) + { + mitkThrowException(SemanticRelationException) << "Not a valid segmentation data node."; + } + + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(segmentationNode); + SemanticTypes::ID segmentationID = GetIDFromDataNode(segmentationNode); + SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); + + if (representedLesion.UID.empty()) + { + mitkThrowException(SemanticRelationException) << "Could not find a represented lesion instance for the given segmentation node " << segmentationNode->GetName(); + } + else + { + return representedLesion; + } +} + +mitk::SemanticTypes::Lesion mitk::SemanticRelationsInference::GetRepresentedLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) +{ + SemanticTypes::Lesion representedLesion = RelationStorage::GetRepresentedLesion(caseID, segmentationID); + + if (representedLesion.UID.empty()) + { + mitkThrowException(SemanticRelationException) << "Could not find a represented lesion instance for the given segmentation node ID " << segmentationID; + } + else + { + return representedLesion; + } +} + +bool mitk::SemanticRelationsInference::IsRepresentingALesion(const DataNode* segmentationNode) +{ + try + { + SemanticTypes::Lesion representedLesion = GetRepresentedLesion(segmentationNode); + return true; + } + catch (const Exception&) + { + return false; + } +} + +bool mitk::SemanticRelationsInference::IsRepresentingALesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& segmentationID) +{ + try + { + SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); + return true; + } + catch (const Exception&) + { + return false; + } +} + +bool mitk::SemanticRelationsInference::IsLesionPresentOnSegmentation(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion, const SemanticTypes::ID& segmentationID) +{ + try + { + const auto representedLesion = GetRepresentedLesion(caseID, segmentationID); + return lesion.UID == representedLesion.UID; + } + catch (const SemanticRelationException&) + { + return false; + } +} + +bool mitk::SemanticRelationsInference::InstanceExists(const DataNode* dataNode) +{ + try + { + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(dataNode); + SemanticTypes::ID dataNodeID = GetIDFromDataNode(dataNode); + + if (NodePredicates::GetImagePredicate()->CheckNode(dataNode)) + { + std::vector allImageIDsOfCase = RelationStorage::GetAllImageIDsOfCase(caseID); + return std::find(allImageIDsOfCase.begin(), allImageIDsOfCase.end(), dataNodeID) != allImageIDsOfCase.end(); + } + else if (NodePredicates::GetSegmentationPredicate()->CheckNode(dataNode)) + { + std::vector allSegmentationIDsOfCase = RelationStorage::GetAllSegmentationIDsOfCase(caseID); + return std::find(allSegmentationIDsOfCase.begin(), allSegmentationIDsOfCase.end(), dataNodeID) != allSegmentationIDsOfCase.end(); + } + else + { + return false; + } + } + catch (const SemanticRelationException&) + { + return false; + } +} + +bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) +{ + SemanticTypes::LesionVector allLesions = GetAllLesionsOfCase(caseID); + + // filter all lesions: check for equality with the given lesion using a lambda function + auto lambda = [&lesion](const SemanticTypes::Lesion& currentLesion) { return currentLesion.UID == lesion.UID; }; + const auto existingLesion = std::find_if(allLesions.begin(), allLesions.end(), lambda); + + if (existingLesion != allLesions.end()) + { + return true; + } + else + { + return false; + } +} + +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllSegmentationIDsOfLesion(const SemanticTypes::CaseID& caseID, const SemanticTypes::Lesion& lesion) +{ + if (InstanceExists(caseID, lesion)) + { + // lesion exists, retrieve all case segmentations from the storage + SemanticTypes::IDVector allSegmentationIDs = RelationStorage::GetAllSegmentationIDsOfCase(caseID); + + // filter all segmentationIDs: check for semantic relation with the given lesion using a lambda function + auto lambda = [&lesion, caseID](const SemanticTypes::ID& segmentationID) + { + try + { + SemanticTypes::Lesion representedLesion = GetRepresentedLesion(caseID, segmentationID); + return lesion.UID != representedLesion.UID; + } + catch (const SemanticRelationException&) + { + return true; + } + }; + + allSegmentationIDs.erase(std::remove_if(allSegmentationIDs.begin(), allSegmentationIDs.end(), lambda), allSegmentationIDs.end()); + + return allSegmentationIDs; + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing lesion instance for the given caseID " << caseID << " and lesion " << lesion.UID << "."; + } +} + +mitk::SemanticTypes::ControlPointVector mitk::SemanticRelationsInference::GetAllControlPointsOfCase(const SemanticTypes::CaseID& caseID) +{ + return RelationStorage::GetAllControlPointsOfCase(caseID); +} + +mitk::SemanticTypes::ControlPoint mitk::SemanticRelationsInference::GetControlPointOfImage(const DataNode* imageNode) +{ + if (nullptr == imageNode) + { + mitkThrowException(SemanticRelationException) << "Not a valid data node."; + } + + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); + SemanticTypes::ID dataNodeID = GetIDFromDataNode(imageNode); + return GetControlPointOfImage(caseID, dataNodeID); +} + +mitk::SemanticTypes::ControlPoint mitk::SemanticRelationsInference::GetControlPointOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) +{ + return RelationStorage::GetControlPointOfImage(caseID, imageID); +} + +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfControlPoint(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) +{ + if (InstanceExists(caseID, controlPoint)) + { + // control point exists, retrieve all imageIDs from the storage + SemanticTypes::IDVector allImageIDs = RelationStorage::GetAllImageIDsOfCase(caseID); + + // filter all imageIDs to remove the ones with a different control point using a lambda function + auto lambda = [&controlPoint, &caseID](const SemanticTypes::ID& imageID) + { + return controlPoint.UID != RelationStorage::GetControlPointOfImage(caseID, imageID).UID; + }; + + allImageIDs.erase(std::remove_if(allImageIDs.begin(), allImageIDs.end(), lambda), allImageIDs.end()); + + return allImageIDs; + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing control point instance for the given caseID " << caseID << " and control point " << controlPoint.UID << "."; + } +} + +bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ControlPoint& controlPoint) +{ + SemanticTypes::ControlPointVector allControlPoints = GetAllControlPointsOfCase(caseID); + + // filter all control points: check for equality with the given control point using a lambda function + auto lambda = [&controlPoint](const SemanticTypes::ControlPoint& currentControlPoint) { return currentControlPoint.UID == controlPoint.UID; }; + const auto existingControlPoint = std::find_if(allControlPoints.begin(), allControlPoints.end(), lambda); + + if (existingControlPoint != allControlPoints.end()) + { + return true; + } + else + { + return false; + } +} + +mitk::SemanticTypes::ExaminationPeriodVector mitk::SemanticRelationsInference::GetAllExaminationPeriodsOfCase(const SemanticTypes::CaseID& caseID) +{ + return RelationStorage::GetAllExaminationPeriodsOfCase(caseID); +} + +bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::ExaminationPeriod& examinationPeriod) +{ + SemanticTypes::ExaminationPeriodVector allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); + + // filter all examination periods: check for equality with the given examination period using a lambda function + auto lambda = [&examinationPeriod](const SemanticTypes::ExaminationPeriod& currentExaminationPeriod) { return currentExaminationPeriod.UID == examinationPeriod.UID; }; + const auto existingExaminationPeriod = std::find_if(allExaminationPeriods.begin(), allExaminationPeriods.end(), lambda); + + if (existingExaminationPeriod != allExaminationPeriods.end()) + { + return true; + } + else + { + return false; + } +} + +mitk::SemanticTypes::InformationTypeVector mitk::SemanticRelationsInference::GetAllInformationTypesOfCase(const SemanticTypes::CaseID& caseID) +{ + return RelationStorage::GetAllInformationTypesOfCase(caseID); +} + +mitk::SemanticTypes::InformationType mitk::SemanticRelationsInference::GetInformationTypeOfImage(const DataNode* imageNode) +{ + if (nullptr == imageNode) + { + mitkThrowException(SemanticRelationException) << "Not a valid image data node."; + } + + SemanticTypes::CaseID caseID = GetCaseIDFromDataNode(imageNode); + SemanticTypes::ID imageID = GetIDFromDataNode(imageNode); + return GetInformationTypeOfImage(caseID, imageID); +} + +mitk::SemanticTypes::InformationType mitk::SemanticRelationsInference::GetInformationTypeOfImage(const SemanticTypes::CaseID& caseID, const SemanticTypes::ID& imageID) +{ + return RelationStorage::GetInformationTypeOfImage(caseID, imageID); +} + +mitk::SemanticTypes::IDVector mitk::SemanticRelationsInference::GetAllImageIDsOfInformationType(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +{ + if (InstanceExists(caseID, informationType)) + { + // information type exists, retrieve all imageIDs from the storage + SemanticTypes::IDVector allImageIDs = RelationStorage::GetAllImageIDsOfCase(caseID); + + // filter all images to remove the ones with a different information type using a lambda function + auto lambda = [&informationType, caseID](const SemanticTypes::ID& imageID) + { + return informationType != RelationStorage::GetInformationTypeOfImage(caseID, imageID); + }; + + allImageIDs.erase(std::remove_if(allImageIDs.begin(), allImageIDs.end(), lambda), allImageIDs.end()); + + return allImageIDs; + } + else + { + mitkThrowException(SemanticRelationException) << "Could not find an existing information type for the given caseID " << caseID << " and information type " << informationType; + } +} + +bool mitk::SemanticRelationsInference::InstanceExists(const SemanticTypes::CaseID& caseID, const SemanticTypes::InformationType& informationType) +{ + SemanticTypes::InformationTypeVector allInformationTypes = GetAllInformationTypesOfCase(caseID); + + // filter all information types: check for equality with the given information type using a lambda function + auto lambda = [&informationType](const SemanticTypes::InformationType& currentInformationType) { return currentInformationType == informationType; }; + const auto existingInformationType = std::find_if(allInformationTypes.begin(), allInformationTypes.end(), lambda); + + if (existingInformationType != allInformationTypes.end()) + { + return true; + } + else + { + return false; + } +} + +std::vector mitk::SemanticRelationsInference::GetAllCaseIDs() +{ + return RelationStorage::GetAllCaseIDs(); +} + +void mitk::SemanticRelationsInference::ClearControlPoints(const SemanticTypes::CaseID& caseID) +{ + SemanticTypes::ControlPointVector allControlPointsOfCase = GetAllControlPointsOfCase(caseID); + + std::vector allImageIDsVectorValue = RelationStorage::GetAllImageIDsOfCase(caseID); + SemanticTypes::ControlPointVector referencedControlPoints; + for (const auto& imageID : allImageIDsVectorValue) + { + auto controlPointOfImage = GetControlPointOfImage(caseID, imageID); + referencedControlPoints.push_back(controlPointOfImage); + } + + std::sort(allControlPointsOfCase.begin(), allControlPointsOfCase.end()); + std::sort(referencedControlPoints.begin(), referencedControlPoints.end()); + + SemanticTypes::ControlPointVector nonReferencedControlPoints; + std::set_difference(allControlPointsOfCase.begin(), allControlPointsOfCase.end(), + referencedControlPoints.begin(), referencedControlPoints.end(), + std::inserter(nonReferencedControlPoints, nonReferencedControlPoints.begin())); + + auto allExaminationPeriods = GetAllExaminationPeriodsOfCase(caseID); + for (const auto& controlPoint : nonReferencedControlPoints) + { + const auto& examinationPeriod = FindExaminationPeriod(controlPoint, allExaminationPeriods); + RelationStorage::RemoveControlPointFromExaminationPeriod(caseID, controlPoint, examinationPeriod); + RelationStorage::RemoveControlPointFromCase(caseID, controlPoint); + } +}