diff --git a/Modules/Core/include/mitkIOVolumeSplitReason.h b/Modules/Core/include/mitkIOVolumeSplitReason.h index 7327d54dbd..0164228b55 100644 --- a/Modules/Core/include/mitkIOVolumeSplitReason.h +++ b/Modules/Core/include/mitkIOVolumeSplitReason.h @@ -1,77 +1,80 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkIOVolumeSplitReason_h #define mitkIOVolumeSplitReason_h #include "itkLightObject.h" #include "mitkCommon.h" #include "MitkCoreExports.h" namespace mitk { class MITKCORE_EXPORT IOVolumeSplitReason : public itk::LightObject { public: mitkClassMacroItkParent(IOVolumeSplitReason, itk::LightObject); itkFactorylessNewMacro(IOVolumeSplitReason); itkCloneMacro(IOVolumeSplitReason); enum class ReasonType { Unkown = 0, ValueSplitDifference = 2, //*< split due to different values in splitting relevant dicom tags ValueSortDistance = 3, //*< split due value distance of sort criterion to large for relevant dicom tag(s) ImagePostionMissing = 4, //*< split because image position tag was missing in one of the compared files OverlappingSlices = 8, //*< split because at least two input files are overlapping in world coordinate space GantryTiltDifference = 16, //*< split because the gantry tilts of at least two input files were different SliceDistanceInconsistency = 32, //*< split because the distance between slices were inconsistent. // This can either be evoked by volumes with heterogeneous z spacing or by missing slices. // Details for this reason will contain the detected slice distance inconsistency MissingSlices = 33 //*< Indicates that is a split was done due to missing slices. (It is a sub class of SliceDistanceInconsistency // as all SliceDistanceInconsistency with a positive distance inconsistency greater then one times the slice // thickness are deemed also missing slices as split reason. This sub class was introduced to make it easier // for parsing applications to react on this important split reason. // Details for this reason will contain the assumed/detected number of missing slices }; void AddReason(ReasonType type, std::string_view detail = ""); void RemoveReason(ReasonType type); bool ReasonExists() const; bool ReasonExists(ReasonType type) const; std::string GetReasonDetails(ReasonType type) const; Pointer ExtendReason(const Self* otherReason) const; static std::string SerializeToJSON(const IOVolumeSplitReason*); + static Pointer DeserializeFromJSON(const std::string& reasonStr); + static std::string TypeToString(const IOVolumeSplitReason::ReasonType& reasonType); + static IOVolumeSplitReason::ReasonType StringToType(const std::string& reasonStr); protected: mitkCloneMacro(IOVolumeSplitReason); IOVolumeSplitReason(); ~IOVolumeSplitReason() override; IOVolumeSplitReason(const IOVolumeSplitReason& other); private: IOVolumeSplitReason& operator=(const IOVolumeSplitReason& other); using ReasonMapType = std::map; ReasonMapType m_ReasonMap; }; } #endif diff --git a/Modules/Core/src/IO/mitkIOVolumeSplitReason.cpp b/Modules/Core/src/IO/mitkIOVolumeSplitReason.cpp index 4b7d67d1cd..ca6a62b899 100644 --- a/Modules/Core/src/IO/mitkIOVolumeSplitReason.cpp +++ b/Modules/Core/src/IO/mitkIOVolumeSplitReason.cpp @@ -1,110 +1,160 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkIOVolumeSplitReason.h" #include void mitk::IOVolumeSplitReason::AddReason(ReasonType type, std::string_view detail) { m_ReasonMap.insert(std::make_pair(type, detail)); } void mitk::IOVolumeSplitReason::RemoveReason(ReasonType type) { m_ReasonMap.erase(type); } bool mitk::IOVolumeSplitReason::ReasonExists() const { return !m_ReasonMap.empty(); } bool mitk::IOVolumeSplitReason::ReasonExists(ReasonType type) const { return m_ReasonMap.cend() != m_ReasonMap.find(type); } std::string mitk::IOVolumeSplitReason::GetReasonDetails(ReasonType type) const { auto finding = m_ReasonMap.find(type); if (m_ReasonMap.cend() == finding) mitkThrow() << "Cannot get details for inexistent type."; return finding->second; }; mitk::IOVolumeSplitReason::Pointer mitk::IOVolumeSplitReason::ExtendReason(const Self* otherReason) const { if (nullptr == otherReason) mitkThrow() << "Cannot extend reason. Pass other reason is in valid."; Pointer result = this->Clone(); result->m_ReasonMap.insert(otherReason->m_ReasonMap.cbegin(), otherReason->m_ReasonMap.cend()); return result; } mitk::IOVolumeSplitReason::IOVolumeSplitReason(): itk::LightObject() { } mitk::IOVolumeSplitReason::~IOVolumeSplitReason() { } mitk::IOVolumeSplitReason::IOVolumeSplitReason(const IOVolumeSplitReason& other) { m_ReasonMap = other.m_ReasonMap; } std::string mitk::IOVolumeSplitReason::TypeToString(const IOVolumeSplitReason::ReasonType& reasonType) { switch (reasonType) { case IOVolumeSplitReason::ReasonType::GantryTiltDifference: return "gantry_tilt_difference"; case IOVolumeSplitReason::ReasonType::ImagePostionMissing: return "image_position_missing"; case IOVolumeSplitReason::ReasonType::OverlappingSlices: return "overlapping_slices"; case IOVolumeSplitReason::ReasonType::SliceDistanceInconsistency: return "slice_distance_inconsistency"; case IOVolumeSplitReason::ReasonType::ValueSortDistance: return "value_sort_distance"; case IOVolumeSplitReason::ReasonType::ValueSplitDifference: return "value_split_difference"; case IOVolumeSplitReason::ReasonType::MissingSlices: return "missing_slices"; } return "unknown"; } +mitk::IOVolumeSplitReason::ReasonType mitk::IOVolumeSplitReason::StringToType(const std::string& reasonStr) +{ + if (reasonStr == "gantry_tilt_difference") + return IOVolumeSplitReason::ReasonType::GantryTiltDifference; + else if (reasonStr == "image_position_missing") + return IOVolumeSplitReason::ReasonType::ImagePostionMissing; + else if (reasonStr == "overlapping_slices") + return IOVolumeSplitReason::ReasonType::OverlappingSlices; + else if (reasonStr == "slice_distance_inconsistency") + return IOVolumeSplitReason::ReasonType::SliceDistanceInconsistency; + else if (reasonStr == "value_sort_distance") + return IOVolumeSplitReason::ReasonType::ValueSortDistance; + else if (reasonStr == "value_split_difference") + return IOVolumeSplitReason::ReasonType::ValueSplitDifference; + else if (reasonStr == "missing_slices") + return IOVolumeSplitReason::ReasonType::MissingSlices; + + return IOVolumeSplitReason::ReasonType::Unkown; +} + std::string mitk::IOVolumeSplitReason::SerializeToJSON(const IOVolumeSplitReason* reason) { if (nullptr == reason) mitkThrow() << "Cannot extend reason. Pass other reason is in valid."; auto data = nlohmann::json::array(); for (const auto& [type, detail] : reason->m_ReasonMap) { auto details = nlohmann::json::array(); details.push_back(TypeToString(type)); - details.push_back(detail); + if (!detail.empty()) + { + details.push_back(detail); + } data.push_back(details); } return data.dump(); } + +mitk::IOVolumeSplitReason::Pointer mitk::IOVolumeSplitReason::DeserializeFromJSON(const std::string& reasonStr) +{ + if (reasonStr.empty()) + return nullptr; + + auto reason = IOVolumeSplitReason::New(); + + auto data = nlohmann::json::parse(reasonStr); + + for (const auto& jItem : data) + { + if (!jItem.empty()) + { + ReasonType reasonType = StringToType(jItem.at(0).get()); + + std::string detail; + if (jItem.size() > 1) + { + detail = jItem.at(1).get(); + } + reason->AddReason(reasonType, detail); + } + } + + return reason; +}