diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index fdd84f41e6..ce537bd427 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,316 +1,316 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCoreActivator.cpp mitkCoreObjectFactoryBase.cpp mitkCoreObjectFactory.cpp mitkCoreServices.cpp mitkException.cpp Algorithms/mitkBaseDataSource.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkCompositePixelValueToString.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkExtractSliceFilter2.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAnatomicalStructureColorPresets.cpp DataManagement/mitkArbitraryTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataStorage.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGeometryTransformHolder.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkGenericIDRelationRule.cpp DataManagement/mitkIdentifiable.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageReadAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp - DataManagement/mitkImageToImageRelationRule.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageVtkReadAccessor.cpp DataManagement/mitkImageVtkWriteAccessor.cpp DataManagement/mitkImageWriteAccessor.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkIPersistenceService.cpp DataManagement/mitkIPropertyAliases.cpp DataManagement/mitkIPropertyDescriptions.cpp DataManagement/mitkIPropertyExtensions.cpp DataManagement/mitkIPropertyFilters.cpp DataManagement/mitkIPropertyOwner.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkIPropertyProvider.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLine.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMaterial.cpp DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDataUID.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateFunction.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkPropertyKeyPath.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkPropertyNameHelper.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkPropertyPersistence.cpp DataManagement/mitkPropertyPersistenceInfo.cpp DataManagement/mitkPropertyRelationRuleBase.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkScaleOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp + DataManagement/mitkSourceImageRelationRule.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTemporoSpatialStringProperty.cpp DataManagement/mitkUIDManipulator.cpp DataManagement/mitkVector.cpp DataManagement/mitkVectorProperty.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkIPropertyRelations.cpp DataManagement/mitkPropertyRelations.cpp Interactions/mitkAction.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventFactory.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkInteractionEventObserver.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkXML2EventParser.cpp IO/mitkAbstractFileIO.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkCustomMimeType.cpp IO/mitkFileReader.cpp IO/mitkFileReaderRegistry.cpp IO/mitkFileReaderSelector.cpp IO/mitkFileReaderWriterBase.cpp IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp IO/mitkFileWriterSelector.cpp IO/mitkGeometry3DToXML.cpp IO/mitkIFileIO.cpp IO/mitkIFileReader.cpp IO/mitkIFileWriter.cpp IO/mitkGeometryDataReaderService.cpp IO/mitkGeometryDataWriterService.cpp IO/mitkImageGenerator.cpp IO/mitkImageVtkLegacyIO.cpp IO/mitkImageVtkXmlIO.cpp IO/mitkIMimeTypeProvider.cpp IO/mitkIOConstants.cpp IO/mitkIOMimeTypes.cpp IO/mitkIOUtil.cpp IO/mitkItkImageIO.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkLegacyFileReaderService.cpp IO/mitkLegacyFileWriterService.cpp IO/mitkLocaleSwitch.cpp IO/mitkLog.cpp IO/mitkMimeType.cpp IO/mitkMimeTypeProvider.cpp IO/mitkOperation.cpp IO/mitkPixelType.cpp IO/mitkPointSetReaderService.cpp IO/mitkPointSetWriterService.cpp IO/mitkProportionalTimeGeometryToXML.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSurfaceStlIO.cpp IO/mitkSurfaceVtkIO.cpp IO/mitkSurfaceVtkLegacyIO.cpp IO/mitkSurfaceVtkXmlIO.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkPreferenceListReaderOptionsFunctor.cpp Rendering/mitkAbstractAnnotationRenderer.cpp Rendering/mitkAnnotationUtils.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkMapper.cpp Rendering/mitkAnnotation.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowFrame.cpp #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module Rendering/mitkSurfaceVtkMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/DisplayConfigMITKNoCrosshair.xml Interactions/DisplayConfigMITKRotation.xml Interactions/DisplayConfigMITKRotationUnCoupled.xml Interactions/DisplayConfigMITKSwivel.xml Interactions/DisplayConfigMITKLimited.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml mitkAnatomicalStructureColorPresets.xml ) diff --git a/Modules/Core/include/mitkImageToImageRelationRule.h b/Modules/Core/include/mitkSourceImageRelationRule.h similarity index 87% rename from Modules/Core/include/mitkImageToImageRelationRule.h rename to Modules/Core/include/mitkSourceImageRelationRule.h index f31e33877d..e6179cca4b 100644 --- a/Modules/Core/include/mitkImageToImageRelationRule.h +++ b/Modules/Core/include/mitkSourceImageRelationRule.h @@ -1,169 +1,173 @@ /*=================================================================== 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 mitkGenericIDRelationRule_h #define mitkGenericIDRelationRule_h #include "mitkPropertyRelationRuleBase.h" #include "mitkImage.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable : 4251) #endif namespace mitk { - /**This rule class can be used for relations between two images. + /**This rule class can be used for relations that reference an image as source for a destination entity. + (e.g. an image that is used to generate the relation source). The ID-layer is supported like for GenericIDReleations. So it can be used for all ID based relations between PropertyProviders that also implement the interface identifiable. In addition the rule uses the data-layer to deduce/define relations. For this layer it uses properties compliant to DICOM. Thus (1) the information is stored in a DICOM Source Image Sequence item (0x0008,0x2112) and (2) the destination must have properties DICOM SOP Instance UIDs (0x0008, 0x0018) and DICOM SOP Class UID (0x0008, 0x0016). If the destination does not have this properties, no connection can be made on the data-layer. @remark Please note that PropertyRelationRules and DICOM use the term "source" differently. The DICOM source (image) equals the PropertyRelationRule destination. This is due to - an inverted relation direction. So a derived image in the context of ImateToImageRelationRules is the source - and points to the oringal image, it derives from. In the context of DICOM this referenced original image would be - called source image. + an inverted relation direction. So in the context of the SourceImageRelationRule interface a derived data is + the source and points to the original image, it derives from. In the context of DICOM this referenced original image would be + called source image (as the name of this class). In order to be able to use this class for different relation types (DICOM would call it purposes), the purposeTag is used. It must be specified when creating a rule instance. The purposeTag will be used as suffix for the rule ID of the instance and therefore allows to create specific and distinguishable rules instances based on this class. One may also specify the display name and the role names of the instance. If not specified the default values - are used (display name: " relation", source role name: "derived image", + are used (display name: " relation", source role name: "derived data", destination role name: "source image") */ - class MITKCORE_EXPORT ImageToImageRelationRule : public mitk::PropertyRelationRuleBase + class MITKCORE_EXPORT SourceImageRelationRule : public mitk::PropertyRelationRuleBase { public: - mitkClassMacro(ImageToImageRelationRule, PropertyRelationRuleBase); - itkCloneMacro(Self); + mitkClassMacro(SourceImageRelationRule, PropertyRelationRuleBase); + itkNewMacro(Self); mitkNewMacro1Param(Self, const RuleIDType &); mitkNewMacro2Param(Self, const RuleIDType &, const std::string &); mitkNewMacro4Param(Self, const RuleIDType &, const std::string &, const std::string &, const std::string &); using RuleIDType = PropertyRelationRuleBase::RuleIDType; using RelationUIDType = PropertyRelationRuleBase::RelationUIDType; using RelationUIDVectorType = PropertyRelationRuleBase::RelationUIDVectorType; /** Returns an ID string that identifies the rule class */ RuleIDType GetRuleID() const override; bool IsAbstract() const override; /** Returns a human readable string that can be used to describe the rule. Does not need to be unique.*/ std::string GetDisplayName() const override; /** Returns a human readable string that can be used to describe the role of a source in context of the rule * instance.*/ std::string GetSourceRoleName() const override; /** Returns a human readable string that can be used to describe the role of a destination in context of the rule * instance.*/ std::string GetDestinationRoleName() const override; + bool IsDestinationCandidate(const IPropertyProvider *owner) const override; + /** Connects to passed images. @remark destination must specifiy DICOM SOP Instance UIDs (0x0008, 0x0018) and DICOM SOP Class UID (0x0008, 0x0016) in order to establish a connection on the data layer.*/ RelationUIDType Connect(Image *source, const Image *destination) const; protected: - ImageToImageRelationRule(const RuleIDType &purposeTag); - ImageToImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName); - ImageToImageRelationRule(const RuleIDType &purposeTag, + SourceImageRelationRule(); + SourceImageRelationRule(const RuleIDType &purposeTag); + SourceImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName); + SourceImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName, const std::string &sourceRole, const std::string &destinationRole); - ~ImageToImageRelationRule() override = default; + ~SourceImageRelationRule() override = default; using InstanceIDType = PropertyRelationRuleBase::InstanceIDType; using InstanceIDVectorType = PropertyRelationRuleBase::InstanceIDVectorType; - /** Helper function that returns a vector of all selections of the property DICOM.0008.2112 that refer to destination.*/ + /** Helper function that returns a vector of all selections of the property DICOM.0008.2112 that refer to destination or all (if no destination is passed).*/ std::vector GetReferenceSequenceIndices(const IPropertyProvider * source, - const IPropertyProvider * destination) const; + const IPropertyProvider * destination = nullptr) const; /** Is called if a instance ID cannot be deduced on the ID-layer. Implement this method to check which existing relation(s) as Connected_Data exists between both passed instances. If the passed instances have no explicit relation of type Connected_Data, an empty vector will be returned. @remark Per definition of property relation rules only 0 or 1 instance should be found for one provider pair and rule. But the data layer may be ambiguous and there for muliple relation instances of the rule instance could match. The implementation of this function should report all relation instances. The calling function will take care of this violation. @pre source must be a pointer to a valid IPropertyProvider instance. @pre destination must be a pointer to a valid IPropertyProvider instance.*/ InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source, const IPropertyProvider *destination) const override; /** Is called by HasRelation() if no relation of type Connected_ID (GetInstanceID_IDLayer()) or Connected_Data (GetInstanceID_datalayer()) is evident. Implement this method to deduce if the passed instances have a relation of type Implicit_Data. @pre source must be a pointer to a valid IPropertyProvider instance. @pre destination must be a pointer to a valid IPropertyProvider instance. */ bool HasImplicitDataRelation(const IPropertyProvider *source, const IPropertyProvider *destination) const override; /**Is called by Connect() to ensure that source has correctly set properties to resemble the relation on the data layer. This means that the method should set the properties that describe and encode the relation on the data layer (data-layer-specific relation properties). If the passed instance are already connected, the old settings should be overwritten. Connect() will ensure that source and destination are valid pointers. @param instanceID is the ID for the relation instance that should be connected. Existance of the relation instance is ensured. @pre source must be a valid instance. @pre destination must be a valid instance.*/ void Connect_datalayer(IPropertyOwner *source, const IPropertyProvider *destination, const InstanceIDType &instanceID) const override; /**This method is called by Disconnect() to remove all properties of the relation from the source that are set by Connect_datalayer(). @remark All RII-properties of this relation will removed by Disconnect() after this method call. If the relationUID is not part of the source. Nothing will be changed. Disconnect() ensures that source is a valid pointer if called. @remark Disconnect() ensures that sourece is valid and only invokes if instance exists.*/ void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType &instanceID) const override; virtual bool IsSupportedRuleID(const RuleIDType& ruleID) const override; itk::LightObject::Pointer InternalClone() const override; /**Prepares a new reference to an image on the data layer. Therefore an unused and valid sequence item index for the passed source will be genarated and a relationUID property with the relationUID will be set to block the instance ID. The instance ID will be returned. @remark The method is guarded by a class wide mutex to avoid racing conditions in a scenario where rules are used concurrently.*/ PropertyKeyPath::ItemSelectionIndex CreateNewSourceImageSequenceItem(IPropertyOwner *source) const; private: RuleIDType m_PurposeTag; std::string m_DisplayName; std::string m_SourceRole; std::string m_DestinationRole; }; } // namespace mitk #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/Modules/Core/src/DataManagement/mitkImageToImageRelationRule.cpp b/Modules/Core/src/DataManagement/mitkImageToImageRelationRule.cpp deleted file mode 100644 index 5f63590230..0000000000 --- a/Modules/Core/src/DataManagement/mitkImageToImageRelationRule.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/*=================================================================== - -The Medical Imaging Interaction Toolkit (MITK) - -Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. -All rights reserved. - -This software is distributed WITHOUT ANY WARRANTY; without -even the implied warranty of MERCHANTABILITY or FITNESS FOR -A PARTICULAR PURPOSE. - -See LICENSE.txt or http://www.mitk.org for details. - -===================================================================*/ - -#include -#include - -#include "mitkImageToImageRelationRule.h" -#include "mitkPropertyNameHelper.h" -#include "mitkStringProperty.h" - - -bool mitk::ImageToImageRelationRule::IsAbstract() const -{ - return m_PurposeTag.empty(); -}; - -bool mitk::ImageToImageRelationRule::IsSupportedRuleID(const RuleIDType& ruleID) const -{ - return ruleID == this->GetRuleID() || (IsAbstract() && ruleID.find("ImageToImageRelation ") == 0); -}; - -mitk::ImageToImageRelationRule::RuleIDType mitk::ImageToImageRelationRule::GetRuleID() const -{ - return "ImageToImageRelation " + m_PurposeTag; -}; - -std::string mitk::ImageToImageRelationRule::GetDisplayName() const -{ - return m_DisplayName; -}; - -std::string mitk::ImageToImageRelationRule::GetSourceRoleName() const -{ - return m_SourceRole; -}; - -std::string mitk::ImageToImageRelationRule::GetDestinationRoleName() const -{ - return m_DestinationRole; -}; - -mitk::ImageToImageRelationRule::RelationUIDType mitk::ImageToImageRelationRule::Connect(Image *source, const Image *destination) const -{ - return Superclass::Connect(source, destination); -}; - -mitk::ImageToImageRelationRule::ImageToImageRelationRule(const RuleIDType &purposeTag) - : ImageToImageRelationRule(purposeTag, purposeTag + " relation"){}; - -mitk::ImageToImageRelationRule::ImageToImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName) - : ImageToImageRelationRule( - purposeTag, displayName, "derived image", "source image"){}; - -mitk::ImageToImageRelationRule::ImageToImageRelationRule(const RuleIDType &purposeTag, - const std::string &displayName, - const std::string &sourceRole, - const std::string &destinationRole) - : m_PurposeTag(purposeTag), m_DisplayName(displayName), m_SourceRole(sourceRole), m_DestinationRole(destinationRole){}; - -mitk::ImageToImageRelationRule::InstanceIDVectorType mitk::ImageToImageRelationRule::GetInstanceID_datalayer( - const IPropertyProvider * source, const IPropertyProvider * destination) const -{ - InstanceIDVectorType result; - - auto relevantReferenceIndices = GetReferenceSequenceIndices(source, destination); - - auto itemRegExStr = this->GetRIIPropertyRegEx("SourceImageSequenceItem"); - auto regEx = std::regex(itemRegExStr); - - std::vector keys; - //workaround until T24729 is done. Please remove if T24728 is done - keys = PropertyRelationRuleBase::GetPropertyKeys(source); - //end workaround for T24729 - - for (const auto &key : keys) - { - if (std::regex_match(key, regEx)) - { - auto sequItemProp = source->GetConstProperty(key); - if (sequItemProp.IsNotNull()) - { - auto finding = std::find(std::cbegin(relevantReferenceIndices), std::cend(relevantReferenceIndices), sequItemProp->GetValueAsString()); - if (finding != std::cend(relevantReferenceIndices)) - { - auto instanceID = GetInstanceIDByPropertyName(key); - auto ruleID = GetRuleIDByInstanceID(source, instanceID); - if (this->IsSupportedRuleID(ruleID)) - { - result.push_back(instanceID); - } - } - } - } - } - - return result; -}; - -std::vector mitk::ImageToImageRelationRule::GetReferenceSequenceIndices(const IPropertyProvider * source, - const IPropertyProvider * destination) const -{ - std::vector result; - - auto destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0018)); - - if (destInstanceUIDProp.IsNull()) - { - return result; - } - - PropertyKeyPath referencedInstanceUIDs; - referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155"); - - auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);; - auto regEx = std::regex(sourceRegExStr); - - std::vector keys; - //workaround until T24729 is done. Please remove if T24728 is done - keys = PropertyRelationRuleBase::GetPropertyKeys(source); - //end workaround for T24729 - - for (const auto &key : keys) - { - if (std::regex_match(key, regEx)) - { - auto refUIDProp = source->GetConstProperty(key); - if (*refUIDProp == *destInstanceUIDProp) - { - PropertyKeyPath finding = PropertyNameToPropertyKeyPath(key); - result.push_back(std::to_string(finding.GetNode(3).selection)); - } - } - } - - return result; -}; - -bool mitk::ImageToImageRelationRule::HasImplicitDataRelation(const IPropertyProvider * source, - const IPropertyProvider * destination) const -{ - auto relevantReferences = GetReferenceSequenceIndices(source, destination); - - return !relevantReferences.empty(); -}; - - -/**This mutex is used to guard mitk::PropertyRelationRuleBase::CreateNewRelationInstance by a class wide mutex to avoid -racing conditions in a scenario where rules are used concurrently. It is not in the class interface itself, because it -is an implementation detail. -*/ -std::mutex sequenceItemCreationLock; - -mitk::PropertyKeyPath::ItemSelectionIndex mitk::ImageToImageRelationRule::CreateNewSourceImageSequenceItem( - IPropertyOwner *source) const -{ - std::lock_guard guard(sequenceItemCreationLock); - - ////////////////////////////////////// - // Get all existing sequence items - - std::vector instanceIDs; - PropertyKeyPath::ItemSelectionIndex newID = 1; - - PropertyKeyPath referencedInstanceUIDs; - referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155"); - auto regExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs); - auto regEx = std::regex(regExStr); - std::smatch instance_matches; - - //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed. - const auto keys = GetPropertyKeys(source); - //end workaround for T24729 - - for (const auto &key : keys) - { - if (std::regex_search(key, instance_matches, regEx)) - { - if (instance_matches.size()>1) - { - instanceIDs.push_back(std::stoi(instance_matches[1])); - } - } - } - - ////////////////////////////////////// - // Get new ID - - std::sort(instanceIDs.begin(), instanceIDs.end()); - if (!instanceIDs.empty()) - { - newID = instanceIDs.back()+1; - } - - ////////////////////////////////////// - // reserve new ID - - PropertyKeyPath newSourceImageSequencePath; - newSourceImageSequencePath.AddElement("DICOM").AddElement("0008").AddSelection("2112",newID).AddElement("0008").AddElement("1155"); - - auto newKey = - PropertyKeyPathToPropertyName(newSourceImageSequencePath); - source->SetProperty(newKey, mitk::StringProperty::New("reserved slot fir source image sequence")); - - return newID; -}; - - -void mitk::ImageToImageRelationRule::Connect_datalayer(IPropertyOwner * source, - const IPropertyProvider * destination, - const InstanceIDType & instanceID) const -{ - auto destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008,0x0018)); - auto destClassUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0016)); - - if (destInstanceUIDProp.IsNotNull() && destClassUIDProp.IsNotNull()) - { - PropertyKeyPath::ItemSelectionIndex newSelectionIndex = CreateNewSourceImageSequenceItem(source); - - PropertyKeyPath refInstanceUIDPath; - refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1155"); - source->SetProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath), destInstanceUIDProp->Clone()); - - PropertyKeyPath refClassUIDPath; - refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1150"); - source->SetProperty(PropertyKeyPathToPropertyName(refClassUIDPath), destClassUIDProp->Clone()); - - PropertyKeyPath purposePath; - purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0040").AddSelection("a170",0).AddElement("0008").AddElement("0104"); - source->SetProperty(PropertyKeyPathToPropertyName(purposePath), StringProperty::New(m_PurposeTag)); - - auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem"); - source->SetProperty(PropertyKeyPathToPropertyName(sourceImageRefPath), StringProperty::New(std::to_string(newSelectionIndex)).GetPointer()); - } - else - { - MITK_DEBUG << "Cannot connect ImageToImageRelationRule on data layer. Passed destination does not have properties for DICOM SOP Instance UIDs(0x0008, 0x0018) and DICOM SOP Class UID(0x0008, 0x0016)"; - } -}; - -void mitk::ImageToImageRelationRule::Disconnect_datalayer(IPropertyOwner * source, const InstanceIDType & instanceID) const -{ - auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem"); - auto imageRefProp = source->GetConstProperty(PropertyKeyPathToPropertyName(sourceImageRefPath)); - - if (imageRefProp.IsNotNull()) - { - PropertyKeyPath refDataPath; - refDataPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", std::stoi(imageRefProp->GetValueAsString())); - - auto regExStr = PropertyKeyPathToPropertyRegEx(refDataPath); - auto regEx = std::regex(regExStr); - std::smatch instance_matches; - - //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed. - const auto keys = GetPropertyKeys(source); - //end workaround for T24729 - - for (const auto &key : keys) - { - if (std::regex_search(key, instance_matches, regEx)) - { - source->RemoveProperty(key); - } - } - - source->RemoveProperty(PropertyKeyPathToPropertyName(sourceImageRefPath)); - } -}; - -itk::LightObject::Pointer mitk::ImageToImageRelationRule::InternalClone() const -{ - itk::LightObject::Pointer result = Self::New(this->m_PurposeTag, this->m_DisplayName, this->m_SourceRole, this->m_DestinationRole).GetPointer(); - - return result; -}; diff --git a/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp b/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp new file mode 100644 index 0000000000..890dc1e773 --- /dev/null +++ b/Modules/Core/src/DataManagement/mitkSourceImageRelationRule.cpp @@ -0,0 +1,379 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include + +#include "mitkSourceImageRelationRule.h" +#include "mitkPropertyNameHelper.h" +#include "mitkStringProperty.h" +#include "mitkTemporoSpatialStringProperty.h" +#include "mitkDataNode.h" + + +bool mitk::SourceImageRelationRule::IsAbstract() const +{ + return m_PurposeTag.empty(); +}; + +bool mitk::SourceImageRelationRule::IsSupportedRuleID(const RuleIDType& ruleID) const +{ + return ruleID == this->GetRuleID() || (IsAbstract() && ruleID.find("SourceImageRelation ") == 0); +}; + +mitk::SourceImageRelationRule::RuleIDType mitk::SourceImageRelationRule::GetRuleID() const +{ + return "SourceImageRelation " + m_PurposeTag; +}; + +std::string mitk::SourceImageRelationRule::GetDisplayName() const +{ + return m_DisplayName; +}; + +std::string mitk::SourceImageRelationRule::GetSourceRoleName() const +{ + return m_SourceRole; +}; + +std::string mitk::SourceImageRelationRule::GetDestinationRoleName() const +{ + return m_DestinationRole; +}; + +bool mitk::SourceImageRelationRule::IsDestinationCandidate(const IPropertyProvider *owner) const +{ + auto node = dynamic_cast(owner); + auto image = dynamic_cast(owner); + if (node) + { + image = dynamic_cast(node->GetData()); + } + + return image != nullptr; +} + +mitk::SourceImageRelationRule::RelationUIDType mitk::SourceImageRelationRule::Connect(Image *source, const Image *destination) const +{ + return Superclass::Connect(source, destination); +}; + +mitk::SourceImageRelationRule::SourceImageRelationRule() + : m_PurposeTag(""), m_DisplayName("Abstract image to image relation"), m_SourceRole("derived data"), m_DestinationRole("source image") +{}; + +mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag) + : SourceImageRelationRule(purposeTag, purposeTag + " relation"){}; + +mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag, const std::string &displayName) + : SourceImageRelationRule( + purposeTag, displayName, "derived data", "source image"){}; + +mitk::SourceImageRelationRule::SourceImageRelationRule(const RuleIDType &purposeTag, + const std::string &displayName, + const std::string &sourceRole, + const std::string &destinationRole) + : m_PurposeTag(purposeTag), m_DisplayName(displayName), m_SourceRole(sourceRole), m_DestinationRole(destinationRole){}; + +mitk::SourceImageRelationRule::InstanceIDVectorType mitk::SourceImageRelationRule::GetInstanceID_datalayer( + const IPropertyProvider * source, const IPropertyProvider * destination) const +{ + InstanceIDVectorType result; + + auto relevantReferenceIndices = GetReferenceSequenceIndices(source, destination); + + auto itemRegExStr = this->GetRIIPropertyRegEx("SourceImageSequenceItem"); + auto regEx = std::regex(itemRegExStr); + + std::vector keys; + //workaround until T24729 is done. Please remove if T24728 is done + keys = PropertyRelationRuleBase::GetPropertyKeys(source); + //end workaround for T24729 + + for (const auto &key : keys) + { + if (std::regex_match(key, regEx)) + { + auto sequItemProp = source->GetConstProperty(key); + if (sequItemProp.IsNotNull()) + { + auto finding = std::find(std::cbegin(relevantReferenceIndices), std::cend(relevantReferenceIndices), sequItemProp->GetValueAsString()); + if (finding != std::cend(relevantReferenceIndices)) + { + auto instanceID = GetInstanceIDByPropertyName(key); + auto ruleID = GetRuleIDByInstanceID(source, instanceID); + if (this->IsSupportedRuleID(ruleID)) + { + result.push_back(instanceID); + } + } + } + } + } + + return result; +}; + +std::vector mitk::SourceImageRelationRule::GetReferenceSequenceIndices(const IPropertyProvider * source, + const IPropertyProvider * destination) const +{ + std::vector result; + + BaseProperty::ConstPointer destInstanceUIDProp; + + if (destination) + { + destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0018)); + + if (destInstanceUIDProp.IsNull()) + { + return result; + } + } + + PropertyKeyPath referencedInstanceUIDs; + referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155"); + + auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);; + auto regEx = std::regex(sourceRegExStr); + + std::vector keys; + //workaround until T24729 is done. Please remove if T24728 is done + keys = PropertyRelationRuleBase::GetPropertyKeys(source); + //end workaround for T24729 + + for (const auto &key : keys) + { + if (std::regex_match(key, regEx)) + { + auto refUIDProp = source->GetConstProperty(key); + if (destination==nullptr || *refUIDProp == *destInstanceUIDProp) + { + auto currentKeyPath = PropertyNameToPropertyKeyPath(key); + auto currentKeyPathSelection = currentKeyPath.GetNode(2).selection; + PropertyKeyPath purposePath; + purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", currentKeyPathSelection).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104"); + + auto purposeProp = source->GetConstProperty(PropertyKeyPathToPropertyName(purposePath)); + if (this->IsAbstract() || (purposeProp.IsNotNull() && purposeProp->GetValueAsString() == this->m_PurposeTag)) + { + result.push_back(std::to_string(currentKeyPathSelection)); + } + } + } + } + + return result; +}; + +bool mitk::SourceImageRelationRule::HasImplicitDataRelation(const IPropertyProvider * source, + const IPropertyProvider * destination) const +{ + auto relevantReferences = GetReferenceSequenceIndices(source, destination); + + if (this->IsAbstract()) + { + return !relevantReferences.empty(); + } + else + { + for (auto referenceIndex : relevantReferences) + { + PropertyKeyPath purposePath; + purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", std::stoi(referenceIndex)).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104"); + auto purposeProp = source->GetConstProperty(PropertyKeyPathToPropertyName(purposePath)); + + if (purposeProp.IsNotNull() && purposeProp->GetValueAsString() == this->m_PurposeTag) + { + return true; + } + } + } + + return false; +}; + + +/**This mutex is used to guard mitk::PropertyRelationRuleBase::CreateNewRelationInstance by a class wide mutex to avoid +racing conditions in a scenario where rules are used concurrently. It is not in the class interface itself, because it +is an implementation detail. +*/ +std::mutex sequenceItemCreationLock; + +mitk::PropertyKeyPath::ItemSelectionIndex mitk::SourceImageRelationRule::CreateNewSourceImageSequenceItem( + IPropertyOwner *source) const +{ + std::lock_guard guard(sequenceItemCreationLock); + + ////////////////////////////////////// + // Get all existing sequence items + + std::vector instanceIDs; + PropertyKeyPath::ItemSelectionIndex newID = 0; + + PropertyKeyPath referencedInstanceUIDs; + referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155"); + auto regExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs); + auto regEx = std::regex(regExStr); + std::smatch instance_matches; + + //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed. + const auto keys = GetPropertyKeys(source); + //end workaround for T24729 + + for (const auto &key : keys) + { + if (std::regex_search(key, instance_matches, regEx)) + { + if (instance_matches.size()>1) + { + instanceIDs.push_back(std::stoi(instance_matches[1])); + } + } + } + + ////////////////////////////////////// + // Get new ID + + std::sort(instanceIDs.begin(), instanceIDs.end()); + if (!instanceIDs.empty()) + { + newID = instanceIDs.back()+1; + } + + ////////////////////////////////////// + // reserve new ID + + PropertyKeyPath newSourceImageSequencePath; + newSourceImageSequencePath.AddElement("DICOM").AddElement("0008").AddSelection("2112",newID).AddElement("0008").AddElement("1155"); + + auto newKey = + PropertyKeyPathToPropertyName(newSourceImageSequencePath); + source->SetProperty(newKey, mitk::TemporoSpatialStringProperty::New("reserved slot for source image sequence")); + + return newID; +}; + + +void mitk::SourceImageRelationRule::Connect_datalayer(IPropertyOwner * source, + const IPropertyProvider * destination, + const InstanceIDType & instanceID) const +{ + auto destInstanceUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008,0x0018)); + auto destClassUIDProp = destination->GetConstProperty(GeneratePropertyNameForDICOMTag(0x0008, 0x0016)); + + if (destInstanceUIDProp.IsNotNull() && destClassUIDProp.IsNotNull()) + { + auto existingRefs = this->GetReferenceSequenceIndices(source, destination); + std::string newSelectionIndexStr; + if (!existingRefs.empty()) + { + newSelectionIndexStr = existingRefs[0]; + } + else + { + PropertyKeyPath::ItemSelectionIndex newSelectionIndex = CreateNewSourceImageSequenceItem(source); + + PropertyKeyPath refInstanceUIDPath; + refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1155"); + source->SetProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath), destInstanceUIDProp->Clone()); + + PropertyKeyPath refClassUIDPath; + refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0008").AddElement("1150"); + source->SetProperty(PropertyKeyPathToPropertyName(refClassUIDPath), destClassUIDProp->Clone()); + + PropertyKeyPath purposePath; + purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", newSelectionIndex).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104"); + source->SetProperty(PropertyKeyPathToPropertyName(purposePath), StringProperty::New(m_PurposeTag)); + + newSelectionIndexStr = std::to_string(newSelectionIndex); + } + + auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem"); + source->SetProperty(PropertyKeyPathToPropertyName(sourceImageRefPath), StringProperty::New(newSelectionIndexStr).GetPointer()); + } + else + { + MITK_DEBUG << "Cannot connect SourceImageRelationRule on data layer. Passed destination does not have properties for DICOM SOP Instance UIDs(0x0008, 0x0018) and DICOM SOP Class UID(0x0008, 0x0016)"; + } +}; + +void mitk::SourceImageRelationRule::Disconnect_datalayer(IPropertyOwner * source, const InstanceIDType & instanceID) const +{ + auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem"); + auto imageRefProp = source->GetConstProperty(PropertyKeyPathToPropertyName(sourceImageRefPath)); + + if (imageRefProp.IsNotNull()) + { + auto deletedImageRefSequenceIndex = imageRefProp->GetValueAsString(); + + auto refs = GetReferenceSequenceIndices(source); + std::sort(refs.begin(), refs.end()); + + for (auto refIndexStr : refs) + { + auto refIndex = std::stoi(refIndexStr); + + if (refIndex >= std::stoi(deletedImageRefSequenceIndex)) + { + PropertyKeyPath refDICOMDataPath; + refDICOMDataPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", refIndex); + auto prefix = PropertyKeyPathToPropertyName(refDICOMDataPath); + + PropertyKeyPath refRelDataPath = GetRootKeyPath().AddAnyElement().AddElement("SourceImageSequenceItem");; + auto regEx = std::regex(PropertyKeyPathToPropertyRegEx(refRelDataPath)); + + //workaround until T24729 is done. You can use directly source->GetPropertyKeys again, when fixed. + const auto keys = GetPropertyKeys(source); + //end workaround for T24729 + + for (const auto &key : keys) + { + if (key.find(prefix) == 0) + { //its a relevant DICOM property delete or update + if (refIndexStr != deletedImageRefSequenceIndex) + { + //reindex to close the gap in the dicom sequence. + auto newPath = PropertyNameToPropertyKeyPath(key); + newPath.GetNode(2).selection = refIndex - 1; + source->SetProperty(PropertyKeyPathToPropertyName(newPath), source->GetNonConstProperty(key)); + } + //remove old/outdated data layer information + source->RemoveProperty(key); + + auto sourceImageRefPath = GetRootKeyPath().AddElement(instanceID).AddElement("SourceImageSequenceItem"); + } + if (std::regex_match(key, regEx)) + { + auto imageSequenceItemProp = source->GetConstProperty(key); + if (imageSequenceItemProp->GetValueAsString() == std::to_string(refIndex)) + { + //its a relevant data property of the relation rule. + source->SetProperty(key, StringProperty::New(std::to_string(refIndex - 1))); + } + } + } + } + } + } +}; + +itk::LightObject::Pointer mitk::SourceImageRelationRule::InternalClone() const +{ + itk::LightObject::Pointer result = Self::New(this->m_PurposeTag, this->m_DisplayName, this->m_SourceRole, this->m_DestinationRole).GetPointer(); + + return result; +}; diff --git a/Modules/Core/test/files.cmake b/Modules/Core/test/files.cmake index 0b6664b2a2..3c8a6f19dc 100644 --- a/Modules/Core/test/files.cmake +++ b/Modules/Core/test/files.cmake @@ -1,200 +1,201 @@ # tests with no extra command line parameter set(MODULE_TESTS # IMPORTANT: If you plan to deactivate / comment out a test please write a bug number to the commented out line of code. # # Example: #mitkMyTest #this test is commented out because of bug 12345 # # It is important that the bug is open and that the test will be activated again before the bug is closed. This assures that # no test is forgotten after it was commented out. If there is no bug for your current problem, please add a new one and # mark it as critical. ################## DISABLED TESTS ################################################# #mitkAbstractTransformGeometryTest.cpp #seems as tested class mitkExternAbstractTransformGeometry doesnt exist any more #mitkStateMachineContainerTest.cpp #rewrite test, indirect since no longer exported Bug 14529 #mitkRegistrationBaseTest.cpp #tested class mitkRegistrationBase doesn't exist any more #mitkSegmentationInterpolationTest.cpp #file doesn't exist! #mitkPipelineSmartPointerCorrectnessTest.cpp #file doesn't exist! #mitkITKThreadingTest.cpp #test outdated because itk::Semaphore was removed from ITK #mitkAbstractTransformPlaneGeometryTest.cpp #mitkVtkAbstractTransformPlaneGeometry doesn't exist any more #mitkTestUtilSharedLibrary.cpp #Linker problem with this test... #mitkTextOverlay2DSymbolsRenderingTest.cpp #Implementation of the tested feature is not finished yet. Ask Christoph or see bug 15104 for details. ################# RUNNING TESTS ################################################### mitkAccessByItkTest.cpp mitkCoreObjectFactoryTest.cpp mitkDataNodeTest.cpp mitkMaterialTest.cpp mitkActionTest.cpp mitkDispatcherTest.cpp mitkEnumerationPropertyTest.cpp mitkFileReaderRegistryTest.cpp #mitkFileWriterRegistryTest.cpp mitkFloatToStringTest.cpp mitkGenericPropertyTest.cpp mitkGeometry3DTest.cpp mitkGeometry3DEqualTest.cpp mitkGeometryDataIOTest.cpp mitkGeometryDataToSurfaceFilterTest.cpp mitkImageCastTest.cpp mitkImageEqualTest.cpp mitkImageDataItemTest.cpp mitkImageGeneratorTest.cpp mitkIOUtilTest.cpp mitkBaseDataTest.cpp mitkImportItkImageTest.cpp mitkGrabItkImageMemoryTest.cpp mitkInstantiateAccessFunctionTest.cpp mitkLevelWindowTest.cpp mitkMessageTest.cpp mitkPixelTypeTest.cpp mitkPlaneGeometryTest.cpp mitkPointSetTest.cpp mitkPointSetEqualTest.cpp mitkPointSetFileIOTest.cpp mitkPointSetOnEmptyTest.cpp mitkPointSetLocaleTest.cpp mitkPointSetWriterTest.cpp mitkPointSetReaderTest.cpp mitkPointSetPointOperationsTest.cpp mitkProgressBarTest.cpp mitkPropertyTest.cpp mitkPropertyListTest.cpp mitkPropertyPersistenceTest.cpp mitkPropertyPersistenceInfoTest.cpp mitkPropertyRelationRuleBaseTest.cpp mitkPropertyRelationsTest.cpp mitkSlicedGeometry3DTest.cpp mitkSliceNavigationControllerTest.cpp mitkSurfaceTest.cpp mitkSurfaceEqualTest.cpp mitkSurfaceToSurfaceFilterTest.cpp mitkTimeGeometryTest.cpp mitkProportionalTimeGeometryTest.cpp mitkUndoControllerTest.cpp mitkVtkWidgetRenderingTest.cpp mitkVerboseLimitedLinearUndoTest.cpp mitkWeakPointerTest.cpp mitkTransferFunctionTest.cpp mitkStepperTest.cpp mitkRenderingManagerTest.cpp mitkCompositePixelValueToStringTest.cpp vtkMitkThickSlicesFilterTest.cpp mitkNodePredicateSourceTest.cpp mitkNodePredicateDataPropertyTest.cpp mitkNodePredicateFunctionTest.cpp mitkVectorTest.cpp mitkClippedSurfaceBoundsCalculatorTest.cpp mitkExceptionTest.cpp mitkExtractSliceFilterTest.cpp mitkLogTest.cpp mitkImageDimensionConverterTest.cpp mitkLoggingAdapterTest.cpp mitkUIDGeneratorTest.cpp mitkPlanePositionManagerTest.cpp mitkAffineTransformBaseTest.cpp mitkPropertyAliasesTest.cpp mitkPropertyDescriptionsTest.cpp mitkPropertyExtensionsTest.cpp mitkPropertyFiltersTest.cpp mitkPropertyKeyPathTest.cpp mitkTinyXMLTest.cpp mitkRawImageFileReaderTest.cpp mitkInteractionEventTest.cpp mitkLookupTableTest.cpp mitkSTLFileReaderTest.cpp mitkPointTypeConversionTest.cpp mitkVectorTypeConversionTest.cpp mitkMatrixTypeConversionTest.cpp mitkArrayTypeConversionTest.cpp mitkSurfaceToImageFilterTest.cpp mitkBaseGeometryTest.cpp mitkImageToSurfaceFilterTest.cpp mitkEqualTest.cpp mitkLineTest.cpp mitkArbitraryTimeGeometryTest mitkItkImageIOTest.cpp mitkRotatedSlice4DTest.cpp mitkLevelWindowManagerCppUnitTest.cpp mitkVectorPropertyTest.cpp mitkTemporoSpatialStringPropertyTest.cpp mitkPropertyNameHelperTest.cpp mitkNodePredicateGeometryTest.cpp mitkPreferenceListReaderOptionsFunctorTest.cpp mitkGenericIDRelationRuleTest.cpp + mitkSourceImageRelationRuleTest.cpp ) if(MITK_ENABLE_RENDERING_TESTING) set(MODULE_TESTS ${MODULE_TESTS} mitkPlaneGeometryDataMapper2DTest.cpp mitkPointSetDataInteractorTest.cpp #since mitkInteractionTestHelper is currently creating a vtkRenderWindow mitkSurfaceVtkMapper2DTest.cpp #new rendering test in CppUnit style mitkSurfaceVtkMapper2D3DTest.cpp # comparisons/consistency 2D/3D ) endif() # test with image filename as an extra command line parameter set(MODULE_IMAGE_TESTS mitkImageTimeSelectorTest.cpp #only runs on images mitkImageAccessorTest.cpp #only runs on images ) set(MODULE_SURFACE_TESTS mitkSurfaceVtkWriterTest.cpp #only runs on surfaces ) # list of images for which the tests are run set(MODULE_TESTIMAGE US4DCyl.nrrd Pic3D.nrrd Pic2DplusT.nrrd BallBinary30x30x30.nrrd Png2D-bw.png ) set(MODULE_TESTSURFACE binary.stl ball.stl ) set(MODULE_CUSTOM_TESTS mitkDataStorageTest.cpp mitkDataNodeTest.cpp mitkEventConfigTest.cpp mitkPointSetLocaleTest.cpp mitkImageTest.cpp mitkImageVtkMapper2DTest.cpp mitkImageVtkMapper2DLevelWindowTest.cpp mitkImageVtkMapper2DOpacityTest.cpp mitkImageVtkMapper2DResliceInterpolationPropertyTest.cpp mitkImageVtkMapper2DColorTest.cpp mitkImageVtkMapper2DSwivelTest.cpp mitkImageVtkMapper2DTransferFunctionTest.cpp mitkImageVtkMapper2DOpacityTransferFunctionTest.cpp mitkImageVtkMapper2DLookupTableTest.cpp mitkSurfaceVtkMapper3DTest mitkVolumeCalculatorTest.cpp mitkLevelWindowManagerTest.cpp mitkPointSetVtkMapper2DTest.cpp mitkPointSetVtkMapper2DImageTest.cpp mitkPointSetVtkMapper2DGlyphTypeTest.cpp mitkPointSetVtkMapper2DTransformedPointsTest.cpp mitkVTKRenderWindowSizeTest.cpp mitkMultiComponentImageDataComparisonFilterTest.cpp mitkImageToItkTest.cpp mitkImageSliceSelectorTest.cpp ) # Currently not working on windows because of a rendering timing issue # see bug 18083 for details if(NOT WIN32) set(MODULE_CUSTOM_TESTS ${MODULE_CUSTOM_TESTS} mitkSurfaceDepthSortingTest.cpp) endif() set(RESOURCE_FILES Interactions/AddAndRemovePoints.xml Interactions/globalConfig.xml Interactions/StatemachineTest.xml Interactions/StatemachineConfigTest.xml ) diff --git a/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp b/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp index 7a246e42dc..6ef8df3be1 100644 --- a/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp +++ b/Modules/Core/test/mitkPropertyRelationRuleBaseTest.cpp @@ -1,919 +1,919 @@ /*=================================================================== 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 "mitkPropertyRelationRuleBase.h" #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkStringProperty.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include /** This class is used to test PropertyRelationRuleBase and get access to internals where needed to test them as well. */ namespace mitk { class TestRule : public mitk::PropertyRelationRuleBase { public: mitkClassMacro(TestRule, mitk::PropertyRelationRuleBase); itkFactorylessNewMacro(Self); itkCloneMacro(Self); using RuleIDType = PropertyRelationRuleBase::RuleIDType; using RelationUIDType = PropertyRelationRuleBase::RelationUIDType; using RelationUIDVectorType = PropertyRelationRuleBase::RelationUIDVectorType; RuleIDType GetRuleID() const override { if (m_AbstractMode) { return "TestRule"; } else { return "TestRule_type1"; } }; std::string GetDisplayName() const override { return "TestDisplayName"; } std::string GetSourceRoleName() const override { return "source role"; } std::string GetDestinationRoleName() const override { return "destination role"; } bool m_AbstractMode; bool IsAbstract() const override { return m_AbstractMode; } using Superclass::GetRootKeyPath; using Superclass::Connect; protected: TestRule() : m_AbstractMode(false) { }; ~TestRule() override = default; using InstanceIDType = PropertyRelationRuleBase::InstanceIDType; using InstanceIDVectorType = PropertyRelationRuleBase::InstanceIDVectorType; bool IsSupportedRuleID(const RuleIDType& ruleID) const override { if (m_AbstractMode) { return ruleID.find(this->GetRuleID()) == 0; } else { return Superclass::IsSupportedRuleID(ruleID); } }; InstanceIDVectorType GetInstanceID_datalayer(const IPropertyProvider *source, const IPropertyProvider *destination) const override { InstanceIDVectorType result; auto destProp = destination->GetConstProperty("name"); if (destProp.IsNotNull()) { auto destRegExStr = PropertyKeyPathToPropertyRegEx(Superclass::GetRootKeyPath().AddAnyElement().AddElement("dataHandle")); auto regEx = std::regex(destRegExStr); std::smatch instance_matches; auto keys = source->GetPropertyKeys(); for (const auto &key : keys) { if (std::regex_search(key, instance_matches, regEx)) { auto sourceProp = source->GetConstProperty(key); if (sourceProp->GetValueAsString() == destProp->GetValueAsString()) { if (instance_matches.size()>1) { result.push_back(instance_matches[1]); } } } } } return result; }; bool HasImplicitDataRelation(const IPropertyProvider *source, const IPropertyProvider *destination) const override { auto destProp = destination->GetConstProperty("name"); auto sourceProp = source->GetConstProperty("referencedName"); return destProp.IsNotNull() && sourceProp.IsNotNull() && destProp->GetValueAsString() == sourceProp->GetValueAsString(); }; void Connect_datalayer(IPropertyOwner *source, const IPropertyProvider *destination, const InstanceIDType &instanceID) const override { auto destProp = destination->GetConstProperty("name"); source->SetProperty("referencedName", StringProperty::New(destProp->GetValueAsString())); source->SetProperty( PropertyKeyPathToPropertyName(Superclass::GetRootKeyPath().AddElement(instanceID).AddElement("dataHandle")), StringProperty::New(destProp->GetValueAsString())); }; void Disconnect_datalayer(IPropertyOwner *source, const InstanceIDType & /*instanceID*/) const override { source->RemoveProperty("referencedName"); }; }; } // namespace mitk class mitkPropertyRelationRuleBaseTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPropertyRelationRuleBaseTestSuite); MITK_TEST(GetRootKeyPath); MITK_TEST(IsSourceCandidate); MITK_TEST(IsDestinationCandidate); MITK_TEST(IsSource); MITK_TEST(HasRelation); MITK_TEST(GetExistingRelations); MITK_TEST(GetRelationUIDs); MITK_TEST(GetSourceCandidateIndicator); MITK_TEST(GetDestinationCandidateIndicator); MITK_TEST(GetConnectedSourcesDetector); MITK_TEST(GetSourcesDetector); MITK_TEST(GetDestinationsDetector); MITK_TEST(GetDestinationDetector); MITK_TEST(Connect); MITK_TEST(Disconnect); MITK_TEST(Connect_abstract); MITK_TEST(Disconnect_abstract); CPPUNIT_TEST_SUITE_END(); private: mitk::TestRule::Pointer rule; mitk::TestRule::Pointer abstractRule; mitk::DataNode::Pointer unRelated; mitk::PointSet::Pointer unRelated_1_data; mitk::DataNode::Pointer source_implicit_1; mitk::DataNode::Pointer source_data_1; mitk::DataNode::Pointer source_idOnly_1; mitk::DataNode::Pointer source_1; mitk::DataNode::Pointer source_multi; mitk::DataNode::Pointer source_otherRule; mitk::DataNode::Pointer source_otherTypeRule; //relevant for abstract rule checks. Abstract rule should see it concrete rule not. mitk::DataNode::Pointer dest_1; mitk::PointSet::Pointer dest_1_data; mitk::DataNode::Pointer dest_2; mitk::PointSet::Pointer dest_2_data; bool hasRelationProperties(mitk::IPropertyProvider *provider, std::string instance = "") const { auto keyPath = mitk::PropertyRelationRuleBase::GetRootKeyPath(); if (!instance.empty()) { keyPath.AddElement(instance); } auto prefix = mitk::PropertyKeyPathToPropertyName(keyPath); auto keys = provider->GetPropertyKeys(); for (const auto &key : keys) { if (key.find(prefix) == 0) { return true; } } return false; } public: void setUp() override { rule = mitk::TestRule::New(); abstractRule = mitk::TestRule::New(); abstractRule->m_AbstractMode = true; unRelated = mitk::DataNode::New(); unRelated->SetName("unRelated"); unRelated_1_data = mitk::PointSet::New(); unRelated->SetData(unRelated_1_data); dest_1 = mitk::DataNode::New(); dest_1->SetName("dest_1"); dest_1_data = mitk::PointSet::New(); dest_1->SetData(dest_1_data); dest_2 = mitk::DataNode::New(); dest_2->SetName("dest_2"); dest_2_data = mitk::PointSet::New(); dest_2->SetData(dest_2_data); source_implicit_1 = mitk::DataNode::New(); source_implicit_1->AddProperty("referencedName", mitk::StringProperty::New(dest_1->GetName())); source_idOnly_1 = mitk::DataNode::New(); std::string name = "MITK.Relations.1.relationUID"; source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid1")); name = "MITK.Relations.1.destinationUID"; source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.1.ruleID"; source_idOnly_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); source_data_1 = source_implicit_1->Clone(); name = "MITK.Relations.1.relationUID"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid2")); name = "MITK.Relations.1.dataHandle"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetName())); name = "MITK.Relations.1.ruleID"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); name = "MITK.Relations.2.relationUID"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid10"), nullptr, true); name = "MITK.Relations.2.destinationUID"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.2.ruleID"; source_data_1->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype")); source_1 = source_data_1->Clone(); name = "MITK.Relations.1.relationUID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid3"), nullptr, true); name = "MITK.Relations.1.destinationUID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.1.ruleID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); name = "MITK.Relations.2.relationUID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New("uid8"), nullptr, true); name = "MITK.Relations.2.destinationUID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New(dest_2_data->GetUID())); name = "MITK.Relations.2.ruleID"; source_1->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype")); source_multi = source_1->Clone(); name = "MITK.Relations.1.relationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid4"), nullptr, true); name = "MITK.Relations.1.destinationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.1.ruleID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); name = "MITK.Relations.4.relationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid5")); name = "MITK.Relations.4.destinationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(dest_2_data->GetUID())); name = "MITK.Relations.4.ruleID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); name = "MITK.Relations.2.relationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("uid6")); name = "MITK.Relations.2.destinationUID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New("unknown")); name = "MITK.Relations.2.ruleID"; source_multi->AddProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); source_otherRule = mitk::DataNode::New(); name = "MITK.Relations.1.relationUID"; source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New("uid7")); name = "MITK.Relations.1.destinationUID"; source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.1.ruleID"; source_otherRule->AddProperty(name.c_str(), mitk::StringProperty::New("otherRuleID")); source_otherTypeRule = mitk::DataNode::New(); name = "MITK.Relations.1.relationUID"; source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New("uid9")); name = "MITK.Relations.1.destinationUID"; source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New(dest_1_data->GetUID())); name = "MITK.Relations.1.ruleID"; source_otherTypeRule->AddProperty(name.c_str(), mitk::StringProperty::New("TestRule_othertype")); } void tearDown() override {} void GetRootKeyPath() { mitk::PropertyKeyPath ref; ref.AddElement("MITK").AddElement("Relations"); CPPUNIT_ASSERT(mitk::PropertyRelationRuleBase::GetRootKeyPath() == ref); } void IsSourceCandidate() { CPPUNIT_ASSERT(rule->IsSourceCandidate(mitk::DataNode::New())); CPPUNIT_ASSERT(!rule->IsSourceCandidate(nullptr)); } void IsDestinationCandidate() { CPPUNIT_ASSERT(rule->IsDestinationCandidate(mitk::DataNode::New())); CPPUNIT_ASSERT(!rule->IsDestinationCandidate(nullptr)); } void IsSource() { CPPUNIT_ASSERT_THROW_MESSAGE( "Violated precondition (nullptr) does not throw.", rule->IsSource(nullptr), itk::ExceptionObject); CPPUNIT_ASSERT(!rule->IsSource(unRelated)); CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1)); CPPUNIT_ASSERT(rule->IsSource(source_data_1)); CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1)); CPPUNIT_ASSERT(rule->IsSource(source_1)); CPPUNIT_ASSERT(rule->IsSource(source_multi)); CPPUNIT_ASSERT(!rule->IsSource(source_otherRule)); CPPUNIT_ASSERT(!rule->IsSource(source_otherTypeRule)); CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated)); CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1)); CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1)); CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1)); CPPUNIT_ASSERT(abstractRule->IsSource(source_1)); CPPUNIT_ASSERT(abstractRule->IsSource(source_multi)); CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule)); CPPUNIT_ASSERT(abstractRule->IsSource(source_otherTypeRule)); } void HasRelation() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->HasRelation(nullptr, dest_1), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->HasRelation(source_1, nullptr), itk::ExceptionObject); CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(rule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(rule->HasRelation(source_otherTypeRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(abstractRule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherTypeRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); } void GetExistingRelations() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->GetExistingRelations(nullptr), itk::ExceptionObject); CPPUNIT_ASSERT(rule->GetExistingRelations(unRelated).empty()); CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherRule).empty()); CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherTypeRule).empty()); CPPUNIT_ASSERT(rule->GetExistingRelations(source_implicit_1).empty()); auto uids = rule->GetExistingRelations(source_idOnly_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid1"); uids = rule->GetExistingRelations(source_data_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid2"); uids = rule->GetExistingRelations(source_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid3"); uids = rule->GetExistingRelations(source_multi); CPPUNIT_ASSERT(uids.size() == 3); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid4") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid5") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid6") != uids.end()); CPPUNIT_ASSERT(abstractRule->GetExistingRelations(unRelated).empty()); CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_otherRule).empty()); CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_implicit_1).empty()); uids = abstractRule->GetExistingRelations(source_idOnly_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid1"); uids = abstractRule->GetExistingRelations(source_data_1); CPPUNIT_ASSERT(uids.size() == 2); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end()); uids = abstractRule->GetExistingRelations(source_1); CPPUNIT_ASSERT(uids.size() == 2); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end()); uids = abstractRule->GetExistingRelations(source_multi); CPPUNIT_ASSERT(uids.size() == 3); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid4") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid5") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid6") != uids.end()); uids = abstractRule->GetExistingRelations(source_otherTypeRule); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid9"); } void GetRelationUIDs() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->GetRelationUIDs(nullptr, dest_1), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->GetRelationUIDs(source_1, nullptr), itk::ExceptionObject); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, unRelated).empty()); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, dest_2).empty()); CPPUNIT_ASSERT(rule->GetRelationUIDs(unRelated, dest_1).empty()); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherRule, dest_1).empty()); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherTypeRule, dest_1).empty()); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1"); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_data_1, dest_1).front() == "uid2"); auto uids = rule->GetRelationUIDs(source_1, dest_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(uids.front() == "uid3"); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_multi, dest_1).front() == "uid4"); CPPUNIT_ASSERT(rule->GetRelationUIDs(source_multi, dest_2).front() == "uid5"); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, unRelated).empty()); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(unRelated, dest_1).empty()); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherRule, dest_1).empty()); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherTypeRule, dest_1).front() == "uid9"); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1"); uids = abstractRule->GetRelationUIDs(source_data_1, dest_1); CPPUNIT_ASSERT(uids.size() == 2); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end()); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end()); uids = abstractRule->GetRelationUIDs(source_1, dest_1); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end()); uids = abstractRule->GetRelationUIDs(source_1, dest_2); CPPUNIT_ASSERT(uids.size() == 1); CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end()); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, dest_1).front() == "uid3"); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_multi, dest_1).front() == "uid4"); CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_multi, dest_2).front() == "uid5"); } void GetSourceCandidateIndicator() { auto predicate = rule->GetSourceCandidateIndicator(); CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New())); CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); } void GetDestinationCandidateIndicator() { auto predicate = rule->GetDestinationCandidateIndicator(); CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New())); CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); } void GetConnectedSourcesDetector() { auto predicate = rule->GetConnectedSourcesDetector(); CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule)); auto predicate2 = abstractRule->GetConnectedSourcesDetector(); CPPUNIT_ASSERT(!predicate2->CheckNode(nullptr)); CPPUNIT_ASSERT(!predicate2->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate2->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate2->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate2->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate2->CheckNode(source_1)); CPPUNIT_ASSERT(predicate2->CheckNode(source_multi)); CPPUNIT_ASSERT(!predicate2->CheckNode(source_otherRule)); CPPUNIT_ASSERT(predicate2->CheckNode(source_otherTypeRule)); } void GetSourcesDetector() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->GetSourcesDetector(nullptr), itk::ExceptionObject); auto predicate = rule->GetSourcesDetector(dest_1); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); predicate = rule->GetSourcesDetector(dest_2, mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(!predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); predicate = abstractRule->GetSourcesDetector(dest_1); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule)); CPPUNIT_ASSERT(predicate->CheckNode(source_otherTypeRule)); CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_data_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_1)); CPPUNIT_ASSERT(predicate->CheckNode(source_multi)); } void GetDestinationsDetector() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->GetDestinationsDetector(nullptr), itk::ExceptionObject); auto predicate = rule->GetDestinationsDetector(source_otherRule); CPPUNIT_ASSERT(!predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_otherTypeRule); CPPUNIT_ASSERT(!predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_implicit_1); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(!predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_data_1); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(!predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_idOnly_1); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = rule->GetDestinationsDetector(source_1); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(dest_2)); predicate = rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(dest_2)); predicate = rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(dest_2)); predicate = rule->GetDestinationsDetector(source_multi); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(predicate->CheckNode(dest_2)); predicate = rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(predicate->CheckNode(dest_2)); predicate = rule->GetDestinationsDetector(source_multi, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(predicate->CheckNode(dest_2)); predicate = abstractRule->GetDestinationsDetector(source_otherTypeRule); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); predicate = abstractRule->GetDestinationsDetector(source_otherTypeRule); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); } void GetDestinationDetector() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->GetDestinationDetector(nullptr, "uid1"), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (relation uid is invalid) does not throw.", rule->GetDestinationDetector(source_1, "invalid uid"), itk::ExceptionObject); auto predicate = rule->GetDestinationDetector(source_1, "uid3"); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(!predicate->CheckNode(dest_2)); predicate = rule->GetDestinationDetector(source_multi, "uid5"); CPPUNIT_ASSERT(!predicate->CheckNode(unRelated)); CPPUNIT_ASSERT(!predicate->CheckNode(dest_1)); CPPUNIT_ASSERT(predicate->CheckNode(dest_2)); } void Connect() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->Connect(nullptr, dest_1), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->Connect(source_1, nullptr), itk::ExceptionObject); // check upgrade of an implicit connection CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); rule->Connect(source_implicit_1, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); // check upgrade of an data connection CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_Data); rule->Connect(source_data_1, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); std::string name = "MITK.Relations.1.destinationUID"; auto prop = source_data_1->GetProperty(name.c_str()); CPPUNIT_ASSERT_MESSAGE( "Destination uid was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was not stored.", prop->GetValueAsString() == dest_1_data->GetUID()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1_data->GetUID()); // check actualization of an id only connection rule->Connect(source_idOnly_1, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.", rule->GetExistingRelations(source_1).size() == 1); name = "MITK.Relations.1.dataHandle"; prop = source_idOnly_1->GetProperty(name.c_str()); CPPUNIT_ASSERT_MESSAGE( "Data layer information was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was not stored.", + CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information not stored.", prop->GetValueAsString() == dest_1->GetName()); prop = source_idOnly_1->GetProperty("referencedName"); CPPUNIT_ASSERT_MESSAGE( "Data layer information was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was not stored.", + CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.", prop->GetValueAsString() == dest_1->GetName()); // check actualization of an existing connection rule->Connect(source_1, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.", rule->GetExistingRelations(source_1).size() == 1); // check new connection auto newConnectUID = rule->Connect(source_multi, unRelated); CPPUNIT_ASSERT(rule->HasRelation(source_multi, unRelated) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); name = "MITK.Relations.5.dataHandle"; prop = source_multi->GetProperty(name.c_str()); CPPUNIT_ASSERT_MESSAGE( "Data layer information was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was not stored.", + CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.", prop->GetValueAsString() == unRelated->GetName()); prop = source_multi->GetProperty("referencedName"); CPPUNIT_ASSERT_MESSAGE( "Data layer information was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was not stored.", + CPPUNIT_ASSERT_MESSAGE("Incorrect data layer information was stored.", prop->GetValueAsString() == unRelated->GetName()); name = "MITK.Relations.5.destinationUID"; prop = source_multi->GetProperty(name.c_str()); CPPUNIT_ASSERT_MESSAGE( "Destination uid was not stored with the correct key. Already existing session should be used.", prop); - CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was not stored.", prop->GetValueAsString() == unRelated_1_data->GetUID()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == unRelated_1_data->GetUID()); auto storedRelationUIDs = rule->GetRelationUIDs(source_multi, unRelated); CPPUNIT_ASSERT_MESSAGE( "Relation uid was not stored for given source and destination.", storedRelationUIDs.size() == 1); - CPPUNIT_ASSERT_MESSAGE("Incorrect Relation uid was not stored.", storedRelationUIDs[0] == newConnectUID); + CPPUNIT_ASSERT_MESSAGE("Incorrect Relation uid was stored.", storedRelationUIDs[0] == newConnectUID); } void Disconnect() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", rule->Disconnect(nullptr, dest_1), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->Disconnect(source_1, nullptr), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", rule->Disconnect(nullptr, "uid"), itk::ExceptionObject); CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); rule->Disconnect(source_1, unRelated); CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT_MESSAGE("Data property was not removed.", !source_1->GetProperty("referencedName")); rule->Disconnect(source_1, dest_2); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(this->hasRelationProperties(source_1)); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); rule->Disconnect(source_1, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1")); CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.",this->hasRelationProperties(source_1, "2")); CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); rule->Disconnect(source_multi, dest_1); CPPUNIT_ASSERT(rule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); rule->Disconnect(source_multi, "uid6"); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); rule->Disconnect(source_multi, "unkownRelationUID"); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); rule->Disconnect(source_otherTypeRule, dest_1); CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", this->hasRelationProperties(source_otherTypeRule, "1")); } void Connect_abstract() { CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.", abstractRule->Connect(nullptr, dest_1), itk::ExceptionObject); CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.", abstractRule->Connect(source_1, nullptr), itk::ExceptionObject); } void Disconnect_abstract() { CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); abstractRule->Disconnect(source_1, dest_2); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "2")); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); abstractRule->Disconnect(source_1, dest_1); CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1")); CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); abstractRule->Disconnect(source_multi, dest_1); CPPUNIT_ASSERT(abstractRule->HasRelation(source_multi, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); abstractRule->Disconnect(source_multi, "uid6"); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); abstractRule->Disconnect(source_multi, "unkownRelationUID"); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "1")); CPPUNIT_ASSERT(!this->hasRelationProperties(source_multi, "2")); CPPUNIT_ASSERT(this->hasRelationProperties(source_multi, "4")); abstractRule->Disconnect(source_otherTypeRule, dest_1); CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", !this->hasRelationProperties(source_otherTypeRule, "1")); } }; MITK_TEST_SUITE_REGISTRATION(mitkPropertyRelationRuleBase) diff --git a/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp b/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp new file mode 100644 index 0000000000..bb97c0baf0 --- /dev/null +++ b/Modules/Core/test/mitkSourceImageRelationRuleTest.cpp @@ -0,0 +1,884 @@ +/*=================================================================== + +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 "mitkSourceImageRelationRule.h" + +#include "mitkDataNode.h" +#include "mitkPointSet.h" +#include "mitkStringProperty.h" + +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" +#include "mitkPropertyNameHelper.h" +#include "mitkTemporoSpatialStringProperty.h" +#include "mitkPropertyNameHelper.h" + +#include + +class mitkSourceImageRelationRuleTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkSourceImageRelationRuleTestSuite); + + MITK_TEST(IsSourceCandidate); + MITK_TEST(IsDestinationCandidate); + MITK_TEST(IsSource); + MITK_TEST(HasRelation); + MITK_TEST(GetExistingRelations); + MITK_TEST(GetRelationUIDs); + MITK_TEST(GetSourceCandidateIndicator); + MITK_TEST(GetDestinationCandidateIndicator); + MITK_TEST(GetConnectedSourcesDetector); + MITK_TEST(GetSourcesDetector); + MITK_TEST(GetDestinationsDetector); + MITK_TEST(GetDestinationDetector); + MITK_TEST(Connect); + MITK_TEST(Disconnect); + MITK_TEST(Connect_abstract); + MITK_TEST(Disconnect_abstract); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::SourceImageRelationRule::Pointer rule; + mitk::SourceImageRelationRule::Pointer abstractRule; + + mitk::Image::Pointer unRelated; + mitk::DataNode::Pointer unRelated_Node; + + mitk::Image::Pointer source_implicit_1; + mitk::DataNode::Pointer source_implicit_1_Node; + mitk::Image::Pointer source_data_1; + mitk::DataNode::Pointer source_data_1_Node; + mitk::Image::Pointer source_idOnly_1; + mitk::DataNode::Pointer source_idOnly_1_Node; + mitk::Image::Pointer source_1; + mitk::DataNode::Pointer source_1_Node; + + mitk::Image::Pointer source_otherRule; + mitk::DataNode::Pointer source_otherRule_Node; + + mitk::Image::Pointer source_otherPurpose; + mitk::DataNode::Pointer source_otherPurpose_Node; //relevant for abstract rule checks. Abstract rule should see it concrete rule not. + + mitk::DataNode::Pointer dest_1_Node; + mitk::Image::Pointer dest_1; + mitk::DataNode::Pointer dest_2_Node; + mitk::Image::Pointer dest_2; + + bool hasRelationProperties(mitk::IPropertyProvider *provider, std::string instance = "") const + { + auto keyPath = mitk::PropertyRelationRuleBase::GetRootKeyPath(); + if (!instance.empty()) + { + keyPath.AddElement(instance); + } + + auto prefix = mitk::PropertyKeyPathToPropertyName(keyPath); + auto keys = provider->GetPropertyKeys(); + + for (const auto &key : keys) + { + if (key.find(prefix) == 0) + { + return true; + } + } + + return false; + } + + std::vector GetReferenceSequenceIndices(const mitk::IPropertyProvider * source, + const mitk::IPropertyProvider * destination) const + { + std::vector result; + + auto destInstanceUIDProp = destination->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0018)); + + if (destInstanceUIDProp.IsNull()) + { + return result; + } + + mitk::PropertyKeyPath referencedInstanceUIDs; + referencedInstanceUIDs.AddElement("DICOM").AddElement("0008").AddAnySelection("2112").AddElement("0008").AddElement("1155"); + + auto sourceRegExStr = PropertyKeyPathToPropertyRegEx(referencedInstanceUIDs);; + auto regEx = std::regex(sourceRegExStr); + + std::vector keys; + //workaround until T24729 is done. Please remove if T24728 is done + keys = source->GetPropertyKeys(); + //end workaround for T24729 + + for (const auto &key : keys) + { + if (std::regex_match(key, regEx)) + { + auto refUIDProp = source->GetConstProperty(key); + if (*refUIDProp == *destInstanceUIDProp) + { + mitk::PropertyKeyPath finding = mitk::PropertyNameToPropertyKeyPath(key); + result.push_back(std::to_string(finding.GetNode(2).selection)); + } + } + } + + return result; + }; + + void SetDICOMReferenceInfo(mitk::IPropertyOwner* owner, const std::string& instanceUID, const std::string& classUID, const std::string& purpose, unsigned int sequElement) + { + mitk::PropertyKeyPath refInstanceUIDPath; + refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1155"); + owner->SetProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath), mitk::TemporoSpatialStringProperty::New(instanceUID)); + + mitk::PropertyKeyPath refClassUIDPath; + refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1150"); + owner->SetProperty(PropertyKeyPathToPropertyName(refClassUIDPath), mitk::TemporoSpatialStringProperty::New(classUID)); + + mitk::PropertyKeyPath purposePath; + purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104"); + owner->SetProperty(PropertyKeyPathToPropertyName(purposePath), mitk::TemporoSpatialStringProperty::New(purpose)); + } + + bool IsCorrectDICOMReference(const mitk::IPropertyOwner* owner, const std::string& instanceUID, const std::string& classUID, const std::string& purpose, unsigned int sequElement) const + { + mitk::PropertyKeyPath refInstanceUIDPath; + refInstanceUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1155"); + auto prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(refInstanceUIDPath)); + if (prop->GetValueAsString() != instanceUID) + { + return false; + } + + mitk::PropertyKeyPath refClassUIDPath; + refClassUIDPath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0008").AddElement("1150"); + prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(refClassUIDPath)); + if (prop->GetValueAsString() != classUID) + { + return false; + } + + mitk::PropertyKeyPath purposePath; + purposePath.AddElement("DICOM").AddElement("0008").AddSelection("2112", sequElement).AddElement("0040").AddSelection("a170", 0).AddElement("0008").AddElement("0104"); + prop = owner->GetConstProperty(PropertyKeyPathToPropertyName(purposePath)); + if (prop->GetValueAsString() != purpose) + { + return false; + } + + return true; + } + + +public: + void setUp() override + { + auto instanceUIDPropName = mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0018); + auto classUIDPropName = mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0016); + + rule = mitk::SourceImageRelationRule::New("Test"); + + abstractRule = mitk::SourceImageRelationRule::New(); + + unRelated = mitk::Image::New(); + unRelated->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("unRelated")); + unRelated->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image")); + unRelated_Node = mitk::DataNode::New(); + unRelated_Node->SetData(unRelated); + + dest_1_Node = mitk::DataNode::New(); + dest_1_Node->SetName("dest_1"); + dest_1 = mitk::Image::New(); + dest_1->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("dest_1")); + dest_1->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image")); + dest_1_Node->SetData(dest_1); + + + + dest_2_Node = mitk::DataNode::New(); + dest_2_Node->SetName("dest_2"); + dest_2 = mitk::Image::New(); + dest_2->SetProperty(instanceUIDPropName, mitk::TemporoSpatialStringProperty::New("dest_2")); + dest_2->SetProperty(classUIDPropName, mitk::TemporoSpatialStringProperty::New("image")); + dest_2_Node->SetData(dest_2); + + source_implicit_1 = mitk::Image::New(); + SetDICOMReferenceInfo(source_implicit_1, "dest_1", "image", "Test", 0); + source_implicit_1_Node = mitk::DataNode::New(); + source_implicit_1_Node->SetData(source_implicit_1); + + source_idOnly_1 = mitk::Image::New(); + std::string name = "MITK.Relations.1.relationUID"; + source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid1")); + name = "MITK.Relations.1.destinationUID"; + source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID())); + name = "MITK.Relations.1.ruleID"; + source_idOnly_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); + source_idOnly_1_Node = mitk::DataNode::New(); + source_idOnly_1_Node->SetData(source_idOnly_1); + + source_data_1 = mitk::Image::New(); + SetDICOMReferenceInfo(source_data_1, "dest_1", "image", "Test", 0); + SetDICOMReferenceInfo(source_data_1, "dest_2", "image", "otherpurpose", 1); + name = "MITK.Relations.1.relationUID"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid2")); + name = "MITK.Relations.1.ruleID"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); + name = "MITK.Relations.1.SourceImageSequenceItem"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("0")); + name = "MITK.Relations.2.relationUID"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid10")); + name = "MITK.Relations.2.SourceImageSequenceItem"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("1")); + name = "MITK.Relations.2.ruleID"; + source_data_1->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose")); + source_data_1_Node = mitk::DataNode::New(); + source_data_1_Node->SetData(source_data_1); + + source_1 = mitk::Image::New(); + SetDICOMReferenceInfo(source_1, "dest_1", "image", "Test", 0); + SetDICOMReferenceInfo(source_1, "dest_2", "image", "otherpurpose", 1); + name = "MITK.Relations.1.relationUID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid3")); + name = "MITK.Relations.1.destinationUID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID())); + name = "MITK.Relations.1.ruleID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New(rule->GetRuleID())); + name = "MITK.Relations.1.SourceImageSequenceItem"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New("0")); + name = "MITK.Relations.2.relationUID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New("uid8")); + name = "MITK.Relations.2.destinationUID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New(dest_2->GetUID())); + name = "MITK.Relations.2.ruleID"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose")); + name = "MITK.Relations.2.SourceImageSequenceItem"; + source_1->SetProperty(name.c_str(), mitk::StringProperty::New("1")); + source_1_Node = mitk::DataNode::New(); + source_1_Node->SetData(source_1); + + source_otherRule = mitk::Image::New(); + name = "MITK.Relations.1.relationUID"; + source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New("uid7")); + name = "MITK.Relations.1.destinationUID"; + source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID())); + name = "MITK.Relations.1.ruleID"; + source_otherRule->SetProperty(name.c_str(), mitk::StringProperty::New("otherRuleID")); + source_otherRule_Node = mitk::DataNode::New(); + source_otherRule_Node->SetData(source_otherRule); + + source_otherPurpose = mitk::Image::New(); + name = "MITK.Relations.1.relationUID"; + source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New("uid9")); + name = "MITK.Relations.1.destinationUID"; + source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New(dest_1->GetUID())); + name = "MITK.Relations.1.ruleID"; + source_otherPurpose->SetProperty(name.c_str(), mitk::StringProperty::New("SourceImageRelation otherpurpose")); + source_otherPurpose_Node = mitk::DataNode::New(); + source_otherPurpose_Node->SetData(source_otherPurpose); + } + + void tearDown() override {} + + void IsSourceCandidate() + { + CPPUNIT_ASSERT(rule->IsSourceCandidate(mitk::DataNode::New())); + CPPUNIT_ASSERT(!rule->IsSourceCandidate(nullptr)); + } + + void IsDestinationCandidate() + { + CPPUNIT_ASSERT(rule->IsDestinationCandidate(this->dest_1_Node)); + CPPUNIT_ASSERT(rule->IsDestinationCandidate(this->dest_1)); + CPPUNIT_ASSERT(!rule->IsDestinationCandidate(mitk::DataNode::New())); + CPPUNIT_ASSERT(!rule->IsDestinationCandidate(nullptr)); + } + + void IsSource() + { + CPPUNIT_ASSERT_THROW_MESSAGE( + "Violated precondition (nullptr) does not throw.", rule->IsSource(nullptr), itk::ExceptionObject); + + CPPUNIT_ASSERT(!rule->IsSource(unRelated)); + CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1)); + CPPUNIT_ASSERT(rule->IsSource(source_data_1)); + CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1)); + CPPUNIT_ASSERT(rule->IsSource(source_1)); + + CPPUNIT_ASSERT(!rule->IsSource(source_otherRule)); + CPPUNIT_ASSERT(!rule->IsSource(source_otherPurpose)); + + CPPUNIT_ASSERT(!rule->IsSource(source_implicit_1_Node)); + CPPUNIT_ASSERT(rule->IsSource(source_data_1_Node)); + CPPUNIT_ASSERT(rule->IsSource(source_idOnly_1_Node)); + CPPUNIT_ASSERT(rule->IsSource(source_1_Node)); + + CPPUNIT_ASSERT(!rule->IsSource(source_otherRule_Node)); + CPPUNIT_ASSERT(!rule->IsSource(source_otherPurpose_Node)); + + + CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated)); + CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_1)); + + CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_otherPurpose)); + + CPPUNIT_ASSERT(!abstractRule->IsSource(unRelated_Node)); + CPPUNIT_ASSERT(!abstractRule->IsSource(source_implicit_1_Node)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_data_1_Node)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_idOnly_1_Node)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_1_Node)); + + CPPUNIT_ASSERT(!abstractRule->IsSource(source_otherRule_Node)); + CPPUNIT_ASSERT(abstractRule->IsSource(source_otherPurpose_Node)); + } + + void HasRelation() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->HasRelation(nullptr, dest_1), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->HasRelation(source_1, nullptr), + itk::ExceptionObject); + + CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(rule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(rule->HasRelation(source_otherPurpose, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + + CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); + CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); + + + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(abstractRule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherRule, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_otherPurpose, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + CPPUNIT_ASSERT(abstractRule->HasRelation(source_implicit_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_data_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_idOnly_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + } + + void GetExistingRelations() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->GetExistingRelations(nullptr), + itk::ExceptionObject); + + CPPUNIT_ASSERT(rule->GetExistingRelations(unRelated).empty()); + CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherRule).empty()); + CPPUNIT_ASSERT(rule->GetExistingRelations(source_otherPurpose).empty()); + CPPUNIT_ASSERT(rule->GetExistingRelations(source_implicit_1).empty()); + + auto uids = rule->GetExistingRelations(source_idOnly_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid1"); + + uids = rule->GetExistingRelations(source_data_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid2"); + + uids = rule->GetExistingRelations(source_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid3"); + + + CPPUNIT_ASSERT(abstractRule->GetExistingRelations(unRelated).empty()); + CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_otherRule).empty()); + CPPUNIT_ASSERT(abstractRule->GetExistingRelations(source_implicit_1).empty()); + + uids = abstractRule->GetExistingRelations(source_idOnly_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid1"); + + uids = abstractRule->GetExistingRelations(source_data_1); + CPPUNIT_ASSERT(uids.size() == 2); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end()); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid10") != uids.end()); + + uids = abstractRule->GetExistingRelations(source_1); + CPPUNIT_ASSERT(uids.size() == 2); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end()); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end()); + + uids = abstractRule->GetExistingRelations(source_otherPurpose); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid9"); + } + + void GetRelationUIDs() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->GetRelationUIDs(nullptr, dest_1), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->GetRelationUIDs(source_1, nullptr), + itk::ExceptionObject); + + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, unRelated).empty()); + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_1, dest_2).empty()); + CPPUNIT_ASSERT(rule->GetRelationUIDs(unRelated, dest_1).empty()); + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherRule, dest_1).empty()); + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_otherPurpose, dest_1).empty()); + + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1"); + CPPUNIT_ASSERT(rule->GetRelationUIDs(source_data_1, dest_1).front() == "uid2"); + auto uids = rule->GetRelationUIDs(source_1, dest_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(uids.front() == "uid3"); + + CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_1, unRelated).empty()); + CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(unRelated, dest_1).empty()); + CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherRule, dest_1).empty()); + CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_otherPurpose, dest_1).front() == "uid9"); + + CPPUNIT_ASSERT(abstractRule->GetRelationUIDs(source_idOnly_1, dest_1).front() == "uid1"); + uids = abstractRule->GetRelationUIDs(source_data_1, dest_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid2") != uids.end()); + uids = abstractRule->GetRelationUIDs(source_1, dest_1); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid3") != uids.end()); + uids = abstractRule->GetRelationUIDs(source_1, dest_2); + CPPUNIT_ASSERT(uids.size() == 1); + CPPUNIT_ASSERT(std::find(uids.begin(), uids.end(), "uid8") != uids.end()); + } + + void GetSourceCandidateIndicator() + { + auto predicate = rule->GetSourceCandidateIndicator(); + + CPPUNIT_ASSERT(predicate->CheckNode(mitk::DataNode::New())); + CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); + } + + void GetDestinationCandidateIndicator() + { + auto predicate = rule->GetDestinationCandidateIndicator(); + + CPPUNIT_ASSERT(predicate->CheckNode(this->dest_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(mitk::DataNode::New())); + CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); + } + + void GetConnectedSourcesDetector() + { + auto predicate = rule->GetConnectedSourcesDetector(); + + CPPUNIT_ASSERT(!predicate->CheckNode(nullptr)); + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node)); + + + auto predicate2 = abstractRule->GetConnectedSourcesDetector(); + + CPPUNIT_ASSERT(!predicate2->CheckNode(nullptr)); + CPPUNIT_ASSERT(!predicate2->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate2->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(predicate2->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate2->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate2->CheckNode(source_1_Node)); + + CPPUNIT_ASSERT(!predicate2->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(predicate2->CheckNode(source_otherPurpose_Node)); + } + + void GetSourcesDetector() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->GetSourcesDetector(nullptr), + itk::ExceptionObject); + + auto predicate = rule->GetSourcesDetector(dest_1); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + + predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + + predicate = rule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + + predicate = rule->GetSourcesDetector(dest_2, mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_1_Node)); + + predicate = abstractRule->GetSourcesDetector(dest_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(!predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + + predicate = abstractRule->GetSourcesDetector(dest_1); + + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(source_otherRule_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_otherPurpose_Node)); + + CPPUNIT_ASSERT(predicate->CheckNode(source_implicit_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_data_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_idOnly_1_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(source_1_Node)); + } + + void GetDestinationsDetector() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->GetDestinationsDetector(nullptr), + itk::ExceptionObject); + + auto predicate = rule->GetDestinationsDetector(source_otherRule); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node)); + + predicate = rule->GetDestinationsDetector(source_otherPurpose); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node)); + + predicate = rule->GetDestinationsDetector(source_implicit_1); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = + rule->GetDestinationsDetector(source_implicit_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node)); + + predicate = rule->GetDestinationsDetector(source_data_1); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = + rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = + rule->GetDestinationsDetector(source_data_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_1_Node)); + + predicate = rule->GetDestinationsDetector(source_idOnly_1); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = + rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = + rule->GetDestinationsDetector(source_idOnly_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + + predicate = rule->GetDestinationsDetector(source_1); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node)); + predicate = + rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node)); + predicate = + rule->GetDestinationsDetector(source_1, mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node)); + + predicate = abstractRule->GetDestinationsDetector(source_otherPurpose); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + predicate = abstractRule->GetDestinationsDetector(source_otherPurpose); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + } + + void GetDestinationDetector() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->GetDestinationDetector(nullptr, "uid1"), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (relation uid is invalid) does not throw.", + rule->GetDestinationDetector(source_1, "invalid uid"), + itk::ExceptionObject); + + auto predicate = rule->GetDestinationDetector(source_1, "uid3"); + CPPUNIT_ASSERT(!predicate->CheckNode(unRelated_Node)); + CPPUNIT_ASSERT(predicate->CheckNode(dest_1_Node)); + CPPUNIT_ASSERT(!predicate->CheckNode(dest_2_Node)); + } + + void Connect() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->Connect(nullptr, dest_1), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->Connect(source_1, nullptr), + itk::ExceptionObject); + + // check upgrade of an implicit connection + CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Implicit_Data); + rule->Connect(source_implicit_1, dest_1); + CPPUNIT_ASSERT(rule->HasRelation(source_implicit_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + auto dcmRefs = GetReferenceSequenceIndices(source_implicit_1, dest_1); + CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_implicit_1, "dest_1", "image", "Test", 0)); + + // check upgrade and reuse of an data connection (no new relation should be generated). + CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_Data); + rule->Connect(source_data_1, dest_1); + CPPUNIT_ASSERT(rule->HasRelation(source_data_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + + auto relUID = rule->GetRelationUIDs(source_data_1, dest_1); + CPPUNIT_ASSERT(relUID.size() == 1); + + std::string name = "MITK.Relations.1.destinationUID"; + auto prop = source_data_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE( + "Destination uid was not stored with the correct key. Already existing session should be used.", prop); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID()); + + name = "MITK.Relations.1.ruleID"; + prop = source_data_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID()); + + name = "MITK.Relations.1.SourceImageSequenceItem"; + prop = source_data_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0"); + + dcmRefs = GetReferenceSequenceIndices(source_data_1, dest_1); + CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_data_1, "dest_1", "image", "Test", 0)); + + // check actualization of an id only connection + rule->Connect(source_idOnly_1, dest_1); + CPPUNIT_ASSERT(rule->HasRelation(source_idOnly_1, dest_1) == + mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.", + rule->GetExistingRelations(source_1).size() == 1); + + // check actualization of an existing connection + rule->Connect(source_1, dest_1); + CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT_MESSAGE("Additional relation was defined instead of updating exting one.", + rule->GetExistingRelations(source_1).size() == 1); + name = "MITK.Relations.1.destinationUID"; + prop = source_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE( + "Destination uid was not stored with the correct key. Already existing session should be used.", prop); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID()); + + name = "MITK.Relations.1.ruleID"; + prop = source_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID()); + + name = "MITK.Relations.1.SourceImageSequenceItem"; + prop = source_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0"); + + dcmRefs = GetReferenceSequenceIndices(source_1, dest_1); + CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0)); + + // check creation of an new connection + rule->Connect(unRelated, dest_1); + CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT_MESSAGE("Relation was not defined instead of updating exting one.", + rule->GetExistingRelations(unRelated).size() == 1); + name = "MITK.Relations.1.destinationUID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID()); + + name = "MITK.Relations.1.ruleID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID()); + + name = "MITK.Relations.1.SourceImageSequenceItem"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0"); + + dcmRefs = GetReferenceSequenceIndices(unRelated, dest_1); + CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was defined instead of using the existing one.", dcmRefs.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Dicom reference squence is corrupted. Should be just an index 0.", dcmRefs[0] == "0"); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_1", "image", "Test", 0)); + + // check creation of a 2nd connection of the same purpose + rule->Connect(unRelated, dest_2); + CPPUNIT_ASSERT(rule->HasRelation(unRelated, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + CPPUNIT_ASSERT_MESSAGE("Additional relation was not defined.", + rule->GetExistingRelations(unRelated).size() == 2); + name = "MITK.Relations.1.destinationUID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_1->GetUID()); + + name = "MITK.Relations.1.ruleID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID()); + + name = "MITK.Relations.1.SourceImageSequenceItem"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "0"); + + name = "MITK.Relations.2.destinationUID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == dest_2->GetUID()); + + name = "MITK.Relations.2.ruleID"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect ruleID was stored.", prop->GetValueAsString() == rule->GetRuleID()); + + name = "MITK.Relations.2.SourceImageSequenceItem"; + prop = unRelated->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == "1"); + + + dcmRefs = GetReferenceSequenceIndices(unRelated, dest_2); + CPPUNIT_ASSERT_MESSAGE("Additional dicom reference was not defined.", dcmRefs.size() == 1); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_1", "image", "Test", 0)); + CPPUNIT_ASSERT_MESSAGE("Dicom reference is not correct.", IsCorrectDICOMReference(unRelated, "dest_2", "image", "Test", 1)); + } + + void Disconnect() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (source is nullptr) does not throw.", + rule->Disconnect(nullptr, dest_1), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->Disconnect(source_1, nullptr), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (destination is nullptr) does not throw.", + rule->Disconnect(nullptr, "uid"), + itk::ExceptionObject); + + CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); + rule->Disconnect(source_1, unRelated); + CPPUNIT_ASSERT(rule->HasRelation(source_1, unRelated) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT_MESSAGE("Other relationdata property was removed.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0)); + + //check if index correction is correct, when disconnecting + rule->Connect(source_1, dest_2); + rule->Connect(source_1, unRelated); + rule->Disconnect(source_1, dest_2); + CPPUNIT_ASSERT(rule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "1")); + CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "2")); + CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "3")); + CPPUNIT_ASSERT(this->hasRelationProperties(source_1, "4")); + CPPUNIT_ASSERT_MESSAGE("Dicom reference to dest_1 has been removed.", IsCorrectDICOMReference(source_1, "dest_1", "image", "Test", 0)); + CPPUNIT_ASSERT_MESSAGE("Dicom reference to dest_2 (other purpose) has been removed or has not a corrected sequence index (1 instead of 2).", IsCorrectDICOMReference(source_1, "dest_2", "image", "otherpurpose", 1)); + CPPUNIT_ASSERT_MESSAGE("Dicom reference to unRelated has been removed or has not a corrected sequence index (1 instead of 2).", IsCorrectDICOMReference(source_1, "unRelated", "image", "Test", 2)); + + std::string name = "MITK.Relations.4.destinationUID"; + auto prop = source_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE( + "Destination uid was not stored with the correct key. Already existing session should be used.", prop); + CPPUNIT_ASSERT_MESSAGE("Incorrect destination uid was stored.", prop->GetValueAsString() == unRelated->GetUID()); + name = "MITK.Relations.4.SourceImageSequenceItem"; + prop = source_1->GetProperty(name.c_str()); + CPPUNIT_ASSERT_MESSAGE("SourceImageSequenceItem was not actualized correctly.", prop->GetValueAsString() == "2"); + + rule->Disconnect(source_otherPurpose, dest_1); + CPPUNIT_ASSERT_MESSAGE("Data of other rule purpose was removed.", this->hasRelationProperties(source_otherPurpose, "1")); + } + + void Connect_abstract() + { + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.", + abstractRule->Connect(nullptr, dest_1), + itk::ExceptionObject); + + CPPUNIT_ASSERT_THROW_MESSAGE("Violated precondition (abstract does not connect) does not throw.", + abstractRule->Connect(source_1, nullptr), + itk::ExceptionObject); + } + + void Disconnect_abstract() + { + + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + abstractRule->Disconnect(source_1, dest_2); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_2) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "2")); + + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::Connected_ID); + abstractRule->Disconnect(source_1, dest_1); + CPPUNIT_ASSERT(abstractRule->HasRelation(source_1, dest_1) == mitk::PropertyRelationRuleBase::RelationType::None); + CPPUNIT_ASSERT(!this->hasRelationProperties(source_1, "1")); + + abstractRule->Disconnect(source_otherPurpose, dest_1); + CPPUNIT_ASSERT_MESSAGE("Data of other rule type was removed.", !this->hasRelationProperties(source_otherPurpose, "1")); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkSourceImageRelationRule)