comparison OrthancServer/OrthancFindRequestHandler.cpp @ 1785:c131566b8252 dcmtk-3.6.1

integration mainline->dcmtk-3.6.1
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 18 Nov 2015 10:16:21 +0100
parents e268412adcf1
children 4f01c9d73f02
comparison
equal deleted inserted replaced
1639:1b82bb0446d2 1785:c131566b8252
31 31
32 32
33 #include "PrecompiledHeadersServer.h" 33 #include "PrecompiledHeadersServer.h"
34 #include "OrthancFindRequestHandler.h" 34 #include "OrthancFindRequestHandler.h"
35 35
36 #include "../Core/DicomFormat/DicomArray.h"
36 #include "../Core/Logging.h" 37 #include "../Core/Logging.h"
37 #include "../Core/DicomFormat/DicomArray.h" 38 #include "FromDcmtkBridge.h"
39 #include "OrthancInitialization.h"
40 #include "Search/LookupResource.h"
38 #include "ServerToolbox.h" 41 #include "ServerToolbox.h"
39 #include "OrthancInitialization.h"
40 #include "FromDcmtkBridge.h"
41
42 #include "ResourceFinder.h"
43 #include "DicomFindQuery.h"
44 42
45 #include <boost/regex.hpp> 43 #include <boost/regex.hpp>
46 44
47 45
48 namespace Orthanc 46 namespace Orthanc
88 answers.Add(result); 86 answers.Add(result);
89 } 87 }
90 } 88 }
91 89
92 90
93 namespace
94 {
95 class CFindQuery : public DicomFindQuery
96 {
97 private:
98 DicomFindAnswers& answers_;
99 ServerIndex& index_;
100 const DicomArray& query_;
101 bool hasModalitiesInStudy_;
102 std::set<std::string> modalitiesInStudy_;
103
104 public:
105 CFindQuery(DicomFindAnswers& answers,
106 ServerIndex& index,
107 const DicomArray& query) :
108 answers_(answers),
109 index_(index),
110 query_(query),
111 hasModalitiesInStudy_(false)
112 {
113 }
114
115 void SetModalitiesInStudy(const std::string& value)
116 {
117 hasModalitiesInStudy_ = true;
118
119 std::vector<std::string> tmp;
120 Toolbox::TokenizeString(tmp, value, '\\');
121
122 for (size_t i = 0; i < tmp.size(); i++)
123 {
124 modalitiesInStudy_.insert(tmp[i]);
125 }
126 }
127
128 virtual bool HasMainDicomTagsFilter(ResourceType level) const
129 {
130 if (DicomFindQuery::HasMainDicomTagsFilter(level))
131 {
132 return true;
133 }
134
135 return (level == ResourceType_Study &&
136 hasModalitiesInStudy_);
137 }
138
139 virtual bool FilterMainDicomTags(const std::string& resourceId,
140 ResourceType level,
141 const DicomMap& mainTags) const
142 {
143 if (!DicomFindQuery::FilterMainDicomTags(resourceId, level, mainTags))
144 {
145 return false;
146 }
147
148 if (level != ResourceType_Study ||
149 !hasModalitiesInStudy_)
150 {
151 return true;
152 }
153
154 try
155 {
156 // We are considering a single study, and the
157 // "MODALITIES_IN_STUDY" tag is set in the C-Find. Check
158 // whether one of its child series matches one of the
159 // modalities.
160
161 Json::Value study;
162 if (index_.LookupResource(study, resourceId, ResourceType_Study))
163 {
164 // Loop over the series of the considered study.
165 for (Json::Value::ArrayIndex j = 0; j < study["Series"].size(); j++)
166 {
167 Json::Value series;
168 if (index_.LookupResource(series, study["Series"][j].asString(), ResourceType_Series))
169 {
170 // Get the modality of this series
171 if (series["MainDicomTags"].isMember("Modality"))
172 {
173 std::string modality = series["MainDicomTags"]["Modality"].asString();
174 if (modalitiesInStudy_.find(modality) != modalitiesInStudy_.end())
175 {
176 // This series of the considered study matches one
177 // of the required modalities. Take the study into
178 // consideration for future filtering.
179 return true;
180 }
181 }
182 }
183 }
184 }
185 }
186 catch (OrthancException&)
187 {
188 // This resource has probably been deleted during the find request
189 }
190
191 return false;
192 }
193
194 virtual bool HasInstanceFilter() const
195 {
196 return true;
197 }
198
199 virtual bool FilterInstance(const std::string& instanceId,
200 const Json::Value& content) const
201 {
202 bool ok = DicomFindQuery::FilterInstance(instanceId, content);
203
204 if (ok)
205 {
206 // Add this resource to the answers
207 AddAnswer(answers_, content, query_);
208 }
209
210 return ok;
211 }
212 };
213 }
214
215
216
217 bool OrthancFindRequestHandler::Handle(DicomFindAnswers& answers, 91 bool OrthancFindRequestHandler::Handle(DicomFindAnswers& answers,
218 const DicomMap& input, 92 const DicomMap& input,
219 const std::string& remoteIp, 93 const std::string& remoteIp,
220 const std::string& remoteAet) 94 const std::string& remoteAet)
221 { 95 {
238 /** 112 /**
239 * Retrieve the query level. 113 * Retrieve the query level.
240 **/ 114 **/
241 115
242 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL); 116 const DicomValue* levelTmp = input.TestAndGetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL);
243 if (levelTmp == NULL) 117 if (levelTmp == NULL ||
118 levelTmp->IsNull() ||
119 levelTmp->IsBinary())
244 { 120 {
245 throw OrthancException(ErrorCode_BadRequest); 121 throw OrthancException(ErrorCode_BadRequest);
246 } 122 }
247 123
248 ResourceType level = StringToResourceType(levelTmp->AsString().c_str()); 124 ResourceType level = StringToResourceType(levelTmp->GetContent().c_str());
249 125
250 if (level != ResourceType_Patient && 126 if (level != ResourceType_Patient &&
251 level != ResourceType_Study && 127 level != ResourceType_Study &&
252 level != ResourceType_Series && 128 level != ResourceType_Series &&
253 level != ResourceType_Instance) 129 level != ResourceType_Instance)
263 { 139 {
264 if (!query.GetElement(i).GetValue().IsNull()) 140 if (!query.GetElement(i).GetValue().IsNull())
265 { 141 {
266 LOG(INFO) << " " << query.GetElement(i).GetTag() 142 LOG(INFO) << " " << query.GetElement(i).GetTag()
267 << " " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag()) 143 << " " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
268 << " = " << query.GetElement(i).GetValue().AsString(); 144 << " = " << query.GetElement(i).GetValue().GetContent();
269 } 145 }
270 } 146 }
271 147
272 148
273 /** 149 /**
274 * Build up the query object. 150 * Build up the query object.
275 **/ 151 **/
276 152
277 CFindQuery findQuery(answers, context_.GetIndex(), query); 153 LookupResource finder(level);
278 findQuery.SetLevel(level); 154
279
280 for (size_t i = 0; i < query.GetSize(); i++) 155 for (size_t i = 0; i < query.GetSize(); i++)
281 { 156 {
282 const DicomTag tag = query.GetElement(i).GetTag(); 157 const DicomTag tag = query.GetElement(i).GetTag();
283 158
284 if (query.GetElement(i).GetValue().IsNull() || 159 if (query.GetElement(i).GetValue().IsNull() ||
286 tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) 161 tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
287 { 162 {
288 continue; 163 continue;
289 } 164 }
290 165
291 std::string value = query.GetElement(i).GetValue().AsString(); 166 std::string value = query.GetElement(i).GetValue().GetContent();
292 if (value.size() == 0) 167 if (value.size() == 0)
293 { 168 {
294 // An empty string corresponds to a "*" wildcard constraint, so we ignore it 169 // An empty string corresponds to a "*" wildcard constraint, so we ignore it
295 continue; 170 continue;
296 } 171 }
297 172
298 if (tag == DICOM_TAG_MODALITIES_IN_STUDY) 173 ValueRepresentation vr = FromDcmtkBridge::GetValueRepresentation(tag);
299 { 174
300 findQuery.SetModalitiesInStudy(value); 175 // DICOM specifies that searches must be case sensitive, except
301 } 176 // for tags with a PN value representation
302 else 177 bool sensitive = true;
303 { 178 if (vr == ValueRepresentation_PatientName)
304 findQuery.SetConstraint(tag, value, caseSensitivePN); 179 {
305 } 180 sensitive = caseSensitivePN;
181 }
182
183 finder.AddDicomConstraint(tag, value, sensitive);
306 } 184 }
307 185
308 186
309 /** 187 /**
310 * Run the query. 188 * Run the query.
311 **/ 189 **/
312 190
313 ResourceFinder finder(context_); 191 size_t maxResults = (level == ResourceType_Instance) ? maxInstances_ : maxResults_;
314 192
315 switch (level) 193 std::vector<std::string> resources, instances;
316 { 194 context_.GetIndex().FindCandidates(resources, instances, finder);
317 case ResourceType_Patient: 195
318 case ResourceType_Study: 196 assert(resources.size() == instances.size());
319 case ResourceType_Series: 197 bool finished = true;
320 finder.SetMaxResults(maxResults_); 198
321 break; 199 for (size_t i = 0; i < instances.size(); i++)
322 200 {
323 case ResourceType_Instance: 201 Json::Value dicom;
324 finder.SetMaxResults(maxInstances_); 202 context_.ReadJson(dicom, instances[i]);
325 break; 203
326 204 if (finder.IsMatch(dicom))
327 default: 205 {
328 throw OrthancException(ErrorCode_InternalError); 206 if (maxResults != 0 &&
329 } 207 answers.GetSize() >= maxResults)
330 208 {
331 std::list<std::string> tmp; 209 finished = false;
332 bool finished = finder.Apply(tmp, findQuery); 210 break;
333 211 }
334 LOG(INFO) << "Number of matching resources: " << tmp.size(); 212 else
213 {
214 AddAnswer(answers, dicom, query);
215 }
216 }
217 }
218
219 LOG(INFO) << "Number of matching resources: " << answers.GetSize();
335 220
336 return finished; 221 return finished;
337 } 222 }
338 } 223 }