Mercurial > hg > orthanc
comparison OrthancServer/Sources/OrthancFindRequestHandler.cpp @ 5704:0c2f0d72d143 find-refactoring-clean
only keep experimental versions
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 12 Jul 2024 17:17:31 +0200 |
parents | 359a8adb3802 |
children | 58c549b881ae |
comparison
equal
deleted
inserted
replaced
5703:12cb6b5c43f0 | 5704:0c2f0d72d143 |
---|---|
80 } | 80 } |
81 } | 81 } |
82 } | 82 } |
83 | 83 |
84 | 84 |
85 static void AddAnswer(DicomFindAnswers& answers, | |
86 ServerContext& context, | |
87 const std::string& publicId, | |
88 const std::string& instanceId, | |
89 const DicomMap& mainDicomTags, | |
90 const Json::Value* dicomAsJson, | |
91 ResourceType level, | |
92 const DicomArray& query, | |
93 const std::list<DicomTag>& sequencesToReturn, | |
94 const std::string& defaultPrivateCreator, | |
95 const std::map<uint16_t, std::string>& privateCreators, | |
96 const std::string& retrieveAet, | |
97 bool allowStorageAccess) | |
98 { | |
99 ExpandedResource resource; | |
100 std::set<DicomTag> requestedTags; | |
101 | |
102 query.GetTags(requestedTags); | |
103 requestedTags.erase(DICOM_TAG_QUERY_RETRIEVE_LEVEL); // this is not part of the answer | |
104 | |
105 // 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 | |
106 context.ExpandResource(resource, publicId, mainDicomTags, instanceId, dicomAsJson, | |
107 level, requestedTags, ExpandResourceFlags_IncludeMainDicomTags, allowStorageAccess); | |
108 | |
109 DicomMap result; | |
110 | |
111 /** | |
112 * Add the mandatory "Retrieve AE Title (0008,0054)" tag, which was missing in Orthanc <= 1.7.2. | |
113 * http://dicom.nema.org/medical/dicom/current/output/html/part04.html#sect_C.4.1.1.3.2 | |
114 * https://groups.google.com/g/orthanc-users/c/-7zNTKR_PMU/m/kfjwzEVNAgAJ | |
115 **/ | |
116 result.SetValue(DICOM_TAG_RETRIEVE_AE_TITLE, retrieveAet, false /* not binary */); | |
117 | |
118 for (size_t i = 0; i < query.GetSize(); i++) | |
119 { | |
120 if (query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL) | |
121 { | |
122 // Fix issue 30 on Google Code (QR response missing "Query/Retrieve Level" (008,0052)) | |
123 result.SetValue(query.GetElement(i).GetTag(), query.GetElement(i).GetValue()); | |
124 } | |
125 else if (query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
126 { | |
127 // Do not include the encoding, this is handled by class ParsedDicomFile | |
128 } | |
129 else | |
130 { | |
131 const DicomTag& tag = query.GetElement(i).GetTag(); | |
132 const DicomValue* value = resource.GetMainDicomTags().TestAndGetValue(tag); | |
133 | |
134 if (value != NULL && | |
135 !value->IsNull() && | |
136 !value->IsBinary()) | |
137 { | |
138 result.SetValue(tag, value->GetContent(), false); | |
139 } | |
140 else | |
141 { | |
142 result.SetValue(tag, "", false); | |
143 } | |
144 } | |
145 } | |
146 | |
147 if (result.GetSize() == 0 && | |
148 sequencesToReturn.empty()) | |
149 { | |
150 CLOG(WARNING, DICOM) << "The C-FIND request does not return any DICOM tag"; | |
151 } | |
152 else if (sequencesToReturn.empty()) | |
153 { | |
154 answers.Add(result); | |
155 } | |
156 else if (dicomAsJson == NULL) | |
157 { | |
158 CLOG(WARNING, DICOM) << "C-FIND query requesting a sequence, but reading JSON from disk is disabled"; | |
159 answers.Add(result); | |
160 } | |
161 else | |
162 { | |
163 ParsedDicomFile dicom(result, GetDefaultDicomEncoding(), | |
164 true /* be permissive, cf. issue #136 */, defaultPrivateCreator, privateCreators); | |
165 | |
166 for (std::list<DicomTag>::const_iterator tag = sequencesToReturn.begin(); | |
167 tag != sequencesToReturn.end(); ++tag) | |
168 { | |
169 assert(dicomAsJson != NULL); | |
170 const Json::Value& source = (*dicomAsJson) [tag->Format()]; | |
171 | |
172 CopySequence(dicom, *tag, source, defaultPrivateCreator, privateCreators); | |
173 } | |
174 | |
175 answers.Add(dicom); | |
176 } | |
177 } | |
178 | |
179 | |
180 | |
181 bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, | 85 bool OrthancFindRequestHandler::FilterQueryTag(std::string& value /* can be modified */, |
182 ResourceType level, | 86 ResourceType level, |
183 const DicomTag& tag, | 87 const DicomTag& tag, |
184 ModalityManufacturer manufacturer) | 88 ModalityManufacturer manufacturer) |
185 { | 89 { |
244 context_(context), | 148 context_(context), |
245 maxResults_(0), | 149 maxResults_(0), |
246 maxInstances_(0) | 150 maxInstances_(0) |
247 { | 151 { |
248 } | 152 } |
249 | |
250 | |
251 class OrthancFindRequestHandler::LookupVisitor : public ServerContext::ILookupVisitor | |
252 { | |
253 private: | |
254 DicomFindAnswers& answers_; | |
255 ServerContext& context_; | |
256 ResourceType level_; | |
257 const DicomMap& query_; | |
258 DicomArray queryAsArray_; | |
259 const std::list<DicomTag>& sequencesToReturn_; | |
260 std::string defaultPrivateCreator_; // the private creator to use if the group is not defined in the query itself | |
261 const std::map<uint16_t, std::string>& privateCreators_; // the private creators defined in the query itself | |
262 std::string retrieveAet_; | |
263 FindStorageAccessMode findStorageAccessMode_; | |
264 | |
265 public: | |
266 LookupVisitor(DicomFindAnswers& answers, | |
267 ServerContext& context, | |
268 ResourceType level, | |
269 const DicomMap& query, | |
270 const std::list<DicomTag>& sequencesToReturn, | |
271 const std::map<uint16_t, std::string>& privateCreators, | |
272 FindStorageAccessMode findStorageAccessMode) : | |
273 answers_(answers), | |
274 context_(context), | |
275 level_(level), | |
276 query_(query), | |
277 queryAsArray_(query), | |
278 sequencesToReturn_(sequencesToReturn), | |
279 privateCreators_(privateCreators), | |
280 findStorageAccessMode_(findStorageAccessMode) | |
281 { | |
282 answers_.SetComplete(false); | |
283 | |
284 { | |
285 OrthancConfiguration::ReaderLock lock; | |
286 defaultPrivateCreator_ = lock.GetConfiguration().GetDefaultPrivateCreator(); | |
287 retrieveAet_ = lock.GetConfiguration().GetOrthancAET(); | |
288 } | |
289 } | |
290 | |
291 virtual bool IsDicomAsJsonNeeded() const ORTHANC_OVERRIDE | |
292 { | |
293 // Ask the "DICOM-as-JSON" attachment only if sequences are to | |
294 // be returned OR if "query_" contains non-main DICOM tags! | |
295 | |
296 DicomMap withoutSpecialTags; | |
297 withoutSpecialTags.Assign(query_); | |
298 | |
299 // Check out "ComputeCounters()" | |
300 withoutSpecialTags.Remove(DICOM_TAG_MODALITIES_IN_STUDY); | |
301 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES); | |
302 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES); | |
303 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES); | |
304 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES); | |
305 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES); | |
306 withoutSpecialTags.Remove(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES); | |
307 withoutSpecialTags.Remove(DICOM_TAG_SOP_CLASSES_IN_STUDY); | |
308 | |
309 // Check out "AddAnswer()" | |
310 withoutSpecialTags.Remove(DICOM_TAG_SPECIFIC_CHARACTER_SET); | |
311 withoutSpecialTags.Remove(DICOM_TAG_QUERY_RETRIEVE_LEVEL); | |
312 | |
313 return (!sequencesToReturn_.empty() || | |
314 !withoutSpecialTags.HasOnlyMainDicomTags()); | |
315 } | |
316 | |
317 virtual void MarkAsComplete() ORTHANC_OVERRIDE | |
318 { | |
319 answers_.SetComplete(true); | |
320 } | |
321 | |
322 virtual void Visit(const std::string& publicId, | |
323 const std::string& instanceId, | |
324 const DicomMap& mainDicomTags, | |
325 const Json::Value* dicomAsJson) ORTHANC_OVERRIDE | |
326 { | |
327 AddAnswer(answers_, context_, publicId, instanceId, mainDicomTags, dicomAsJson, level_, queryAsArray_, sequencesToReturn_, | |
328 defaultPrivateCreator_, privateCreators_, retrieveAet_, IsStorageAccessAllowedForAnswers(findStorageAccessMode_)); | |
329 } | |
330 }; | |
331 | 153 |
332 | 154 |
333 namespace | 155 namespace |
334 { | 156 { |
335 class LookupVisitorV2 : public ResourceFinder::IVisitor | 157 class LookupVisitorV2 : public ResourceFinder::IVisitor |
620 | 442 |
621 /** | 443 /** |
622 * Run the query. | 444 * Run the query. |
623 **/ | 445 **/ |
624 | 446 |
625 size_t limit = (level == ResourceType_Instance) ? maxInstances_ : maxResults_; | 447 ResourceFinder finder(level, false /* don't expand */); |
626 | 448 finder.SetDatabaseLookup(lookup); |
627 | 449 finder.AddRequestedTags(requestedTags); |
628 if (true) | 450 |
629 { | 451 LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); |
630 /** | 452 finder.Execute(visitor, context_); |
631 * EXPERIMENTAL VERSION | |
632 **/ | |
633 | |
634 ResourceFinder finder(level, false /* don't expand */); | |
635 finder.SetDatabaseLookup(lookup); | |
636 finder.AddRequestedTags(requestedTags); | |
637 | |
638 LookupVisitorV2 visitor(answers, *filteredInput, sequencesToReturn, privateCreators); | |
639 finder.Execute(visitor, context_); | |
640 } | |
641 else | |
642 { | |
643 /** | |
644 * VERSION IN ORTHANC <= 1.12.4 | |
645 **/ | |
646 | |
647 LookupVisitor visitor(answers, context_, level, *filteredInput, sequencesToReturn, privateCreators, context_.GetFindStorageAccessMode()); | |
648 context_.Apply(visitor, lookup, level, 0 /* "since" is not relevant to C-FIND */, limit); | |
649 } | |
650 } | 453 } |
651 | 454 |
652 | 455 |
653 void OrthancFindRequestHandler::FormatOrigin(Json::Value& origin, | 456 void OrthancFindRequestHandler::FormatOrigin(Json::Value& origin, |
654 const std::string& remoteIp, | 457 const std::string& remoteIp, |