Mercurial > hg > orthanc-stone
comparison Framework/Toolbox/OrthancSlicesLoader.cpp @ 247:3d523c9a8f0d am
trying to use boost::signals2 even more.
author | am@osimis.io |
---|---|
date | Mon, 02 Jul 2018 12:32:02 +0200 |
parents | 5412adf19980 |
children |
comparison
equal
deleted
inserted
replaced
246:5470b15f7cf2 | 247:3d523c9a8f0d |
---|---|
167 return tmp.release(); | 167 return tmp.release(); |
168 } | 168 } |
169 }; | 169 }; |
170 | 170 |
171 | 171 |
172 class OrthancSlicesLoader::WebCallback : public IWebService::ICallback | 172 // class OrthancSlicesLoader::WebCallback : public IWebService::ICallback |
173 { | 173 // { |
174 private: | 174 // private: |
175 OrthancSlicesLoader& that_; | 175 // OrthancSlicesLoader& that_; |
176 | 176 |
177 public: | 177 // public: |
178 WebCallback(OrthancSlicesLoader& that) : | 178 // WebCallback(OrthancSlicesLoader& that) : |
179 that_(that) | 179 // that_(that) |
180 { | 180 // { |
181 } | 181 // } |
182 | 182 |
183 virtual void NotifySuccess(const std::string& uri, | 183 void OrthancSlicesLoader::OnRequestSuccess(const std::string& uri, |
184 const void* answer, | 184 const void* answer, |
185 size_t answerSize, | 185 size_t answerSize, |
186 Orthanc::IDynamicObject* payload) | 186 Orthanc::IDynamicObject* payload) |
187 { | 187 { |
188 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); | 188 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); |
189 | 189 |
190 switch (operation->GetMode()) | 190 switch (operation->GetMode()) |
191 { | 191 { |
192 case Mode_SeriesGeometry: | 192 case Mode_SeriesGeometry: |
193 that_.ParseSeriesGeometry(answer, answerSize); | 193 ParseSeriesGeometry(answer, answerSize); |
194 break; | 194 break; |
195 | 195 |
196 case Mode_InstanceGeometry: | 196 case Mode_InstanceGeometry: |
197 that_.ParseInstanceGeometry(operation->GetInstanceId(), answer, answerSize); | 197 ParseInstanceGeometry(operation->GetInstanceId(), answer, answerSize); |
198 break; | 198 break; |
199 | 199 |
200 case Mode_FrameGeometry: | 200 case Mode_FrameGeometry: |
201 that_.ParseFrameGeometry(operation->GetInstanceId(), | 201 ParseFrameGeometry(operation->GetInstanceId(), |
202 operation->GetFrame(), answer, answerSize); | 202 operation->GetFrame(), answer, answerSize); |
203 break; | 203 break; |
204 | 204 |
205 case Mode_LoadImage: | 205 case Mode_LoadImage: |
206 switch (operation->GetQuality()) | 206 switch (operation->GetQuality()) |
207 { | 207 { |
208 case SliceImageQuality_Full: | 208 case SliceImageQuality_Full: |
209 that_.ParseSliceImagePng(*operation, answer, answerSize); | 209 ParseSliceImagePng(*operation, answer, answerSize); |
210 break; | 210 break; |
211 | 211 |
212 case SliceImageQuality_Jpeg50: | 212 case SliceImageQuality_Jpeg50: |
213 case SliceImageQuality_Jpeg90: | 213 case SliceImageQuality_Jpeg90: |
214 case SliceImageQuality_Jpeg95: | 214 case SliceImageQuality_Jpeg95: |
215 that_.ParseSliceImageJpeg(*operation, answer, answerSize); | 215 ParseSliceImageJpeg(*operation, answer, answerSize); |
216 break; | 216 break; |
217 | 217 |
218 default: | 218 default: |
219 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 219 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
220 } | 220 } |
221 | 221 |
222 break; | 222 break; |
223 | 223 |
224 case Mode_LoadRawImage: | 224 case Mode_LoadRawImage: |
225 that_.ParseSliceRawImage(*operation, answer, answerSize); | 225 ParseSliceRawImage(*operation, answer, answerSize); |
226 break; | 226 break; |
227 | 227 |
228 default: | 228 default: |
229 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 229 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
230 } | 230 } |
231 } | 231 } |
232 | 232 |
233 virtual void NotifyError(const std::string& uri, | 233 void OrthancSlicesLoader::OnRequestError(const std::string& uri, |
234 Orthanc::IDynamicObject* payload) | 234 Orthanc::IDynamicObject* payload) |
235 { | 235 { |
236 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); | 236 std::auto_ptr<Operation> operation(dynamic_cast<Operation*>(payload)); |
237 LOG(ERROR) << "Cannot download " << uri; | 237 LOG(ERROR) << "Cannot download " << uri; |
238 | 238 |
239 switch (operation->GetMode()) | 239 switch (operation->GetMode()) |
240 { | 240 { |
241 case Mode_FrameGeometry: | 241 case Mode_FrameGeometry: |
242 case Mode_SeriesGeometry: | 242 case Mode_SeriesGeometry: |
243 that_.userCallback_.NotifyGeometryError(that_); | 243 SignalGeometryError(*this); |
244 that_.state_ = State_Error; | 244 state_ = State_Error; |
245 break; | 245 break; |
246 | 246 |
247 case Mode_LoadImage: | 247 case Mode_LoadImage: |
248 that_.userCallback_.NotifySliceImageError(that_, operation->GetSliceIndex(), | 248 SignalSliceImageError(*this, operation->GetSliceIndex(), |
249 operation->GetSlice(), | 249 operation->GetSlice(), |
250 operation->GetQuality()); | 250 operation->GetQuality()); |
251 break; | 251 break; |
252 | 252 |
253 default: | 253 default: |
254 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 254 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
255 } | 255 } |
256 } | 256 } |
257 }; | 257 // }; |
258 | 258 |
259 | 259 |
260 | 260 |
261 void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation, | 261 void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation, |
262 std::auto_ptr<Orthanc::ImageAccessor>& image) const | 262 std::auto_ptr<Orthanc::ImageAccessor>& image) const |
265 { | 265 { |
266 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 266 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
267 } | 267 } |
268 else | 268 else |
269 { | 269 { |
270 userCallback_.NotifySliceImageReady | 270 SignalSliceImageReady(*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality()); |
271 (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality()); | |
272 } | 271 } |
273 } | 272 } |
274 | 273 |
275 | 274 |
276 void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation) const | 275 void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation) const |
277 { | 276 { |
278 userCallback_.NotifySliceImageError | 277 SignalSliceImageError(*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality()); |
279 (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality()); | |
280 } | 278 } |
281 | 279 |
282 | 280 |
283 void OrthancSlicesLoader::SortAndFinalizeSlices() | 281 void OrthancSlicesLoader::SortAndFinalizeSlices() |
284 { | 282 { |
299 state_ = State_GeometryReady; | 297 state_ = State_GeometryReady; |
300 | 298 |
301 if (ok) | 299 if (ok) |
302 { | 300 { |
303 LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; | 301 LOG(INFO) << "Loaded a series with " << slices_.GetSliceCount() << " slice(s)"; |
304 userCallback_.NotifyGeometryReady(*this); | 302 SignalGeometryReady(*this); |
305 } | 303 } |
306 else | 304 else |
307 { | 305 { |
308 LOG(ERROR) << "This series is empty"; | 306 LOG(ERROR) << "This series is empty"; |
309 userCallback_.NotifyGeometryError(*this); | 307 SignalGeometryError(*this); |
310 } | 308 } |
311 } | 309 } |
312 | 310 |
313 | 311 |
314 void OrthancSlicesLoader::ParseSeriesGeometry(const void* answer, | 312 void OrthancSlicesLoader::ParseSeriesGeometry(const void* answer, |
316 { | 314 { |
317 Json::Value series; | 315 Json::Value series; |
318 if (!MessagingToolbox::ParseJson(series, answer, size) || | 316 if (!MessagingToolbox::ParseJson(series, answer, size) || |
319 series.type() != Json::objectValue) | 317 series.type() != Json::objectValue) |
320 { | 318 { |
321 userCallback_.NotifyGeometryError(*this); | 319 SignalGeometryError(*this); |
322 return; | 320 return; |
323 } | 321 } |
324 | 322 |
325 Json::Value::Members instances = series.getMemberNames(); | 323 Json::Value::Members instances = series.getMemberNames(); |
326 | 324 |
363 { | 361 { |
364 Json::Value tags; | 362 Json::Value tags; |
365 if (!MessagingToolbox::ParseJson(tags, answer, size) || | 363 if (!MessagingToolbox::ParseJson(tags, answer, size) || |
366 tags.type() != Json::objectValue) | 364 tags.type() != Json::objectValue) |
367 { | 365 { |
368 userCallback_.NotifyGeometryError(*this); | 366 SignalGeometryError(*this); |
369 return; | 367 return; |
370 } | 368 } |
371 | 369 |
372 OrthancPlugins::FullOrthancDataset dataset(tags); | 370 OrthancPlugins::FullOrthancDataset dataset(tags); |
373 | 371 |
390 slices_.AddSlice(slice.release()); | 388 slices_.AddSlice(slice.release()); |
391 } | 389 } |
392 else | 390 else |
393 { | 391 { |
394 LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; | 392 LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; |
395 userCallback_.NotifyGeometryError(*this); | 393 SignalGeometryError(*this); |
396 return; | 394 return; |
397 } | 395 } |
398 } | 396 } |
399 | 397 |
400 SortAndFinalizeSlices(); | 398 SortAndFinalizeSlices(); |
408 { | 406 { |
409 Json::Value tags; | 407 Json::Value tags; |
410 if (!MessagingToolbox::ParseJson(tags, answer, size) || | 408 if (!MessagingToolbox::ParseJson(tags, answer, size) || |
411 tags.type() != Json::objectValue) | 409 tags.type() != Json::objectValue) |
412 { | 410 { |
413 userCallback_.NotifyGeometryError(*this); | 411 SignalGeometryError(*this); |
414 return; | 412 return; |
415 } | 413 } |
416 | 414 |
417 OrthancPlugins::FullOrthancDataset dataset(tags); | 415 OrthancPlugins::FullOrthancDataset dataset(tags); |
418 | 416 |
424 std::auto_ptr<Slice> slice(new Slice); | 422 std::auto_ptr<Slice> slice(new Slice); |
425 if (slice->ParseOrthancFrame(dicom, instanceId, frame)) | 423 if (slice->ParseOrthancFrame(dicom, instanceId, frame)) |
426 { | 424 { |
427 LOG(INFO) << "Loaded instance " << instanceId; | 425 LOG(INFO) << "Loaded instance " << instanceId; |
428 slices_.AddSlice(slice.release()); | 426 slices_.AddSlice(slice.release()); |
429 userCallback_.NotifyGeometryReady(*this); | 427 SignalGeometryReady(*this); |
430 } | 428 } |
431 else | 429 else |
432 { | 430 { |
433 LOG(WARNING) << "Skipping invalid instance " << instanceId; | 431 LOG(WARNING) << "Skipping invalid instance " << instanceId; |
434 userCallback_.NotifyGeometryError(*this); | 432 SignalGeometryError(*this); |
435 } | 433 } |
436 } | 434 } |
437 | 435 |
438 | 436 |
439 void OrthancSlicesLoader::ParseSliceImagePng(const Operation& operation, | 437 void OrthancSlicesLoader::ParseSliceImagePng(const Operation& operation, |
713 } | 711 } |
714 | 712 |
715 } | 713 } |
716 | 714 |
717 | 715 |
718 OrthancSlicesLoader::OrthancSlicesLoader(ICallback& callback, | 716 OrthancSlicesLoader::OrthancSlicesLoader(boost::shared_ptr<OrthancSlicesLoader::IObserver> observer, |
719 IWebService& orthanc) : | 717 IWebService& orthanc) : |
720 webCallback_(new WebCallback(*this)), | 718 //webCallback_(new WebCallback(*this)), |
721 userCallback_(callback), | 719 // userCallback_(callback), |
720 observer_(observer), | |
722 orthanc_(orthanc), | 721 orthanc_(orthanc), |
723 state_(State_Initialization) | 722 state_(State_Initialization) |
724 { | 723 { |
725 } | 724 SignalGeometryReady.connect(OrthancSlicesLoader::IObserver::SignalGeometryReadyType::slot_type(&OrthancSlicesLoader::IObserver::NotifyGeometryReady, observer.get(), _1).track(observer)); |
726 | 725 SignalGeometryError.connect(OrthancSlicesLoader::IObserver::SignalGeometryErrorType::slot_type(&OrthancSlicesLoader::IObserver::NotifyGeometryError, observer.get(), _1).track(observer)); |
727 | 726 SignalSliceImageReady.connect(OrthancSlicesLoader::IObserver::SignalSliceImageReadyType::slot_type(&OrthancSlicesLoader::IObserver::NotifySliceImageReady, observer.get(), _1, _2, _3, _4, _5).track(observer)); |
728 void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId) | 727 SignalSliceImageError.connect(OrthancSlicesLoader::IObserver::SignalSliceImageErrorType::slot_type(&OrthancSlicesLoader::IObserver::NotifySliceImageError, observer.get(), _1, _2, _3, _4).track(observer)); |
728 } | |
729 | |
730 | |
731 void OrthancSlicesLoader::ScheduleLoadSeries(boost::shared_ptr<boost::noncopyable> tracker, const std::string& seriesId) | |
729 { | 732 { |
730 if (state_ != State_Initialization) | 733 if (state_ != State_Initialization) |
731 { | 734 { |
732 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 735 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
733 } | 736 } |
734 else | 737 else |
735 { | 738 { |
736 state_ = State_LoadingGeometry; | 739 state_ = State_LoadingGeometry; |
737 std::string uri = "/series/" + seriesId + "/instances-tags"; | 740 std::string uri = "/series/" + seriesId + "/instances-tags"; |
738 orthanc_.ScheduleGetRequest(*webCallback_, uri, Operation::DownloadSeriesGeometry()); | 741 orthanc_.ScheduleGetRequest(this, tracker, uri, Operation::DownloadSeriesGeometry()); |
739 } | 742 } |
740 } | 743 } |
741 | 744 |
742 | 745 |
743 void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId) | 746 void OrthancSlicesLoader::ScheduleLoadInstance(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId) |
744 { | 747 { |
745 if (state_ != State_Initialization) | 748 if (state_ != State_Initialization) |
746 { | 749 { |
747 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 750 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
748 } | 751 } |
752 | 755 |
753 // Tag "3004-000c" is "Grid Frame Offset Vector", which is | 756 // Tag "3004-000c" is "Grid Frame Offset Vector", which is |
754 // mandatory to read RT DOSE, but is too long to be returned by default | 757 // mandatory to read RT DOSE, but is too long to be returned by default |
755 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3004-000c"; | 758 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3004-000c"; |
756 orthanc_.ScheduleGetRequest | 759 orthanc_.ScheduleGetRequest |
757 (*webCallback_, uri, Operation::DownloadInstanceGeometry(instanceId)); | 760 (this, tracker, uri, Operation::DownloadInstanceGeometry(instanceId)); |
758 } | 761 } |
759 } | 762 } |
760 | 763 |
761 | 764 |
762 void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId, | 765 void OrthancSlicesLoader::ScheduleLoadFrame(boost::shared_ptr<boost::noncopyable> tracker, const std::string& instanceId, |
763 unsigned int frame) | 766 unsigned int frame) |
764 { | 767 { |
765 if (state_ != State_Initialization) | 768 if (state_ != State_Initialization) |
766 { | 769 { |
767 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 770 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
769 else | 772 else |
770 { | 773 { |
771 state_ = State_LoadingGeometry; | 774 state_ = State_LoadingGeometry; |
772 std::string uri = "/instances/" + instanceId + "/tags"; | 775 std::string uri = "/instances/" + instanceId + "/tags"; |
773 orthanc_.ScheduleGetRequest | 776 orthanc_.ScheduleGetRequest |
774 (*webCallback_, uri, Operation::DownloadFrameGeometry(instanceId, frame)); | 777 (this, tracker, uri, Operation::DownloadFrameGeometry(instanceId, frame)); |
775 } | 778 } |
776 } | 779 } |
777 | 780 |
778 | 781 |
779 bool OrthancSlicesLoader::IsGeometryReady() const | 782 bool OrthancSlicesLoader::IsGeometryReady() const |
814 | 817 |
815 return slices_.LookupSlice(index, plane); | 818 return slices_.LookupSlice(index, plane); |
816 } | 819 } |
817 | 820 |
818 | 821 |
819 void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice, | 822 void OrthancSlicesLoader::ScheduleSliceImagePng(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice, |
820 size_t index) | 823 size_t index) |
821 { | 824 { |
822 std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + | 825 std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + |
823 boost::lexical_cast<std::string>(slice.GetFrame())); | 826 boost::lexical_cast<std::string>(slice.GetFrame())); |
824 | 827 |
838 | 841 |
839 default: | 842 default: |
840 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 843 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
841 } | 844 } |
842 | 845 |
843 orthanc_.ScheduleGetRequest(*webCallback_, uri, | 846 orthanc_.ScheduleGetRequest(this, tracker, uri, |
844 Operation::DownloadSliceImage(index, slice, SliceImageQuality_Full)); | 847 Operation::DownloadSliceImage(index, slice, SliceImageQuality_Full)); |
845 } | 848 } |
846 | 849 |
847 | 850 |
848 void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice, | 851 void OrthancSlicesLoader::ScheduleSliceImageJpeg(boost::shared_ptr<boost::noncopyable> tracker, const Slice& slice, |
849 size_t index, | 852 size_t index, |
850 SliceImageQuality quality) | 853 SliceImageQuality quality) |
851 { | 854 { |
852 unsigned int value; | 855 unsigned int value; |
853 | 856 |
873 std::string uri = ("/web-viewer/instances/jpeg" + | 876 std::string uri = ("/web-viewer/instances/jpeg" + |
874 boost::lexical_cast<std::string>(value) + | 877 boost::lexical_cast<std::string>(value) + |
875 "-" + slice.GetOrthancInstanceId() + "_" + | 878 "-" + slice.GetOrthancInstanceId() + "_" + |
876 boost::lexical_cast<std::string>(slice.GetFrame())); | 879 boost::lexical_cast<std::string>(slice.GetFrame())); |
877 | 880 |
878 orthanc_.ScheduleGetRequest(*webCallback_, uri, | 881 orthanc_.ScheduleGetRequest(this, tracker, uri, |
879 Operation::DownloadSliceImage(index, slice, quality)); | 882 Operation::DownloadSliceImage(index, slice, quality)); |
880 } | 883 } |
881 | 884 |
882 | 885 |
883 | 886 |
884 void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index, | 887 void OrthancSlicesLoader::ScheduleLoadSliceImage(boost::shared_ptr<boost::noncopyable> tracker, size_t index, |
885 SliceImageQuality quality) | 888 SliceImageQuality quality) |
886 { | 889 { |
887 if (state_ != State_GeometryReady) | 890 if (state_ != State_GeometryReady) |
888 { | 891 { |
889 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 892 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
893 | 896 |
894 if (slice.HasOrthancDecoding()) | 897 if (slice.HasOrthancDecoding()) |
895 { | 898 { |
896 if (quality == SliceImageQuality_Full) | 899 if (quality == SliceImageQuality_Full) |
897 { | 900 { |
898 ScheduleSliceImagePng(slice, index); | 901 ScheduleSliceImagePng(tracker, slice, index); |
899 } | 902 } |
900 else | 903 else |
901 { | 904 { |
902 ScheduleSliceImageJpeg(slice, index, quality); | 905 ScheduleSliceImageJpeg(tracker, slice, index, quality); |
903 } | 906 } |
904 } | 907 } |
905 else | 908 else |
906 { | 909 { |
907 std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + | 910 std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + |
908 boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz"); | 911 boost::lexical_cast<std::string>(slice.GetFrame()) + "/raw.gz"); |
909 orthanc_.ScheduleGetRequest(*webCallback_, uri, | 912 orthanc_.ScheduleGetRequest(this, tracker, uri, |
910 Operation::DownloadSliceRawImage(index, slice)); | 913 Operation::DownloadSliceRawImage(index, slice)); |
911 } | 914 } |
912 } | 915 } |
913 } | 916 } |