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,