Mercurial > hg > orthanc
annotate OrthancServer/OrthancFindRequestHandler.cpp @ 700:0fe6632864b9
ubuntu 13.10
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 07 Feb 2014 21:34:09 +0100 |
parents | 2e67366aab83 |
children | 6a1dbba0cca7 |
rev | line source |
---|---|
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
1 /** |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
2 * Orthanc - A Lightweight, RESTful DICOM Store |
689 | 3 * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
4 * Belgium |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
5 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
6 * This program is free software: you can redistribute it and/or |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
7 * modify it under the terms of the GNU General Public License as |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
8 * published by the Free Software Foundation, either version 3 of the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
9 * License, or (at your option) any later version. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
10 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
11 * In addition, as a special exception, the copyright holders of this |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
12 * program give permission to link the code of its release with the |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
14 * that use the same license as the "OpenSSL" library), and distribute |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
15 * the linked executables. You must obey the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
16 * in all respects for all of the code used other than "OpenSSL". If you |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
17 * modify file(s) with this exception, you may extend this exception to |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
18 * your version of the file(s), but you are not obligated to do so. If |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
19 * you do not wish to do so, delete this exception statement from your |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
20 * version. If you delete this exception statement from all source files |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
21 * in the program, then also delete it here. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
22 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
23 * This program is distributed in the hope that it will be useful, but |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
24 * WITHOUT ANY WARRANTY; without even the implied warranty of |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
26 * General Public License for more details. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
27 * |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
28 * You should have received a copy of the GNU General Public License |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
30 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
31 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
32 #include "OrthancFindRequestHandler.h" |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
33 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
34 #include <glog/logging.h> |
608 | 35 #include <boost/regex.hpp> |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
36 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
37 #include "../Core/DicomFormat/DicomArray.h" |
608 | 38 #include "ServerToolbox.h" |
618 | 39 #include "OrthancInitialization.h" |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
40 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
41 namespace Orthanc |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
42 { |
615 | 43 static bool IsWildcard(const std::string& constraint) |
44 { | |
45 return (constraint.find('-') != std::string::npos || | |
46 constraint.find('*') != std::string::npos || | |
47 constraint.find('\\') != std::string::npos || | |
48 constraint.find('?') != std::string::npos); | |
49 } | |
50 | |
608 | 51 static bool ApplyRangeConstraint(const std::string& value, |
52 const std::string& constraint) | |
53 { | |
610 | 54 size_t separator = constraint.find('-'); |
690
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
55 std::string lower, upper, v; |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
56 Toolbox::ToLowerCase(lower, constraint.substr(0, separator)); |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
57 Toolbox::ToLowerCase(upper, constraint.substr(separator + 1)); |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
58 Toolbox::ToLowerCase(v, value); |
610 | 59 |
60 if (lower.size() == 0 && upper.size() == 0) | |
61 { | |
62 return false; | |
63 } | |
64 | |
65 if (lower.size() == 0) | |
66 { | |
67 return v <= upper; | |
68 } | |
69 | |
70 if (upper.size() == 0) | |
71 { | |
72 return v >= lower; | |
73 } | |
74 | |
75 return (v >= lower && v <= upper); | |
608 | 76 } |
77 | |
78 | |
79 static bool ApplyListConstraint(const std::string& value, | |
80 const std::string& constraint) | |
81 { | |
690
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
82 std::string v1; |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
83 Toolbox::ToLowerCase(v1, value); |
608 | 84 |
85 std::vector<std::string> items; | |
86 Toolbox::TokenizeString(items, constraint, '\\'); | |
87 | |
88 for (size_t i = 0; i < items.size(); i++) | |
89 { | |
690
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
90 std::string lower; |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
91 Toolbox::ToLowerCase(lower, items[i]); |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
92 if (lower == v1) |
608 | 93 { |
94 return true; | |
95 } | |
96 } | |
97 | |
98 return false; | |
99 } | |
100 | |
101 | |
102 static bool Matches(const std::string& value, | |
103 const std::string& constraint) | |
104 { | |
105 // http://www.itk.org/Wiki/DICOM_QueryRetrieve_Explained | |
106 // http://dicomiseasy.blogspot.be/2012/01/dicom-queryretrieve-part-i.html | |
107 | |
108 if (constraint.find('-') != std::string::npos) | |
109 { | |
110 return ApplyRangeConstraint(value, constraint); | |
111 } | |
112 | |
113 if (constraint.find('\\') != std::string::npos) | |
114 { | |
115 return ApplyListConstraint(value, constraint); | |
116 } | |
117 | |
118 if (constraint.find('*') != std::string::npos || | |
119 constraint.find('?') != std::string::npos) | |
120 { | |
121 // TODO - Cache the constructed regular expression | |
122 boost::regex pattern(Toolbox::WildcardToRegularExpression(constraint), | |
123 boost::regex::icase /* case insensitive search */); | |
124 return boost::regex_match(value, pattern); | |
125 } | |
126 else | |
127 { | |
690
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
128 std::string v, c; |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
129 Toolbox::ToLowerCase(v, value); |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
130 Toolbox::ToLowerCase(c, constraint); |
2e67366aab83
case-insensitive matching of Application Entity Titles
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
131 return v == c; |
608 | 132 } |
133 } | |
134 | |
135 | |
136 static bool LookupOneInstance(std::string& result, | |
137 ServerIndex& index, | |
138 const std::string& id, | |
139 ResourceType type) | |
140 { | |
141 if (type == ResourceType_Instance) | |
142 { | |
143 result = id; | |
144 return true; | |
145 } | |
146 | |
147 std::string childId; | |
148 | |
149 { | |
150 std::list<std::string> children; | |
151 index.GetChildInstances(children, id); | |
152 | |
656 | 153 if (children.empty()) |
608 | 154 { |
155 return false; | |
156 } | |
157 | |
158 childId = children.front(); | |
159 } | |
160 | |
161 return LookupOneInstance(result, index, childId, GetChildResourceType(type)); | |
162 } | |
163 | |
164 | |
165 static bool Matches(const Json::Value& resource, | |
166 const DicomArray& query) | |
167 { | |
168 for (size_t i = 0; i < query.GetSize(); i++) | |
169 { | |
170 if (query.GetElement(i).GetValue().IsNull() || | |
171 query.GetElement(i).GetTag() == DICOM_TAG_QUERY_RETRIEVE_LEVEL || | |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
172 query.GetElement(i).GetTag() == DICOM_TAG_SPECIFIC_CHARACTER_SET || |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
173 query.GetElement(i).GetTag() == DICOM_TAG_MODALITIES_IN_STUDY) |
608 | 174 { |
175 continue; | |
176 } | |
177 | |
178 std::string tag = query.GetElement(i).GetTag().Format(); | |
179 std::string value; | |
180 if (resource.isMember(tag)) | |
181 { | |
182 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
183 } | |
184 | |
185 if (!Matches(value, query.GetElement(i).GetValue().AsString())) | |
186 { | |
187 return false; | |
188 } | |
189 } | |
190 | |
191 return true; | |
192 } | |
193 | |
194 | |
195 static void AddAnswer(DicomFindAnswers& answers, | |
196 const Json::Value& resource, | |
197 const DicomArray& query) | |
198 { | |
199 DicomMap result; | |
200 | |
201 for (size_t i = 0; i < query.GetSize(); i++) | |
202 { | |
203 if (query.GetElement(i).GetTag() != DICOM_TAG_QUERY_RETRIEVE_LEVEL && | |
204 query.GetElement(i).GetTag() != DICOM_TAG_SPECIFIC_CHARACTER_SET) | |
205 { | |
206 std::string tag = query.GetElement(i).GetTag().Format(); | |
207 std::string value; | |
208 if (resource.isMember(tag)) | |
209 { | |
210 value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); | |
211 result.SetValue(query.GetElement(i).GetTag(), value); | |
212 } | |
213 } | |
214 } | |
215 | |
216 answers.Add(result); | |
217 } | |
218 | |
219 | |
615 | 220 static bool ApplyModalitiesInStudyFilter(std::list<std::string>& filteredStudies, |
221 const std::list<std::string>& studies, | |
612 | 222 const DicomMap& input, |
223 ServerIndex& index) | |
224 { | |
615 | 225 filteredStudies.clear(); |
612 | 226 |
227 const DicomValue& v = input.GetValue(DICOM_TAG_MODALITIES_IN_STUDY); | |
228 if (v.IsNull()) | |
229 { | |
230 return false; | |
231 } | |
232 | |
233 // Move the allowed modalities into a "std::set" | |
234 std::vector<std::string> tmp; | |
235 Toolbox::TokenizeString(tmp, v.AsString(), '\\'); | |
236 | |
237 std::set<std::string> modalities; | |
238 for (size_t i = 0; i < tmp.size(); i++) | |
239 { | |
240 modalities.insert(tmp[i]); | |
241 } | |
242 | |
243 // Loop over the studies | |
615 | 244 for (std::list<std::string>::const_iterator |
656 | 245 it = studies.begin(); it != studies.end(); ++it) |
612 | 246 { |
247 try | |
248 { | |
249 // We are considering a single study. Check whether one of | |
250 // its child series matches one of the modalities. | |
251 Json::Value study; | |
615 | 252 if (index.LookupResource(study, *it, ResourceType_Study)) |
612 | 253 { |
254 // Loop over the series of the considered study. | |
255 for (Json::Value::ArrayIndex j = 0; j < study["Series"].size(); j++) // (*) | |
256 { | |
257 Json::Value series; | |
258 if (index.LookupResource(series, study["Series"][j].asString(), ResourceType_Series)) | |
259 { | |
260 // Get the modality of this series | |
261 if (series["MainDicomTags"].isMember("Modality")) | |
262 { | |
263 std::string modality = series["MainDicomTags"]["Modality"].asString(); | |
264 if (modalities.find(modality) != modalities.end()) | |
265 { | |
266 // This series of the considered study matches one | |
267 // of the required modalities. Take the study into | |
268 // consideration for future filtering. | |
615 | 269 filteredStudies.push_back(*it); |
612 | 270 |
271 // We have finished considering this study. Break the study loop at (*). | |
272 break; | |
273 } | |
274 } | |
275 } | |
276 } | |
277 } | |
278 } | |
279 catch (OrthancException&) | |
280 { | |
281 // This resource has probably been deleted during the find request | |
282 } | |
283 } | |
284 | |
285 return true; | |
286 } | |
287 | |
288 | |
615 | 289 static bool LookupCandidateResourcesInternal(/* out */ std::list<std::string>& resources, |
290 /* in */ ServerIndex& index, | |
291 /* in */ ResourceType level, | |
292 /* in */ const DicomMap& query, | |
293 /* in */ DicomTag tag) | |
294 { | |
295 if (query.HasTag(tag)) | |
296 { | |
297 const DicomValue& value = query.GetValue(tag); | |
298 if (!value.IsNull()) | |
299 { | |
300 std::string str = query.GetValue(tag).AsString(); | |
301 if (!IsWildcard(str)) | |
302 { | |
303 index.LookupTagValue(resources, tag, str/*, level*/); | |
304 return true; | |
305 } | |
306 } | |
307 } | |
308 | |
309 return false; | |
310 } | |
311 | |
312 | |
313 static void LookupCandidateResources(/* out */ std::list<std::string>& resources, | |
314 /* in */ ServerIndex& index, | |
315 /* in */ ResourceType level, | |
665 | 316 /* in */ const DicomMap& query, |
317 /* in */ ModalityManufacturer manufacturer) | |
615 | 318 { |
319 // TODO : Speed up using full querying against the MainDicomTags. | |
320 | |
321 resources.clear(); | |
322 | |
323 bool done = false; | |
324 | |
325 switch (level) | |
326 { | |
327 case ResourceType_Patient: | |
328 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_PATIENT_ID); | |
329 break; | |
330 | |
331 case ResourceType_Study: | |
332 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_STUDY_INSTANCE_UID); | |
333 break; | |
334 | |
335 case ResourceType_Series: | |
336 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SERIES_INSTANCE_UID); | |
337 break; | |
338 | |
339 case ResourceType_Instance: | |
665 | 340 if (manufacturer == ModalityManufacturer_MedInria) |
341 { | |
342 std::list<std::string> series; | |
343 | |
344 if (LookupCandidateResourcesInternal(series, index, ResourceType_Series, query, DICOM_TAG_SERIES_INSTANCE_UID) && | |
345 series.size() == 1) | |
346 { | |
347 index.GetChildInstances(resources, series.front()); | |
348 done = true; | |
349 } | |
350 } | |
351 else | |
352 { | |
353 done = LookupCandidateResourcesInternal(resources, index, level, query, DICOM_TAG_SOP_INSTANCE_UID); | |
354 } | |
355 | |
615 | 356 break; |
357 | |
358 default: | |
359 break; | |
360 } | |
361 | |
362 if (!done) | |
363 { | |
364 Json::Value allResources; | |
365 index.GetAllUuids(allResources, level); | |
366 assert(allResources.type() == Json::arrayValue); | |
367 | |
368 for (Json::Value::ArrayIndex i = 0; i < allResources.size(); i++) | |
369 { | |
370 resources.push_back(allResources[i].asString()); | |
371 } | |
372 } | |
373 } | |
374 | |
375 | |
618 | 376 void OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, |
665 | 377 const DicomMap& input, |
378 const std::string& callingAETitle) | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
379 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
380 /** |
665 | 381 * Retrieve the manufacturer of this modality. |
382 **/ | |
383 | |
384 ModalityManufacturer manufacturer; | |
385 | |
386 { | |
387 std::string symbolicName, address; | |
388 int port; | |
389 | |
390 if (!LookupDicomModalityUsingAETitle(callingAETitle, symbolicName, address, port, manufacturer)) | |
391 { | |
392 throw OrthancException("Unknown modality"); | |
393 } | |
394 } | |
395 | |
396 | |
397 /** | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
398 * Retrieve the query level. |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
399 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
400 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
401 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
402 if (levelTmp == NULL) |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
403 { |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
404 throw OrthancException(ErrorCode_BadRequest); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
405 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
406 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
407 ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
408 |
665 | 409 switch (manufacturer) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
410 { |
665 | 411 case ModalityManufacturer_MedInria: |
412 // MedInria makes FIND requests at the instance level before starting MOVE | |
413 break; | |
414 | |
415 default: | |
416 if (level != ResourceType_Patient && | |
417 level != ResourceType_Study && | |
418 level != ResourceType_Series) | |
419 { | |
420 throw OrthancException(ErrorCode_NotImplemented); | |
421 } | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
422 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
423 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
424 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
425 /** |
615 | 426 * Retrieve the candidate resources for this query level. Whenever |
427 * possible, we avoid returning ALL the resources for this query | |
428 * level, as it would imply reading the JSON file on the harddisk | |
429 * for each of them. | |
608 | 430 **/ |
431 | |
615 | 432 std::list<std::string> resources; |
665 | 433 LookupCandidateResources(resources, context_.GetIndex(), level, input, manufacturer); |
608 | 434 |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
435 |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
436 /** |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
437 * Apply filtering on modalities for studies, if asked (this is an |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
438 * extension to standard DICOM) |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
439 * http://www.medicalconnections.co.uk/kb/Filtering_on_and_Retrieving_the_Modality_in_a_C_FIND |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
440 **/ |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
441 |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
442 if (level == ResourceType_Study && |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
443 input.HasTag(DICOM_TAG_MODALITIES_IN_STUDY)) |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
444 { |
615 | 445 std::list<std::string> filtered; |
612 | 446 if (ApplyModalitiesInStudyFilter(filtered, resources, input, context_.GetIndex())) |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
447 { |
612 | 448 resources = filtered; |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
449 } |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
450 } |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
451 |
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
452 |
608 | 453 /** |
454 * Loop over all the resources for this query level. | |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
455 **/ |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
456 |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
457 DicomArray query(input); |
615 | 458 for (std::list<std::string>::const_iterator |
656 | 459 resource = resources.begin(); resource != resources.end(); ++resource) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
460 { |
608 | 461 try |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
462 { |
608 | 463 std::string instance; |
615 | 464 if (LookupOneInstance(instance, context_.GetIndex(), *resource, level)) |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
465 { |
615 | 466 Json::Value info; |
467 context_.ReadJson(info, instance); | |
608 | 468 |
615 | 469 if (Matches(info, query)) |
608 | 470 { |
615 | 471 AddAnswer(answers, info, query); |
608 | 472 } |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
473 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
474 } |
608 | 475 catch (OrthancException&) |
476 { | |
611
9924aec1d694
filtering on modalities
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
610
diff
changeset
|
477 // This resource has probably been deleted during the find request |
608 | 478 } |
565
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
479 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
480 } |
c931ac02db82
refactoring of find class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
diff
changeset
|
481 } |
682
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
482 |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
483 |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
484 |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
485 /** |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
486 * TODO : Case-insensitive match for PN value representation (Patient |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
487 * Name). Case-senstive match for all the other value representations. |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
488 * |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
489 * Reference: DICOM PS 3.4 |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
490 * - C.2.2.2.1 ("Single Value Matching") |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
491 * - C.2.2.2.4 ("Wild Card Matching") |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
492 * http://medical.nema.org/Dicom/2011/11_04pu.pdf ( |
efc4928be6fb
Recover pixel data for more transfer syntaxes (notably JPEG)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
665
diff
changeset
|
493 **/ |