Mercurial > hg > orthanc-stone
comparison OrthancStone/Sources/Loaders/SeriesMetadataLoader.cpp @ 1512:244ad1e4e76a
reorganization of folders
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 07 Jul 2020 16:21:02 +0200 |
parents | Framework/Loaders/SeriesMetadataLoader.cpp@4db187d29731 |
children | 85e117739eca |
comparison
equal
deleted
inserted
replaced
1511:9dfeee74c1e6 | 1512:244ad1e4e76a |
---|---|
1 /** | |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "SeriesMetadataLoader.h" | |
23 | |
24 #include <DicomFormat/DicomInstanceHasher.h> | |
25 | |
26 namespace OrthancStone | |
27 { | |
28 SeriesMetadataLoader::SeriesMetadataLoader(boost::shared_ptr<DicomResourcesLoader>& loader) : | |
29 loader_(loader), | |
30 state_(State_Setup) | |
31 { | |
32 } | |
33 | |
34 | |
35 bool SeriesMetadataLoader::IsScheduledWithHigherPriority(const std::string& seriesInstanceUid, | |
36 int priority) const | |
37 { | |
38 if (series_.find(seriesInstanceUid) != series_.end()) | |
39 { | |
40 // This series is readily available | |
41 return true; | |
42 } | |
43 else | |
44 { | |
45 std::map<std::string, int>::const_iterator found = scheduled_.find(seriesInstanceUid); | |
46 | |
47 return (found != scheduled_.end() && | |
48 found->second < priority); | |
49 } | |
50 } | |
51 | |
52 | |
53 void SeriesMetadataLoader::Handle(const DicomResourcesLoader::SuccessMessage& message) | |
54 { | |
55 assert(message.GetResources()); | |
56 | |
57 switch (state_) | |
58 { | |
59 case State_Setup: | |
60 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
61 | |
62 case State_Default: | |
63 { | |
64 std::string studyInstanceUid; | |
65 std::string seriesInstanceUid; | |
66 | |
67 if (message.GetResources()->LookupTagValueConsensus(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID) && | |
68 message.GetResources()->LookupTagValueConsensus(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID)) | |
69 { | |
70 series_[seriesInstanceUid] = message.GetResources(); | |
71 | |
72 SuccessMessage loadedMessage(*this, message.GetDicomSource(), studyInstanceUid, | |
73 seriesInstanceUid, *message.GetResources()); | |
74 BroadcastMessage(loadedMessage); | |
75 } | |
76 | |
77 break; | |
78 } | |
79 | |
80 case State_DicomDir: | |
81 { | |
82 assert(!dicomDir_); | |
83 assert(seriesSize_.empty()); | |
84 | |
85 dicomDir_ = message.GetResources(); | |
86 | |
87 for (size_t i = 0; i < message.GetResources()->GetSize(); i++) | |
88 { | |
89 std::string seriesInstanceUid; | |
90 if (message.GetResources()->GetResource(i).LookupStringValue | |
91 (seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false)) | |
92 { | |
93 boost::shared_ptr<OrthancStone::LoadedDicomResources> target | |
94 (new OrthancStone::LoadedDicomResources(Orthanc::DICOM_TAG_SOP_INSTANCE_UID)); | |
95 | |
96 if (loader_->ScheduleLoadDicomFile(target, message.GetPriority(), message.GetDicomSource(), dicomDirPath_, | |
97 message.GetResources()->GetResource(i), false /* no need for pixel data */, | |
98 NULL /* TODO PAYLOAD */)) | |
99 { | |
100 std::map<std::string, unsigned int>::iterator found = seriesSize_.find(seriesInstanceUid); | |
101 if (found == seriesSize_.end()) | |
102 { | |
103 series_[seriesInstanceUid].reset | |
104 (new OrthancStone::LoadedDicomResources(Orthanc::DICOM_TAG_SOP_INSTANCE_UID)); | |
105 seriesSize_[seriesInstanceUid] = 1; | |
106 } | |
107 else | |
108 { | |
109 found->second ++; | |
110 } | |
111 } | |
112 } | |
113 } | |
114 | |
115 LOG(INFO) << "Read a DICOMDIR containing " << seriesSize_.size() << " series"; | |
116 | |
117 state_ = State_DicomFile; | |
118 break; | |
119 } | |
120 | |
121 case State_DicomFile: | |
122 { | |
123 assert(dicomDir_); | |
124 assert(message.GetResources()->GetSize() <= 1); // Could be zero if corrupted DICOM instance | |
125 | |
126 if (message.GetResources()->GetSize() == 1) | |
127 { | |
128 const Orthanc::DicomMap& instance = message.GetResources()->GetResource(0); | |
129 | |
130 std::string studyInstanceUid; | |
131 std::string seriesInstanceUid; | |
132 if (instance.LookupStringValue(studyInstanceUid, Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, false) && | |
133 instance.LookupStringValue(seriesInstanceUid, Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, false)) | |
134 { | |
135 Series::const_iterator series = series_.find(seriesInstanceUid); | |
136 std::map<std::string, unsigned int>::const_iterator size = seriesSize_.find(seriesInstanceUid); | |
137 | |
138 if (series == series_.end() || | |
139 size == seriesSize_.end()) | |
140 { | |
141 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
142 } | |
143 else | |
144 { | |
145 series->second->AddResource(instance); | |
146 | |
147 if (series->second->GetSize() > size->second) | |
148 { | |
149 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
150 } | |
151 else if (series->second->GetSize() == size->second) | |
152 { | |
153 // The series is complete | |
154 SuccessMessage loadedMessage( | |
155 *this, message.GetDicomSource(), | |
156 studyInstanceUid, seriesInstanceUid, *series->second); | |
157 loadedMessage.SetDicomDir(dicomDirPath_, dicomDir_); | |
158 BroadcastMessage(loadedMessage); | |
159 } | |
160 } | |
161 } | |
162 } | |
163 | |
164 break; | |
165 } | |
166 | |
167 default: | |
168 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
169 } | |
170 } | |
171 | |
172 | |
173 SeriesMetadataLoader::SuccessMessage::SuccessMessage( | |
174 const SeriesMetadataLoader& loader, | |
175 const DicomSource& source, | |
176 const std::string& studyInstanceUid, | |
177 const std::string& seriesInstanceUid, | |
178 LoadedDicomResources& instances) : | |
179 OriginMessage(loader), | |
180 source_(source), | |
181 studyInstanceUid_(studyInstanceUid), | |
182 seriesInstanceUid_(seriesInstanceUid), | |
183 instances_(instances) | |
184 { | |
185 LOG(INFO) << "Loaded series " << seriesInstanceUid | |
186 << ", number of instances: " << instances_.GetSize(); | |
187 } | |
188 | |
189 | |
190 boost::shared_ptr<SeriesMetadataLoader> SeriesMetadataLoader::Create(ILoadersContext::ILock& context) | |
191 { | |
192 boost::shared_ptr<DicomResourcesLoader> loader(DicomResourcesLoader::Create(context)); | |
193 | |
194 boost::shared_ptr<SeriesMetadataLoader> obj(new SeriesMetadataLoader(loader)); | |
195 obj->Register<DicomResourcesLoader::SuccessMessage>(*loader, &SeriesMetadataLoader::Handle); | |
196 return obj; | |
197 } | |
198 | |
199 | |
200 SeriesMetadataLoader::Accessor::Accessor(SeriesMetadataLoader& that, | |
201 const std::string& seriesInstanceUid) | |
202 { | |
203 Series::const_iterator found = that.series_.find(seriesInstanceUid); | |
204 if (found != that.series_.end()) | |
205 { | |
206 assert(found->second != NULL); | |
207 series_ = found->second; | |
208 } | |
209 } | |
210 | |
211 | |
212 size_t SeriesMetadataLoader::Accessor::GetInstancesCount() const | |
213 { | |
214 if (IsComplete()) | |
215 { | |
216 return series_->GetSize(); | |
217 } | |
218 else | |
219 { | |
220 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
221 } | |
222 } | |
223 | |
224 | |
225 const Orthanc::DicomMap& SeriesMetadataLoader::Accessor::GetInstance(size_t index) const | |
226 { | |
227 if (IsComplete()) | |
228 { | |
229 return series_->GetResource(index); | |
230 } | |
231 else | |
232 { | |
233 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
234 } | |
235 } | |
236 | |
237 | |
238 void SeriesMetadataLoader::ScheduleLoadSeries(int priority, | |
239 const DicomSource& source, | |
240 const std::string& studyInstanceUid, | |
241 const std::string& seriesInstanceUid) | |
242 { | |
243 if (state_ != State_Setup && | |
244 state_ != State_Default) | |
245 { | |
246 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, | |
247 "The loader is working in DICOMDIR state"); | |
248 } | |
249 | |
250 state_ = State_Default; | |
251 | |
252 // Only re-schedule the loading if the previous loading was with lower priority | |
253 if (!IsScheduledWithHigherPriority(seriesInstanceUid, priority)) | |
254 { | |
255 if (source.IsDicomWeb()) | |
256 { | |
257 boost::shared_ptr<LoadedDicomResources> target | |
258 (new LoadedDicomResources(Orthanc::DICOM_TAG_SOP_INSTANCE_UID)); | |
259 loader_->ScheduleGetDicomWeb( | |
260 target, priority, source, | |
261 "/studies/" + studyInstanceUid + "/series/" + seriesInstanceUid + "/metadata", | |
262 NULL /* TODO PAYLOAD */); | |
263 | |
264 scheduled_[seriesInstanceUid] = priority; | |
265 } | |
266 else if (source.IsOrthanc()) | |
267 { | |
268 // This flavor of the method is only available with DICOMweb, as | |
269 // Orthanc requires the "PatientID" to be known | |
270 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, | |
271 "The PatientID must be provided on Orthanc sources"); | |
272 } | |
273 else | |
274 { | |
275 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
276 } | |
277 } | |
278 } | |
279 | |
280 | |
281 void SeriesMetadataLoader::ScheduleLoadSeries(int priority, | |
282 const DicomSource& source, | |
283 const std::string& patientId, | |
284 const std::string& studyInstanceUid, | |
285 const std::string& seriesInstanceUid) | |
286 { | |
287 if (state_ != State_Setup && | |
288 state_ != State_Default) | |
289 { | |
290 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, | |
291 "The loader is working in DICOMDIR state"); | |
292 } | |
293 | |
294 state_ = State_Default; | |
295 | |
296 if (source.IsDicomWeb()) | |
297 { | |
298 ScheduleLoadSeries(priority, source, studyInstanceUid, seriesInstanceUid); | |
299 } | |
300 else if (!IsScheduledWithHigherPriority(seriesInstanceUid, priority)) | |
301 { | |
302 if (source.IsOrthanc()) | |
303 { | |
304 // Dummy SOP Instance UID, as we are working at the "series" level | |
305 Orthanc::DicomInstanceHasher hasher(patientId, studyInstanceUid, seriesInstanceUid, "dummy"); | |
306 | |
307 boost::shared_ptr<LoadedDicomResources> target | |
308 (new LoadedDicomResources(Orthanc::DICOM_TAG_SOP_INSTANCE_UID)); | |
309 | |
310 loader_->ScheduleLoadOrthancResources(target, priority, source, Orthanc::ResourceType_Series, | |
311 hasher.HashSeries(), Orthanc::ResourceType_Instance, | |
312 NULL /* TODO PAYLOAD */); | |
313 | |
314 scheduled_[seriesInstanceUid] = priority; | |
315 } | |
316 else | |
317 { | |
318 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
319 } | |
320 } | |
321 } | |
322 | |
323 | |
324 void SeriesMetadataLoader::ScheduleLoadDicomDir(int priority, | |
325 const DicomSource& source, | |
326 const std::string& path) | |
327 { | |
328 if (!source.IsDicomDir()) | |
329 { | |
330 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
331 } | |
332 | |
333 if (state_ != State_Setup) | |
334 { | |
335 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, | |
336 "The loader cannot load two different DICOMDIR"); | |
337 } | |
338 | |
339 state_ = State_DicomDir; | |
340 dicomDirPath_ = path; | |
341 boost::shared_ptr<LoadedDicomResources> dicomDir | |
342 (new LoadedDicomResources(Orthanc::DICOM_TAG_REFERENCED_SOP_INSTANCE_UID_IN_FILE)); | |
343 loader_->ScheduleLoadDicomDir(dicomDir, priority, source, path, | |
344 NULL /* TODO PAYLOAD */); | |
345 } | |
346 } |