Mercurial > hg > orthanc-stone
diff Framework/Loaders/DicomStructureSetLoader.cpp @ 1416:d959bc8f6c1b loader-injection-feature
Instance lookup is now performed in a separate class through an interface. Another implementation can be injected (SetInstanceLookupHandler)
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Mon, 11 May 2020 17:37:30 +0200 |
parents | ffe9beb7c5d3 |
children | 30deba7bc8e2 |
line wrap: on
line diff
--- a/Framework/Loaders/DicomStructureSetLoader.cpp Mon May 11 09:50:02 2020 +0200 +++ b/Framework/Loaders/DicomStructureSetLoader.cpp Mon May 11 17:37:30 2020 +0200 @@ -48,8 +48,37 @@ } #endif + // implementation of IInstanceLookupHandler that uses Orthanc REST API calls to retrive the + // geometry of referenced instances + class DicomStructureSetLoader::RestInstanceLookupHandler : public DicomStructureSetLoader::IInstanceLookupHandler, + public LoaderStateMachine + { + public: + static boost::shared_ptr<RestInstanceLookupHandler > Create(DicomStructureSetLoader& loader) + { + boost::shared_ptr<RestInstanceLookupHandler> obj(new RestInstanceLookupHandler(loader)); + obj->LoaderStateMachine::PostConstructor(); + return obj; + } - class DicomStructureSetLoader::AddReferencedInstance : public LoaderStateMachine::State + protected: + RestInstanceLookupHandler(DicomStructureSetLoader& loader) + : LoaderStateMachine(loader.loadersContext_) + , loader_(loader) + { + } + + virtual void RetrieveReferencedSlices(const std::set<std::string>& nonEmptyInstances) ORTHANC_OVERRIDE; + + private: + // these subclasses hold the loading state + class AddReferencedInstance; // 2nd state + class LookupInstance; // 1st state + + DicomStructureSetLoader& loader_; + }; + + class DicomStructureSetLoader::RestInstanceLookupHandler::AddReferencedInstance : public LoaderStateMachine::State { private: std::string instanceId_; @@ -71,27 +100,14 @@ dicom.FromDicomAsJson(tags); DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); - - loader.content_->AddReferencedSlice(dicom); - loader.countProcessedInstances_ ++; - assert(loader.countProcessedInstances_ <= loader.countReferencedInstances_); - - loader.revision_++; - loader.SetStructuresUpdated(); - - if (loader.countProcessedInstances_ == loader.countReferencedInstances_) - { - // All the referenced instances have been loaded, finalize the RT-STRUCT - loader.content_->CheckReferencedSlices(); - loader.revision_++; - loader.SetStructuresReady(); - } + + loader.AddReferencedSlice(dicom); } }; // State that converts a "SOP Instance UID" to an Orthanc identifier - class DicomStructureSetLoader::LookupInstance : public LoaderStateMachine::State + class DicomStructureSetLoader::RestInstanceLookupHandler::LookupInstance : public LoaderStateMachine::State { private: std::string sopInstanceUid_; @@ -106,9 +122,6 @@ virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) { -#if 0 - LOG(TRACE) << "DicomStructureSetLoader::LookupInstance::Handle() (SUCCESS)"; -#endif DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); Json::Value lookup; @@ -147,6 +160,21 @@ } }; + void DicomStructureSetLoader::RestInstanceLookupHandler::RetrieveReferencedSlices( + const std::set<std::string>& nonEmptyInstances) + { + for (std::set<std::string>::const_iterator it = nonEmptyInstances.begin(); + it != nonEmptyInstances.end(); + ++it) + { + std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); + command->SetUri("/tools/lookup"); + command->SetMethod(Orthanc::HttpMethod_Post); + command->SetBody(*it); + command->AcquirePayload(new LookupInstance(loader_, *it)); + Schedule(command.release()); + } + } class DicomStructureSetLoader::LoadStructure : public LoaderStateMachine::State { @@ -159,53 +187,28 @@ virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) { DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); - + + // Set the actual structure set content { OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); + loader.content_.reset(new OrthancStone::DicomStructureSet(dicom)); - size_t structureCount = loader.content_->GetStructuresCount(); - loader.structureVisibility_.resize(structureCount); - bool everythingVisible = false; - if ((loader.initiallyVisibleStructures_.size() == 1) - && (loader.initiallyVisibleStructures_[0].size() == 1) - && (loader.initiallyVisibleStructures_[0][0] == '*')) - { - everythingVisible = true; - } - - for (size_t i = 0; i < structureCount; ++i) - { - // if a single "*" string is supplied, this means we want everything - // to be visible... - if(everythingVisible) - { - loader.structureVisibility_.at(i) = true; - } - else - { - // otherwise, we only enable visibility for those structures whose - // names are mentioned in the initiallyVisibleStructures_ array - const std::string& structureName = loader.content_->GetStructureName(i); - - std::vector<std::string>::iterator foundIt = - std::find( - loader.initiallyVisibleStructures_.begin(), - loader.initiallyVisibleStructures_.end(), - structureName); - std::vector<std::string>::iterator endIt = loader.initiallyVisibleStructures_.end(); - if (foundIt != endIt) - loader.structureVisibility_.at(i) = true; - else - loader.structureVisibility_.at(i) = false; - } - } } + // initialize visibility flags + SetDefaultStructureVisibility(); + + // retrieve the (non-empty) referenced instances (the CT slices containing the corresponding structures) // Some (admittedly invalid) Dicom files have empty values in the // 0008,1155 tag. We try our best to cope with this. + // this is why we use `nonEmptyInstances` and not `instances` std::set<std::string> instances; std::set<std::string> nonEmptyInstances; + + // this traverses the polygon collection for all structures and retrieve the SOPInstanceUID of + // the referenced instances loader.content_->GetReferencedInstances(instances); + for (std::set<std::string>::const_iterator it = instances.begin(); it != instances.end(); ++it) { @@ -214,20 +217,55 @@ nonEmptyInstances.insert(instance); } - loader.countReferencedInstances_ = - static_cast<unsigned int>(nonEmptyInstances.size()); + loader.RetrieveReferencedSlices(nonEmptyInstances); + } + + void SetDefaultStructureVisibility() + { + DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); + + size_t structureCount = loader.content_->GetStructuresCount(); - for (std::set<std::string>::const_iterator - it = nonEmptyInstances.begin(); it != nonEmptyInstances.end(); ++it) + loader.structureVisibility_.resize(structureCount); + bool everythingVisible = false; + if ((loader.initiallyVisibleStructures_.size() == 1) + && (loader.initiallyVisibleStructures_[0].size() == 1) + && (loader.initiallyVisibleStructures_[0][0] == '*')) + { + everythingVisible = true; + } + + for (size_t i = 0; i < structureCount; ++i) { - std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); - command->SetUri("/tools/lookup"); - command->SetMethod(Orthanc::HttpMethod_Post); - command->SetBody(*it); - command->AcquirePayload(new LookupInstance(loader, *it)); - Schedule(command.release()); + // if a single "*" string is supplied, this means we want everything + // to be visible... + if (everythingVisible) + { + loader.structureVisibility_.at(i) = true; + } + else + { + // otherwise, we only enable visibility for those structures whose + // names are mentioned in the initiallyVisibleStructures_ array + const std::string& structureName = loader.content_->GetStructureName(i); + + std::vector<std::string>::iterator foundIt = + std::find( + loader.initiallyVisibleStructures_.begin(), + loader.initiallyVisibleStructures_.end(), + structureName); + std::vector<std::string>::iterator endIt = loader.initiallyVisibleStructures_.end(); + if (foundIt != endIt) + loader.structureVisibility_.at(i) = true; + else + loader.structureVisibility_.at(i) = false; + } } } + + private: + + }; @@ -347,8 +385,9 @@ , countReferencedInstances_(0) , structuresReady_(false) { + // the default handler to retrieve slice geometry is RestInstanceLookupHandler + instanceLookupHandler_ = RestInstanceLookupHandler::Create(*this); } - boost::shared_ptr<OrthancStone::DicomStructureSetLoader> DicomStructureSetLoader::Create(OrthancStone::ILoadersContext& loadersContext) { @@ -357,7 +396,31 @@ loadersContext)); obj->LoaderStateMachine::PostConstructor(); return obj; + } + void DicomStructureSetLoader::AddReferencedSlice(const Orthanc::DicomMap& dicom) + { + content_->AddReferencedSlice(dicom); + countProcessedInstances_ ++; + assert(countProcessedInstances_ <= countReferencedInstances_); + + revision_++; + SetStructuresUpdated(); + + if (countProcessedInstances_ == countReferencedInstances_) + { + // All the referenced instances have been loaded, finalize the RT-STRUCT + content_->CheckReferencedSlices(); + revision_++; + SetStructuresReady(); + } + } + + void DicomStructureSetLoader::RetrieveReferencedSlices(const std::set<std::string>& nonEmptyInstances) + { + // we set the number of referenced instances. This allows to know, in the method above, when we're done + countReferencedInstances_ = static_cast<unsigned int>(nonEmptyInstances.size()); + instanceLookupHandler_->RetrieveReferencedSlices(nonEmptyInstances); } void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display)