Mercurial > hg > orthanc
comparison OrthancServer/Search/Compatibility/DatabaseLookup.cpp @ 3055:71ac4f28176f db-changes
compatibility layer seems to be working
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 21 Dec 2018 13:36:30 +0100 |
parents | 3638de45a08c |
children | 5ebd2ef5e7ae |
comparison
equal
deleted
inserted
replaced
3054:3638de45a08c | 3055:71ac4f28176f |
---|---|
40 | 40 |
41 namespace Orthanc | 41 namespace Orthanc |
42 { | 42 { |
43 namespace Compatibility | 43 namespace Compatibility |
44 { | 44 { |
45 namespace | |
46 { | |
47 // Anonymous namespace to avoid clashes between compiler modules | |
48 class MainTagsConstraints : boost::noncopyable | |
49 { | |
50 private: | |
51 std::vector<DicomTagConstraint*> constraints_; | |
52 | |
53 public: | |
54 ~MainTagsConstraints() | |
55 { | |
56 for (size_t i = 0; i < constraints_.size(); i++) | |
57 { | |
58 assert(constraints_[i] != NULL); | |
59 delete constraints_[i]; | |
60 } | |
61 } | |
62 | |
63 void Reserve(size_t n) | |
64 { | |
65 constraints_.reserve(n); | |
66 } | |
67 | |
68 size_t GetSize() const | |
69 { | |
70 return constraints_.size(); | |
71 } | |
72 | |
73 DicomTagConstraint& GetConstraint(size_t i) const | |
74 { | |
75 if (i >= constraints_.size()) | |
76 { | |
77 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
78 } | |
79 else | |
80 { | |
81 assert(constraints_[i] != NULL); | |
82 return *constraints_[i]; | |
83 } | |
84 } | |
85 | |
86 void Add(const DatabaseConstraint& constraint) | |
87 { | |
88 constraints_.push_back(new DicomTagConstraint(constraint)); | |
89 } | |
90 }; | |
91 } | |
92 | |
93 | |
45 static void ApplyIdentifierConstraint(SetOfResources& candidates, | 94 static void ApplyIdentifierConstraint(SetOfResources& candidates, |
46 CompatibilityDatabaseWrapper& database, | 95 CompatibilityDatabaseWrapper& database, |
47 const DatabaseConstraint& constraint, | 96 const DatabaseConstraint& constraint, |
48 ResourceType level) | 97 ResourceType level) |
49 { | 98 { |
72 IdentifierConstraintType_Wildcard, constraint.GetSingleValue()); | 121 IdentifierConstraintType_Wildcard, constraint.GetSingleValue()); |
73 | 122 |
74 break; | 123 break; |
75 | 124 |
76 case ConstraintType_List: | 125 case ConstraintType_List: |
77 { | |
78 for (size_t i = 0; i < constraint.GetValuesCount(); i++) | 126 for (size_t i = 0; i < constraint.GetValuesCount(); i++) |
79 { | 127 { |
80 std::list<int64_t> tmp; | 128 std::list<int64_t> tmp; |
81 database.LookupIdentifier(tmp, level, constraint.GetTag(), | 129 database.LookupIdentifier(tmp, level, constraint.GetTag(), |
82 IdentifierConstraintType_Wildcard, constraint.GetValue(i)); | 130 IdentifierConstraintType_Wildcard, constraint.GetValue(i)); |
83 matches.splice(matches.end(), tmp); | 131 matches.splice(matches.end(), tmp); |
84 } | 132 } |
85 | 133 |
86 break; | 134 break; |
87 } | |
88 | 135 |
89 default: | 136 default: |
90 throw OrthancException(ErrorCode_InternalError); | 137 throw OrthancException(ErrorCode_InternalError); |
91 } | 138 } |
92 | 139 |
118 ResourceType level) | 165 ResourceType level) |
119 { | 166 { |
120 typedef std::set<const DatabaseConstraint*> SetOfConstraints; | 167 typedef std::set<const DatabaseConstraint*> SetOfConstraints; |
121 typedef std::map<DicomTag, SetOfConstraints> Identifiers; | 168 typedef std::map<DicomTag, SetOfConstraints> Identifiers; |
122 | 169 |
170 // (1) Select which constraints apply to this level, and split | |
171 // them between "identifier tags" constraints and "main DICOM | |
172 // tags" constraints | |
173 | |
123 Identifiers identifiers; | 174 Identifiers identifiers; |
124 SetOfConstraints mainTags; | 175 SetOfConstraints mainTags; |
125 | 176 |
126 for (size_t i = 0; i < lookup.size(); i++) | 177 for (size_t i = 0; i < lookup.size(); i++) |
127 { | 178 { |
136 mainTags.insert(&lookup[i]); | 187 mainTags.insert(&lookup[i]); |
137 } | 188 } |
138 } | 189 } |
139 } | 190 } |
140 | 191 |
192 | |
193 // (2) Apply the constraints over the identifiers | |
194 | |
141 for (Identifiers::const_iterator it = identifiers.begin(); | 195 for (Identifiers::const_iterator it = identifiers.begin(); |
142 it != identifiers.end(); ++it) | 196 it != identifiers.end(); ++it) |
143 { | 197 { |
198 // Check whether some range constraint over identifiers is | |
199 // present at this level | |
144 const DatabaseConstraint* smaller = NULL; | 200 const DatabaseConstraint* smaller = NULL; |
145 const DatabaseConstraint* greater = NULL; | 201 const DatabaseConstraint* greater = NULL; |
146 | 202 |
147 for (SetOfConstraints::const_iterator it2 = it->second.begin(); | 203 for (SetOfConstraints::const_iterator it2 = it->second.begin(); |
148 it2 != it->second.end(); ++it2) | 204 it2 != it->second.end(); ++it2) |
149 { | 205 { |
206 assert(*it2 != NULL); | |
207 | |
150 if ((*it2)->GetConstraintType() == ConstraintType_SmallerOrEqual) | 208 if ((*it2)->GetConstraintType() == ConstraintType_SmallerOrEqual) |
151 { | 209 { |
152 smaller = *it2; | 210 smaller = *it2; |
153 } | 211 } |
154 | 212 |
159 } | 217 } |
160 | 218 |
161 if (smaller != NULL && | 219 if (smaller != NULL && |
162 greater != NULL) | 220 greater != NULL) |
163 { | 221 { |
222 // There is a range constraint: Apply it, as it is more efficient | |
164 ApplyIdentifierRange(candidates, database, *smaller, *greater, level); | 223 ApplyIdentifierRange(candidates, database, *smaller, *greater, level); |
165 } | 224 } |
166 else | 225 else |
167 { | 226 { |
168 smaller = NULL; | 227 smaller = NULL; |
170 } | 229 } |
171 | 230 |
172 for (SetOfConstraints::const_iterator it2 = it->second.begin(); | 231 for (SetOfConstraints::const_iterator it2 = it->second.begin(); |
173 it2 != it->second.end(); ++it2) | 232 it2 != it->second.end(); ++it2) |
174 { | 233 { |
234 // Check to avoid applying twice the range constraint | |
175 if (*it2 != smaller && | 235 if (*it2 != smaller && |
176 *it2 != greater) | 236 *it2 != greater) |
177 { | 237 { |
178 ApplyIdentifierConstraint(candidates, database, **it2, level); | 238 ApplyIdentifierConstraint(candidates, database, **it2, level); |
179 } | 239 } |
180 } | 240 } |
181 } | 241 } |
182 | 242 |
183 | 243 |
184 // TODO - Fiter main DICOM tags | 244 // (3) Apply the constraints over the main DICOM tags (no index |
245 // here, so this is less efficient than filtering over the | |
246 // identifiers) | |
247 if (!mainTags.empty()) | |
248 { | |
249 MainTagsConstraints c; | |
250 c.Reserve(mainTags.size()); | |
251 | |
252 for (SetOfConstraints::const_iterator it = mainTags.begin(); | |
253 it != mainTags.end(); ++it) | |
254 { | |
255 assert(*it != NULL); | |
256 c.Add(**it); | |
257 } | |
258 | |
259 std::list<int64_t> source; | |
260 candidates.Flatten(source); | |
261 candidates.Clear(); | |
262 | |
263 std::list<int64_t> filtered; | |
264 for (std::list<int64_t>::const_iterator candidate = source.begin(); | |
265 candidate != source.end(); ++candidate) | |
266 { | |
267 DicomMap tags; | |
268 database.GetMainDicomTags(tags, *candidate); | |
269 | |
270 bool match = true; | |
271 | |
272 for (size_t i = 0; i < c.GetSize(); i++) | |
273 { | |
274 if (!c.GetConstraint(i).IsMatch(tags)) | |
275 { | |
276 match = false; | |
277 break; | |
278 } | |
279 } | |
280 | |
281 if (match) | |
282 { | |
283 filtered.push_back(*candidate); | |
284 } | |
285 } | |
286 | |
287 candidates.Intersect(filtered); | |
288 } | |
185 } | 289 } |
186 | 290 |
187 | 291 |
188 static std::string GetOneInstance(IDatabaseWrapper& database, | 292 static std::string GetOneInstance(IDatabaseWrapper& database, |
189 int64_t resource, | 293 int64_t resource, |