diff OrthancServer/Sources/OrthancFindRequestHandler.cpp @ 4940:304514ce84ee more-tags

tools/find + C-Find + list-resources now all using the same code (ExpandResource) to build 'computed tags'
author Alain Mazy <am@osimis.io>
date Tue, 15 Mar 2022 15:57:21 +0100
parents 6eff25f70121
children 2cfa50d8eb60
line wrap: on
line diff
--- a/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Tue Mar 15 09:09:52 2022 +0100
+++ b/OrthancServer/Sources/OrthancFindRequestHandler.cpp	Tue Mar 15 15:57:21 2022 +0100
@@ -38,275 +38,27 @@
 
 namespace Orthanc
 {
-  static void GetChildren(std::list<std::string>& target,
-                          ServerIndex& index,
-                          const std::list<std::string>& source)
-  {
-    target.clear();
-
-    for (std::list<std::string>::const_iterator
-           it = source.begin(); it != source.end(); ++it)
-    {
-      std::list<std::string> tmp;
-      index.GetChildren(tmp, *it);
-      target.splice(target.end(), tmp);
-    }
-  }
-
-
-  static void StoreSetOfStrings(DicomMap& result,
-                                const DicomTag& tag,
-                                const std::set<std::string>& values)
-  {
-    bool isFirst = true;
-
-    std::string s;
-    for (std::set<std::string>::const_iterator
-           it = values.begin(); it != values.end(); ++it)
-    {
-      if (isFirst)
-      {
-        isFirst = false;
-      }
-      else
-      {
-        s += "\\";
-      }
-
-      s += *it;
-    }
-
-    result.SetValue(tag, s, false);
-  }
-
-
-  static void ComputePatientCounters(DicomMap& result,
-                                     ServerIndex& index,
-                                     const std::string& patient,
-                                     const DicomMap& query)
-  {
-    std::list<std::string> studies;
-    index.GetChildren(studies, patient);
-
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES,
-                      boost::lexical_cast<std::string>(studies.size()), false);
-    }
-
-    if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) &&
-        !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
-    {
-      return;
-    }
-
-    std::list<std::string> series;
-    GetChildren(series, index, studies);
-    studies.clear();  // This information is useless below
-    
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES,
-                      boost::lexical_cast<std::string>(series.size()), false);
-    }
-
-    if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
-    {
-      return;
-    }
-
-    std::list<std::string> instances;
-    GetChildren(instances, index, series);
-
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES,
-                      boost::lexical_cast<std::string>(instances.size()), false);
-    }
-  }
-
-
-  static void ComputeStudyCounters(DicomMap& result,
-                                   ServerContext& context,
-                                   const std::string& study,
-                                   const DicomMap& query)
-  {
-    ServerIndex& index = context.GetIndex();
-
-    std::list<std::string> series;
-    index.GetChildren(series, study);
-    
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES,
-                      boost::lexical_cast<std::string>(series.size()), false);
-    }
-
-    if (query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY))
-    {
-      std::set<std::string> values;
-
-      for (std::list<std::string>::const_iterator
-             it = series.begin(); it != series.end(); ++it)
-      {
-        DicomMap tags;
-        if (index.GetMainDicomTags(tags, *it, ResourceType_Series, ResourceType_Series))
-        {
-          const DicomValue* value = tags.TestAndGetValue(DICOM_TAG_MODALITY);
-
-          if (value != NULL &&
-              !value->IsNull() &&
-              !value->IsBinary())
-          {
-            values.insert(value->GetContent());
-          }
-        }
-      }
-
-      StoreSetOfStrings(result, DICOM_TAG_MODALITIES_IN_STUDY, values);
-    }
-
-    if (!query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) &&
-        !query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
-    {
-      return;
-    }
-
-    std::list<std::string> instances;
-    GetChildren(instances, index, series);
-
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES,
-                      boost::lexical_cast<std::string>(instances.size()), false);
-    }
-
-    if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
-    {
-      std::set<std::string> values;
-
-      for (std::list<std::string>::const_iterator
-             it = instances.begin(); it != instances.end(); ++it)
-      {
-        std::string value;
-        if (context.LookupOrReconstructMetadata(value, *it, ResourceType_Instance, MetadataType_Instance_SopClassUid))
-        {
-          values.insert(value);
-        }
-      }
-
-      StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
-    }
-  }
-
-
-  static void ComputeSeriesCounters(DicomMap& result,
-                                    ServerIndex& index,
-                                    const std::string& series,
-                                    const DicomMap& query)
-  {
-    std::list<std::string> instances;
-    index.GetChildren(instances, series);
-
-    if (query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES))
-    {
-      result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES,
-                      boost::lexical_cast<std::string>(instances.size()), false);
-    }
-  }
-
-
-  static DicomMap* ComputeCounters(ServerContext& context,
-                                   const std::string& instanceId,
-                                   ResourceType level,
-                                   const DicomMap& query)
-  {
-    switch (level)
-    {
-      case ResourceType_Patient:
-        if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES) &&
-            !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) &&
-            !query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES))
-        {
-          return NULL;
-        }
-
-        break;
-
-      case ResourceType_Study:
-        if (!query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES) &&
-            !query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES) &&
-            !query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY) &&
-            !query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY))
-        {
-          return NULL;
-        }
-
-        break;
-
-      case ResourceType_Series:
-        if (!query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES))
-        {
-          return NULL;
-        }
-
-        break;
-
-      default:
-        return NULL;
-    }
-
-    std::string parent;
-    if (!context.GetIndex().LookupParent(parent, instanceId, level))
-    {
-      throw OrthancException(ErrorCode_UnknownResource);  // The resource was deleted in between
-    }
-
-    std::unique_ptr<DicomMap> result(new DicomMap);
-
-    switch (level)
-    {
-      case ResourceType_Patient:
-        ComputePatientCounters(*result, context.GetIndex(), parent, query);
-        break;
-
-      case ResourceType_Study:
-        ComputeStudyCounters(*result, context, parent, query);
-        break;
-
-      case ResourceType_Series:
-        ComputeSeriesCounters(*result, context.GetIndex(), parent, query);
-        break;
-
-      default:
-        throw OrthancException(ErrorCode_InternalError);
-    }
-
-    return result.release();
-  }
-
-
   static void AddAnswer(DicomFindAnswers& answers,
+                        ServerContext& context,
+                        const std::string& publicId,
+                        const std::string& instanceId,
                         const DicomMap& mainDicomTags,
                         const Json::Value* dicomAsJson,
+                        ResourceType level,
                         const DicomArray& query,
                         const std::list<DicomTag>& sequencesToReturn,
-                        const DicomMap* counters,
                         const std::string& defaultPrivateCreator,
                         const std::map<uint16_t, std::string>& privateCreators,
                         const std::string& retrieveAet)
   {
-    DicomMap match;
+    ExpandedResource resource;
+    std::set<DicomTag> requestedTags;
+    
+    query.GetTags(requestedTags);
 
-    if (dicomAsJson != NULL)
-    {
-      match.FromDicomAsJson(*dicomAsJson);
-    }
-    else
-    {
-      match.Assign(mainDicomTags);
-    }
-    
+    // reuse ExpandResource to get missing tags and computed tags (ModalitiesInStudy ...).  This code is therefore shared between C-Find, tools/find, list-resources and QIDO-RS
+    context.ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson, level, requestedTags, ExpandResourceDbFlags_IncludeMainDicomTags);
+
     DicomMap result;
 
     /**
@@ -330,7 +82,7 @@
       else
       {
         const DicomTag& tag = query.GetElement(i).GetTag();
-        const DicomValue* value = match.TestAndGetValue(tag);
+        const DicomValue* value = resource.tags_.TestAndGetValue(tag);
 
         if (value != NULL &&
             !value->IsNull() &&
@@ -345,15 +97,6 @@
       }
     }
 
-    if (counters != NULL)
-    {
-      DicomArray tmp(*counters);
-      for (size_t i = 0; i < tmp.GetSize(); i++)
-      {
-        result.SetValue(tmp.GetElement(i).GetTag(), tmp.GetElement(i).GetValue().GetContent(), false);
-      }
-    }
-
     if (result.GetSize() == 0 &&
         sequencesToReturn.empty())
     {
@@ -563,10 +306,8 @@
                        const DicomMap& mainDicomTags,
                        const Json::Value* dicomAsJson) ORTHANC_OVERRIDE
     {
-      std::unique_ptr<DicomMap> counters(ComputeCounters(context_, instanceId, level_, query_));
-
-      AddAnswer(answers_, mainDicomTags, dicomAsJson, queryAsArray_, sequencesToReturn_,
-                counters.get(), defaultPrivateCreator_, privateCreators_, retrieveAet_);
+      AddAnswer(answers_, context_, publicId, instanceId, mainDicomTags, dicomAsJson, level_, queryAsArray_, sequencesToReturn_,
+                defaultPrivateCreator_, privateCreators_, retrieveAet_);
     }
   };