Mercurial > hg > orthanc
diff OrthancServer/ResourceFinder.cpp @ 1359:4378a6636187
rename
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 15 May 2015 13:17:37 +0200 |
parents | 62d2d35b725e |
children | 0649c5aef34a |
line wrap: on
line diff
--- a/OrthancServer/ResourceFinder.cpp Wed May 13 17:56:27 2015 +0200 +++ b/OrthancServer/ResourceFinder.cpp Fri May 15 13:17:37 2015 +0200 @@ -31,24 +31,367 @@ #include "PrecompiledHeadersServer.h" -#include "ResourceFinder.h" +#include "BaseResourceFinder.h" + +#include "FromDcmtkBridge.h" +#include "ServerContext.h" + +#include <glog/logging.h> +#include <boost/algorithm/string/predicate.hpp> namespace Orthanc { - namespace + class BaseResourceFinder::CandidateResources { - class IConstraint : public boost::noncopyable + private: + typedef std::map<DicomTag, std::string> Query; + + BaseResourceFinder& finder_; + ServerIndex& index_; + ResourceType level_; + bool isFilterApplied_; + std::set<std::string> filtered_; + + + static void ListToSet(std::set<std::string>& target, + const std::list<std::string>& source) + { + for (std::list<std::string>::const_iterator + it = source.begin(); it != source.end(); ++it) + { + target.insert(*it); + } + } + + + void RestrictIdentifier(const DicomTag& tag, + const std::string& value) + { + assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || + (level_ == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) || + (level_ == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || + (level_ == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || + (level_ == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); + + LOG(INFO) << "Lookup for identifier tag " + << FromDcmtkBridge::GetName(tag) << " (value: " << value << ")"; + + std::list<std::string> resources; + index_.LookupIdentifier(resources, tag, value, level_); + + if (isFilterApplied_) + { + std::set<std::string> s; + ListToSet(s, resources); + + std::set<std::string> tmp = filtered_; + filtered_.clear(); + + for (std::set<std::string>::const_iterator + it = tmp.begin(); it != tmp.end(); ++it) + { + if (s.find(*it) != s.end()) + { + filtered_.insert(*it); + } + } + } + else + { + assert(filtered_.empty()); + isFilterApplied_ = true; + ListToSet(filtered_, resources); + } + } + + + public: + CandidateResources(BaseResourceFinder& finder) : + finder_(finder), + index_(finder.context_.GetIndex()), + level_(ResourceType_Patient), + isFilterApplied_(false) + { + } + + ResourceType GetLevel() const { - public: - virtual ~IConstraint() + return level_; + } + + void GoDown() + { + assert(level_ != ResourceType_Instance); + + if (isFilterApplied_) + { + std::set<std::string> tmp = filtered_; + + filtered_.clear(); + + for (std::set<std::string>::const_iterator + it = tmp.begin(); it != tmp.end(); ++it) + { + std::list<std::string> children; + try + { + index_.GetChildren(children, *it); + ListToSet(filtered_, children); + } + catch (OrthancException&) + { + // The resource was removed in the meantime + } + } + } + + switch (level_) { + case ResourceType_Patient: + level_ = ResourceType_Study; + break; + + case ResourceType_Study: + level_ = ResourceType_Series; + break; + + case ResourceType_Series: + level_ = ResourceType_Instance; + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + } + + + void Flatten(std::list<std::string>& resources) const + { + resources.clear(); + + if (isFilterApplied_) + { + for (std::set<std::string>::const_iterator + it = filtered_.begin(); it != filtered_.end(); ++it) + { + resources.push_back(*it); + } + } + else + { + index_.GetAllUuids(resources, level_); + } + } + + + void RestrictIdentifier(const DicomTag& tag) + { + Identifiers::const_iterator it = finder_.identifiers_.find(tag); + if (it != finder_.identifiers_.end()) + { + RestrictIdentifier(it->first, it->second); + } + } + + + void RestrictMainDicomTags() + { + if (finder_.mainTagsFilter_ == NULL) + { + return; } - virtual bool Apply(const std::string& value) = 0; - }; + std::list<std::string> resources; + Flatten(resources); + + isFilterApplied_ = true; + filtered_.clear(); + + for (std::list<std::string>::const_iterator + it = resources.begin(); it != resources.end(); it++) + { + DicomMap mainTags; + if (index_.GetMainDicomTags(mainTags, *it, level_)) + { + if (finder_.mainTagsFilter_->Apply(mainTags, level_)) + { + filtered_.insert(*it); + } + } + } + } + }; + + + BaseResourceFinder::BaseResourceFinder(ServerContext& context) : + context_(context), + level_(ResourceType_Patient), + maxResults_(0) + { + } + + + void BaseResourceFinder::ApplyAtLevel(CandidateResources& candidates, + ResourceType level) + { + if (level != ResourceType_Patient) + { + candidates.GoDown(); + } + + switch (level_) + { + case ResourceType_Patient: + { + candidates.RestrictIdentifier(DICOM_TAG_PATIENT_ID); + break; + } + + case ResourceType_Study: + { + candidates.RestrictIdentifier(DICOM_TAG_STUDY_INSTANCE_UID); + candidates.RestrictIdentifier(DICOM_TAG_ACCESSION_NUMBER); + break; + } + + case ResourceType_Series: + { + candidates.RestrictIdentifier(DICOM_TAG_SERIES_INSTANCE_UID); + break; + } + + case ResourceType_Instance: + { + candidates.RestrictIdentifier(DICOM_TAG_SOP_INSTANCE_UID); + break; + } + + default: + throw OrthancException(ErrorCode_InternalError); + } + + candidates.RestrictMainDicomTags(); + } + + + + void BaseResourceFinder::SetIdentifier(const DicomTag& tag, + const std::string& value) + { + assert((level_ >= ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || + (level_ >= ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) || + (level_ >= ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || + (level_ >= ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || + (level_ >= ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); + + identifiers_[tag] = value; + } + static bool LookupOneInstance(std::string& result, + ServerIndex& index, + const std::string& id, + ResourceType type) + { + if (type == ResourceType_Instance) + { + result = id; + return true; + } + + std::string childId; + { + std::list<std::string> children; + index.GetChildInstances(children, id); + + if (children.empty()) + { + return false; + } + + childId = children.front(); + } + + return LookupOneInstance(result, index, childId, GetChildResourceType(type)); } + + bool BaseResourceFinder::Apply(std::list<std::string>& result) + { + CandidateResources candidates(*this); + + ApplyAtLevel(candidates, ResourceType_Patient); + + if (level_ == ResourceType_Study || + level_ == ResourceType_Series || + level_ == ResourceType_Instance) + { + ApplyAtLevel(candidates, ResourceType_Study); + } + + if (level_ == ResourceType_Series || + level_ == ResourceType_Instance) + { + ApplyAtLevel(candidates, ResourceType_Series); + } + + if (level_ == ResourceType_Instance) + { + ApplyAtLevel(candidates, ResourceType_Instance); + } + + if (instanceFilter_ == NULL) + { + candidates.Flatten(result); + + if (maxResults_ != 0 && + result.size() >= maxResults_) + { + result.resize(maxResults_); + return false; + } + else + { + return true; + } + } + else + { + std::list<std::string> tmp; + candidates.Flatten(tmp); + + result.clear(); + for (std::list<std::string>::const_iterator + resource = tmp.begin(); resource != tmp.end(); ++resource) + { + try + { + std::string instance; + if (LookupOneInstance(instance, context_.GetIndex(), *resource, level_)) + { + Json::Value content; + context_.ReadJson(content, instance); + if (instanceFilter_->Apply(*resource, content)) + { + result.push_back(*resource); + + if (maxResults_ != 0 && + result.size() >= maxResults_) + { + // Too many results, stop before recording this new match + return false; + } + } + } + } + catch (OrthancException&) + { + // This resource has been deleted since the search was started + } + } + } + + return true; // All the matching resources have been returned + } }