comparison OrthancServer/ResourceFinder.cpp @ 1360:0649c5aef34a

DicomFindQuery
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 15 May 2015 15:34:32 +0200
parents 4378a6636187
children 94ffb597d297
comparison
equal deleted inserted replaced
1359:4378a6636187 1360:0649c5aef34a
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. 29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/ 30 **/
31 31
32 32
33 #include "PrecompiledHeadersServer.h" 33 #include "PrecompiledHeadersServer.h"
34 #include "BaseResourceFinder.h" 34 #include "ResourceFinder.h"
35 35
36 #include "FromDcmtkBridge.h" 36 #include "FromDcmtkBridge.h"
37 #include "ServerContext.h" 37 #include "ServerContext.h"
38 38
39 #include <glog/logging.h> 39 #include <glog/logging.h>
40 #include <boost/algorithm/string/predicate.hpp> 40 #include <boost/algorithm/string/predicate.hpp>
41 41
42 namespace Orthanc 42 namespace Orthanc
43 { 43 {
44 class BaseResourceFinder::CandidateResources 44 class ResourceFinder::CandidateResources
45 { 45 {
46 private: 46 private:
47 typedef std::map<DicomTag, std::string> Query; 47 typedef std::map<DicomTag, std::string> Query;
48 48
49 BaseResourceFinder& finder_; 49 ResourceFinder& finder_;
50 ServerIndex& index_; 50 ServerIndex& index_;
51 ResourceType level_; 51 ResourceType level_;
52 bool isFilterApplied_; 52 bool isFilterApplied_;
53 std::set<std::string> filtered_; 53 std::set<std::string> filtered_;
54 54
62 target.insert(*it); 62 target.insert(*it);
63 } 63 }
64 } 64 }
65 65
66 66
67 void RestrictIdentifier(const DicomTag& tag, 67 public:
68 const std::string& value) 68 CandidateResources(ResourceFinder& finder) :
69 finder_(finder),
70 index_(finder.context_.GetIndex()),
71 level_(ResourceType_Patient),
72 isFilterApplied_(false)
73 {
74 }
75
76 ResourceType GetLevel() const
77 {
78 return level_;
79 }
80
81 void GoDown()
82 {
83 assert(level_ != ResourceType_Instance);
84
85 if (isFilterApplied_)
86 {
87 std::set<std::string> tmp = filtered_;
88
89 filtered_.clear();
90
91 for (std::set<std::string>::const_iterator
92 it = tmp.begin(); it != tmp.end(); ++it)
93 {
94 std::list<std::string> children;
95 try
96 {
97 index_.GetChildren(children, *it);
98 ListToSet(filtered_, children);
99 }
100 catch (OrthancException&)
101 {
102 // The resource was removed in the meantime
103 }
104 }
105 }
106
107 switch (level_)
108 {
109 case ResourceType_Patient:
110 level_ = ResourceType_Study;
111 break;
112
113 case ResourceType_Study:
114 level_ = ResourceType_Series;
115 break;
116
117 case ResourceType_Series:
118 level_ = ResourceType_Instance;
119 break;
120
121 default:
122 throw OrthancException(ErrorCode_InternalError);
123 }
124 }
125
126
127 void Flatten(std::list<std::string>& resources) const
128 {
129 resources.clear();
130
131 if (isFilterApplied_)
132 {
133 for (std::set<std::string>::const_iterator
134 it = filtered_.begin(); it != filtered_.end(); ++it)
135 {
136 resources.push_back(*it);
137 }
138 }
139 else
140 {
141 index_.GetAllUuids(resources, level_);
142 }
143 }
144
145
146 void RestrictIdentifier(const IQuery& query,
147 const DicomTag& tag)
69 { 148 {
70 assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) || 149 assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
71 (level_ == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) || 150 (level_ == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
72 (level_ == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) || 151 (level_ == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
73 (level_ == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) || 152 (level_ == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
74 (level_ == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID)); 153 (level_ == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
75 154
155 std::string value;
156 if (!query.RestrictIdentifier(value, tag))
157 {
158 return;
159 }
160
76 LOG(INFO) << "Lookup for identifier tag " 161 LOG(INFO) << "Lookup for identifier tag "
77 << FromDcmtkBridge::GetName(tag) << " (value: " << value << ")"; 162 << FromDcmtkBridge::GetName(tag) << " (value: " << value << ")";
78 163
79 std::list<std::string> resources; 164 std::list<std::string> resources;
80 index_.LookupIdentifier(resources, tag, value, level_); 165 index_.LookupIdentifier(resources, tag, value, level_);
103 ListToSet(filtered_, resources); 188 ListToSet(filtered_, resources);
104 } 189 }
105 } 190 }
106 191
107 192
108 public: 193 void RestrictMainDicomTags(const IQuery& query)
109 CandidateResources(BaseResourceFinder& finder) : 194 {
110 finder_(finder), 195 if (!query.HasMainDicomTagsFilter(level_))
111 index_(finder.context_.GetIndex()),
112 level_(ResourceType_Patient),
113 isFilterApplied_(false)
114 {
115 }
116
117 ResourceType GetLevel() const
118 {
119 return level_;
120 }
121
122 void GoDown()
123 {
124 assert(level_ != ResourceType_Instance);
125
126 if (isFilterApplied_)
127 {
128 std::set<std::string> tmp = filtered_;
129
130 filtered_.clear();
131
132 for (std::set<std::string>::const_iterator
133 it = tmp.begin(); it != tmp.end(); ++it)
134 {
135 std::list<std::string> children;
136 try
137 {
138 index_.GetChildren(children, *it);
139 ListToSet(filtered_, children);
140 }
141 catch (OrthancException&)
142 {
143 // The resource was removed in the meantime
144 }
145 }
146 }
147
148 switch (level_)
149 {
150 case ResourceType_Patient:
151 level_ = ResourceType_Study;
152 break;
153
154 case ResourceType_Study:
155 level_ = ResourceType_Series;
156 break;
157
158 case ResourceType_Series:
159 level_ = ResourceType_Instance;
160 break;
161
162 default:
163 throw OrthancException(ErrorCode_InternalError);
164 }
165 }
166
167
168 void Flatten(std::list<std::string>& resources) const
169 {
170 resources.clear();
171
172 if (isFilterApplied_)
173 {
174 for (std::set<std::string>::const_iterator
175 it = filtered_.begin(); it != filtered_.end(); ++it)
176 {
177 resources.push_back(*it);
178 }
179 }
180 else
181 {
182 index_.GetAllUuids(resources, level_);
183 }
184 }
185
186
187 void RestrictIdentifier(const DicomTag& tag)
188 {
189 Identifiers::const_iterator it = finder_.identifiers_.find(tag);
190 if (it != finder_.identifiers_.end())
191 {
192 RestrictIdentifier(it->first, it->second);
193 }
194 }
195
196
197 void RestrictMainDicomTags()
198 {
199 if (finder_.mainTagsFilter_ == NULL)
200 { 196 {
201 return; 197 return;
202 } 198 }
203 199
204 std::list<std::string> resources; 200 std::list<std::string> resources;
211 it = resources.begin(); it != resources.end(); it++) 207 it = resources.begin(); it != resources.end(); it++)
212 { 208 {
213 DicomMap mainTags; 209 DicomMap mainTags;
214 if (index_.GetMainDicomTags(mainTags, *it, level_)) 210 if (index_.GetMainDicomTags(mainTags, *it, level_))
215 { 211 {
216 if (finder_.mainTagsFilter_->Apply(mainTags, level_)) 212 if (query.FilterMainDicomTags(mainTags, level_))
217 { 213 {
218 filtered_.insert(*it); 214 filtered_.insert(*it);
219 } 215 }
220 } 216 }
221 } 217 }
222 } 218 }
223 }; 219 };
224 220
225 221
226 BaseResourceFinder::BaseResourceFinder(ServerContext& context) : 222 ResourceFinder::ResourceFinder(ServerContext& context) :
227 context_(context), 223 context_(context),
228 level_(ResourceType_Patient),
229 maxResults_(0) 224 maxResults_(0)
230 { 225 {
231 } 226 }
232 227
233 228
234 void BaseResourceFinder::ApplyAtLevel(CandidateResources& candidates, 229 void ResourceFinder::ApplyAtLevel(CandidateResources& candidates,
235 ResourceType level) 230 const IQuery& query,
231 ResourceType level)
236 { 232 {
237 if (level != ResourceType_Patient) 233 if (level != ResourceType_Patient)
238 { 234 {
239 candidates.GoDown(); 235 candidates.GoDown();
240 } 236 }
241 237
242 switch (level_) 238 switch (level)
243 { 239 {
244 case ResourceType_Patient: 240 case ResourceType_Patient:
245 { 241 {
246 candidates.RestrictIdentifier(DICOM_TAG_PATIENT_ID); 242 candidates.RestrictIdentifier(query, DICOM_TAG_PATIENT_ID);
247 break; 243 break;
248 } 244 }
249 245
250 case ResourceType_Study: 246 case ResourceType_Study:
251 { 247 {
252 candidates.RestrictIdentifier(DICOM_TAG_STUDY_INSTANCE_UID); 248 candidates.RestrictIdentifier(query, DICOM_TAG_STUDY_INSTANCE_UID);
253 candidates.RestrictIdentifier(DICOM_TAG_ACCESSION_NUMBER); 249 candidates.RestrictIdentifier(query, DICOM_TAG_ACCESSION_NUMBER);
254 break; 250 break;
255 } 251 }
256 252
257 case ResourceType_Series: 253 case ResourceType_Series:
258 { 254 {
259 candidates.RestrictIdentifier(DICOM_TAG_SERIES_INSTANCE_UID); 255 candidates.RestrictIdentifier(query, DICOM_TAG_SERIES_INSTANCE_UID);
260 break; 256 break;
261 } 257 }
262 258
263 case ResourceType_Instance: 259 case ResourceType_Instance:
264 { 260 {
265 candidates.RestrictIdentifier(DICOM_TAG_SOP_INSTANCE_UID); 261 candidates.RestrictIdentifier(query, DICOM_TAG_SOP_INSTANCE_UID);
266 break; 262 break;
267 } 263 }
268 264
269 default: 265 default:
270 throw OrthancException(ErrorCode_InternalError); 266 throw OrthancException(ErrorCode_InternalError);
271 } 267 }
272 268
273 candidates.RestrictMainDicomTags(); 269 candidates.RestrictMainDicomTags(query);
274 } 270 }
275 271
276
277
278 void BaseResourceFinder::SetIdentifier(const DicomTag& tag,
279 const std::string& value)
280 {
281 assert((level_ >= ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
282 (level_ >= ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
283 (level_ >= ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
284 (level_ >= ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
285 (level_ >= ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
286
287 identifiers_[tag] = value;
288 }
289 272
290 273
291 static bool LookupOneInstance(std::string& result, 274 static bool LookupOneInstance(std::string& result,
292 ServerIndex& index, 275 ServerIndex& index,
293 const std::string& id, 276 const std::string& id,
315 298
316 return LookupOneInstance(result, index, childId, GetChildResourceType(type)); 299 return LookupOneInstance(result, index, childId, GetChildResourceType(type));
317 } 300 }
318 301
319 302
320 bool BaseResourceFinder::Apply(std::list<std::string>& result) 303 bool ResourceFinder::Apply(std::list<std::string>& result,
304 const IQuery& query)
321 { 305 {
322 CandidateResources candidates(*this); 306 CandidateResources candidates(*this);
323 307
324 ApplyAtLevel(candidates, ResourceType_Patient); 308 ApplyAtLevel(candidates, query, ResourceType_Patient);
325 309
326 if (level_ == ResourceType_Study || 310 const ResourceType level = query.GetLevel();
327 level_ == ResourceType_Series || 311
328 level_ == ResourceType_Instance) 312 if (level == ResourceType_Study ||
329 { 313 level == ResourceType_Series ||
330 ApplyAtLevel(candidates, ResourceType_Study); 314 level == ResourceType_Instance)
315 {
316 ApplyAtLevel(candidates, query, ResourceType_Study);
331 } 317 }
332 318
333 if (level_ == ResourceType_Series || 319 if (level == ResourceType_Series ||
334 level_ == ResourceType_Instance) 320 level == ResourceType_Instance)
335 { 321 {
336 ApplyAtLevel(candidates, ResourceType_Series); 322 ApplyAtLevel(candidates, query, ResourceType_Series);
337 } 323 }
338 324
339 if (level_ == ResourceType_Instance) 325 if (level == ResourceType_Instance)
340 { 326 {
341 ApplyAtLevel(candidates, ResourceType_Instance); 327 ApplyAtLevel(candidates, query, ResourceType_Instance);
342 } 328 }
343 329
344 if (instanceFilter_ == NULL) 330 if (!query.HasInstanceFilter())
345 { 331 {
346 candidates.Flatten(result); 332 candidates.Flatten(result);
347 333
348 if (maxResults_ != 0 && 334 if (maxResults_ != 0 &&
349 result.size() >= maxResults_) 335 result.size() >= maxResults_)
366 resource = tmp.begin(); resource != tmp.end(); ++resource) 352 resource = tmp.begin(); resource != tmp.end(); ++resource)
367 { 353 {
368 try 354 try
369 { 355 {
370 std::string instance; 356 std::string instance;
371 if (LookupOneInstance(instance, context_.GetIndex(), *resource, level_)) 357 if (LookupOneInstance(instance, context_.GetIndex(), *resource, level))
372 { 358 {
373 Json::Value content; 359 Json::Value content;
374 context_.ReadJson(content, instance); 360 context_.ReadJson(content, instance);
375 if (instanceFilter_->Apply(*resource, content)) 361 if (query.FilterInstance(*resource, content))
376 { 362 {
377 result.push_back(*resource); 363 result.push_back(*resource);
378 364
379 if (maxResults_ != 0 && 365 if (maxResults_ != 0 &&
380 result.size() >= maxResults_) 366 result.size() >= maxResults_)