comparison OrthancServer/ResourceFinder.cpp @ 1352:382439943749

ResourceFinder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 11 May 2015 17:25:53 +0200
parents
children d7da97e21161
comparison
equal deleted inserted replaced
1351:fa09aa513fd4 1352:382439943749
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "PrecompiledHeadersServer.h"
34 #include "ResourceFinder.h"
35
36 #include "FromDcmtkBridge.h"
37
38 #include <glog/logging.h>
39 #include <boost/algorithm/string/predicate.hpp>
40
41 namespace Orthanc
42 {
43 static bool Compare(const std::string& a,
44 const std::string& b,
45 bool caseSensitive)
46 {
47 if (caseSensitive)
48 {
49 return a == b;
50 }
51 else
52 {
53 return boost::iequals(a, b);
54 }
55 }
56
57
58 namespace
59 {
60 class CandidateResources
61 {
62 private:
63 ServerIndex& index_;
64 ResourceType level_;
65 bool isFilterApplied_;
66 std::set<std::string> filtered_;
67
68
69 static void ListToSet(std::set<std::string>& target,
70 const std::list<std::string>& source)
71 {
72 for (std::list<std::string>::const_iterator
73 it = source.begin(); it != source.end(); ++it)
74 {
75 target.insert(*it);
76 }
77 }
78
79
80 public:
81 CandidateResources(ServerIndex& index) :
82 index_(index),
83 level_(ResourceType_Patient),
84 isFilterApplied_(false)
85 {
86 }
87
88 ResourceType GetLevel() const
89 {
90 return level_;
91 }
92
93 void GoDown()
94 {
95 assert(level_ != ResourceType_Instance);
96
97 if (isFilterApplied_)
98 {
99 std::set<std::string> tmp = filtered_;
100
101 filtered_.clear();
102
103 for (std::set<std::string>::const_iterator
104 it = tmp.begin(); it != tmp.end(); ++it)
105 {
106 std::list<std::string> children;
107 index_.GetChildren(children, *it);
108 ListToSet(filtered_, children);
109 }
110 }
111
112 switch (level_)
113 {
114 case ResourceType_Patient:
115 level_ = ResourceType_Study;
116 break;
117
118 case ResourceType_Study:
119 level_ = ResourceType_Series;
120 break;
121
122 case ResourceType_Series:
123 level_ = ResourceType_Instance;
124 break;
125
126 default:
127 throw OrthancException(ErrorCode_InternalError);
128 }
129 }
130
131
132 void Flatten(std::list<std::string>& resources) const
133 {
134 resources.clear();
135
136 if (isFilterApplied_)
137 {
138 for (std::set<std::string>::const_iterator
139 it = filtered_.begin(); it != filtered_.end(); ++it)
140 {
141 resources.push_back(*it);
142 }
143 }
144 else
145 {
146 Json::Value tmp;
147 index_.GetAllUuids(tmp, level_);
148 for (Json::Value::ArrayIndex i = 0; i < tmp.size(); i++)
149 {
150 resources.push_back(tmp[i].asString());
151 }
152 }
153 }
154
155
156 void RestrictIdentifier(const DicomTag& tag,
157 const std::string& value)
158 {
159 assert((level_ == ResourceType_Patient && tag == DICOM_TAG_PATIENT_ID) ||
160 (level_ == ResourceType_Study && tag == DICOM_TAG_STUDY_INSTANCE_UID) ||
161 (level_ == ResourceType_Study && tag == DICOM_TAG_ACCESSION_NUMBER) ||
162 (level_ == ResourceType_Series && tag == DICOM_TAG_SERIES_INSTANCE_UID) ||
163 (level_ == ResourceType_Instance && tag == DICOM_TAG_SOP_INSTANCE_UID));
164
165 LOG(INFO) << "Lookup for identifier tag "
166 << FromDcmtkBridge::GetName(tag) << " (value: " << value << ")";
167
168 std::list<std::string> resources;
169 index_.LookupIdentifier(resources, tag, value, level_);
170
171 if (isFilterApplied_)
172 {
173 std::set<std::string> s;
174 ListToSet(s, resources);
175
176 std::set<std::string> tmp = filtered_;
177 filtered_.clear();
178
179 for (std::set<std::string>::const_iterator
180 it = tmp.begin(); it != tmp.end(); ++it)
181 {
182 if (s.find(*it) != s.end())
183 {
184 filtered_.insert(*it);
185 }
186 }
187 }
188 else
189 {
190 assert(filtered_.empty());
191 isFilterApplied_ = true;
192 ListToSet(filtered_, resources);
193 }
194 }
195
196
197 void RestrictMainDicomTags(const ResourceFinder::Query& query,
198 bool caseSensitive)
199 {
200 std::list<std::string> resources;
201 Flatten(resources);
202
203 isFilterApplied_ = true;
204 filtered_.clear();
205
206 for (std::list<std::string>::const_iterator
207 it = resources.begin(); it != resources.end(); it++)
208 {
209 DicomMap mainTags;
210 if (index_.GetMainDicomTags(mainTags, *it, level_))
211 {
212 for (ResourceFinder::Query::const_iterator
213 tag = query.begin(); tag != query.end(); ++tag)
214 {
215 assert(DicomMap::IsMainDicomTag(tag->first, level_));
216 LOG(INFO) << "Lookup for main DICOM tag "
217 << FromDcmtkBridge::GetName(tag->first) << " (value: " << tag->second << ")";
218
219 const DicomValue* value = mainTags.TestAndGetValue(tag->first);
220 if (value != NULL &&
221 Compare(value->AsString(), tag->second, caseSensitive))
222 {
223 filtered_.insert(*it);
224 }
225 }
226 }
227 }
228 }
229 };
230 }
231
232
233 ResourceFinder::ResourceFinder(ServerContext& context) :
234 context_(context),
235 level_(ResourceType_Patient),
236 caseSensitive_(true)
237 {
238 }
239
240
241 void ResourceFinder::AddTag(const std::string& tag,
242 const std::string& value)
243 {
244 AddTag(FromDcmtkBridge::ParseTag(tag.c_str()), value);
245 }
246
247
248 void ResourceFinder::Apply(std::list<std::string>& result)
249 {
250 result.clear();
251 }
252 }