comparison Samples/Sdl/Loader.cpp @ 757:f7c236894c1a

cont
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 22 May 2019 17:05:14 +0200
parents ab236bb5dbc7
children 774681b2c77c
comparison
equal deleted inserted replaced
749:f3a7092ed10e 757:f7c236894c1a
24 #include "../../Framework/Oracle/GetOrthancWebViewerJpegCommand.h" 24 #include "../../Framework/Oracle/GetOrthancWebViewerJpegCommand.h"
25 #include "../../Framework/Oracle/GetOrthancImageCommand.h" 25 #include "../../Framework/Oracle/GetOrthancImageCommand.h"
26 #include "../../Framework/Oracle/OrthancRestApiCommand.h" 26 #include "../../Framework/Oracle/OrthancRestApiCommand.h"
27 #include "../../Framework/Oracle/SleepOracleCommand.h" 27 #include "../../Framework/Oracle/SleepOracleCommand.h"
28 #include "../../Framework/Oracle/OracleCommandExceptionMessage.h" 28 #include "../../Framework/Oracle/OracleCommandExceptionMessage.h"
29 #include "../../Framework/Messages/IMessageEmitter.h"
30 #include "../../Framework/Oracle/OracleCommandWithPayload.h"
31 #include "../../Framework/Oracle/IOracle.h"
32 29
33 // From Stone 30 // From Stone
34 #include "../../Framework/Loaders/BasicFetchingItemsSorter.h" 31 #include "../../Framework/Loaders/BasicFetchingItemsSorter.h"
35 #include "../../Framework/Loaders/BasicFetchingStrategy.h" 32 #include "../../Framework/Loaders/BasicFetchingStrategy.h"
36 #include "../../Framework/Scene2D/Scene2D.h" 33 #include "../../Framework/Scene2D/Scene2D.h"
39 #include "../../Framework/Toolbox/SlicesSorter.h" 36 #include "../../Framework/Toolbox/SlicesSorter.h"
40 #include "../../Framework/Volumes/ImageBuffer3D.h" 37 #include "../../Framework/Volumes/ImageBuffer3D.h"
41 #include "../../Framework/Volumes/VolumeImageGeometry.h" 38 #include "../../Framework/Volumes/VolumeImageGeometry.h"
42 39
43 // From Orthanc framework 40 // From Orthanc framework
44 #include <Core/Compression/GzipCompressor.h>
45 #include <Core/Compression/ZlibCompressor.h>
46 #include <Core/DicomFormat/DicomArray.h>
47 #include <Core/DicomFormat/DicomImageInformation.h>
48 #include <Core/HttpClient.h>
49 #include <Core/IDynamicObject.h>
50 #include <Core/Images/ImageProcessing.h> 41 #include <Core/Images/ImageProcessing.h>
51 #include <Core/Logging.h> 42 #include <Core/Logging.h>
52 #include <Core/MultiThreading/SharedMessageQueue.h>
53 #include <Core/OrthancException.h> 43 #include <Core/OrthancException.h>
54 #include <Core/SystemToolbox.h> 44 #include <Core/SystemToolbox.h>
55 #include <Core/Toolbox.h>
56
57 #include <json/reader.h>
58 #include <json/value.h>
59 #include <json/writer.h>
60
61 #include <list>
62 #include <stdio.h>
63
64 45
65 46
66 namespace OrthancStone 47 namespace OrthancStone
67 { 48 {
68 class DicomVolumeImage : public boost::noncopyable 49 static bool IsSameCuttingPlane(const CoordinateSystem3D& a,
50 const CoordinateSystem3D& b)
51 {
52 double distance;
53 return (CoordinateSystem3D::ComputeDistance(distance, a, b) &&
54 LinearAlgebra::IsCloseToZero(distance));
55 }
56
57
58 class IVolumeSlicer : public boost::noncopyable
59 {
60 public:
61 class ExtractedSlice : public boost::noncopyable
62 {
63 public:
64 virtual ~ExtractedSlice()
65 {
66 }
67
68 virtual bool IsValid() = 0;
69
70 // Must be a cheap call
71 virtual uint64_t GetRevision() = 0;
72
73 // This call can take some time
74 virtual ISceneLayer* CreateSceneLayer() = 0;
75 };
76
77 virtual ~IVolumeSlicer()
78 {
79 }
80
81 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const = 0;
82 };
83
84
85
86 class DicomVolumeImageOrthogonalSlice : public IVolumeSlicer::ExtractedSlice
69 { 87 {
70 private: 88 private:
89 CoordinateSystem3D cuttingPlane_;
90 bool isInitialized_;
91 bool valid_;
92 VolumeProjection projection_;
93 unsigned int sliceIndex_;
94 uint64_t revision_;
95
96 void Initialize()
97 {
98 if (!isInitialized_)
99 {
100 valid_ = DetectSlice(projection_, sliceIndex_, revision_, cuttingPlane_);
101 isInitialized_ = true;
102 }
103 }
104
105 protected:
106 virtual const ImageBuffer3D& GetImage() const = 0;
107
108 virtual const VolumeImageGeometry& GetGeometry() const = 0;
109
110 // WARNING - This cannot be invoked from the constructor, hence lazy "Initialize()"
111 virtual bool DetectSlice(VolumeProjection& projection,
112 unsigned int& sliceIndex,
113 uint64_t& revision,
114 const CoordinateSystem3D& cuttingPlane) const = 0;
115
116 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection,
117 unsigned int sliceIndex) const = 0;
118
119 public:
120 DicomVolumeImageOrthogonalSlice(const CoordinateSystem3D& cuttingPlane) :
121 cuttingPlane_(cuttingPlane),
122 isInitialized_(false)
123 {
124 }
125
126 virtual bool IsValid()
127 {
128 Initialize();
129
130 return valid_;
131 }
132
133 virtual uint64_t GetRevision()
134 {
135 Initialize();
136
137 if (!valid_)
138 {
139 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
140 }
141 else
142 {
143 return revision_;
144 }
145 }
146
147 virtual ISceneLayer* CreateSceneLayer()
148 {
149 Initialize();
150
151 if (!valid_)
152 {
153 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
154 }
155 else
156 {
157 std::auto_ptr<TextureBaseSceneLayer> texture;
158
159 {
160 ImageBuffer3D::SliceReader reader(GetImage(), projection_, sliceIndex_);
161 texture.reset(GetDicomParameters(projection_, sliceIndex_).CreateTexture(reader.GetAccessor()));
162 }
163
164 const CoordinateSystem3D& system = GetGeometry().GetProjectionGeometry(projection_);
165
166 double x0, y0, x1, y1;
167 system.ProjectPoint(x0, y0, system.GetOrigin());
168 system.ProjectPoint(x1, y1, system.GetOrigin() + system.GetAxisX());
169 texture->SetOrigin(x0, y0);
170
171 double dx = x1 - x0;
172 double dy = y1 - y0;
173 if (!LinearAlgebra::IsCloseToZero(dx) ||
174 !LinearAlgebra::IsCloseToZero(dy))
175 {
176 texture->SetAngle(atan2(dy, dx));
177 }
178
179 Vector tmp;
180 GetGeometry().GetVoxelDimensions(projection_);
181 texture->SetPixelSpacing(tmp[0], tmp[1]);
182
183 // texture->SetLinearInterpolation(linearInterpolation_); // TODO
184
185 return texture.release();
186 }
187 }
188 };
189
190
191 // This class combines a 3D image buffer, a 3D volume geometry and
192 // information about the DICOM parameters of each slice.
193 class DicomSeriesVolumeImage : public IVolumeSlicer
194 {
195 private:
196 class Slice : public DicomVolumeImageOrthogonalSlice
197 {
198 private:
199 const DicomSeriesVolumeImage& that_;
200
201 protected:
202 virtual const ImageBuffer3D& GetImage() const
203 {
204 return that_.GetImage();
205 }
206
207 virtual const VolumeImageGeometry& GetGeometry() const
208 {
209 return that_.GetGeometry();
210 }
211
212 virtual bool DetectSlice(VolumeProjection& projection,
213 unsigned int& sliceIndex,
214 uint64_t& revision,
215 const CoordinateSystem3D& cuttingPlane) const
216 {
217 if (!that_.HasGeometry() ||
218 !that_.GetGeometry().DetectSlice(projection, sliceIndex, cuttingPlane))
219 {
220 return false;
221 }
222 else
223 {
224 if (projection == VolumeProjection_Axial)
225 {
226 revision = that_.GetSliceRevision(sliceIndex);
227 }
228 else
229 {
230 // For coronal and sagittal projections, we take the global
231 // revision of the volume
232 revision = that_.GetRevision();
233 }
234
235 return true;
236 }
237 }
238
239 virtual const DicomInstanceParameters& GetDicomParameters(VolumeProjection projection,
240 unsigned int sliceIndex) const
241 {
242 return that_.GetSliceParameters(projection == VolumeProjection_Axial ? sliceIndex : 0);
243 }
244
245 public:
246 Slice(const DicomSeriesVolumeImage& that,
247 const CoordinateSystem3D& plane) :
248 DicomVolumeImageOrthogonalSlice(plane),
249 that_(that)
250 {
251 }
252 };
253
254
71 std::auto_ptr<ImageBuffer3D> image_; 255 std::auto_ptr<ImageBuffer3D> image_;
72 std::auto_ptr<VolumeImageGeometry> geometry_; 256 std::auto_ptr<VolumeImageGeometry> geometry_;
73 std::vector<DicomInstanceParameters*> slices_; 257 std::vector<DicomInstanceParameters*> slices_;
74 uint64_t revision_; 258 uint64_t revision_;
75 std::vector<uint64_t> slicesRevision_; 259 std::vector<uint64_t> slicesRevision_;
166 } 350 }
167 } 351 }
168 352
169 353
170 public: 354 public:
171 DicomVolumeImage() 355 DicomSeriesVolumeImage()
172 { 356 {
173 } 357 }
174 358
175 ~DicomVolumeImage() 359 ~DicomSeriesVolumeImage()
176 { 360 {
177 Clear(); 361 Clear();
178 } 362 }
179 363
180 // WARNING: The payload of "slices" must be of class "DicomInstanceParameters" 364 // WARNING: The payload of "slices" must be of class "DicomInstanceParameters"
308 492
309 revision_ ++; 493 revision_ ++;
310 slicesRevision_[index] += 1; 494 slicesRevision_[index] += 1;
311 } 495 }
312 } 496 }
497
498 virtual IVolumeSlicer::ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const
499 {
500 return new Slice(*this, cuttingPlane);
501 }
313 }; 502 };
314 503
315 504
316 505
506 // This class combines a 3D DICOM volume together with its loader
317 class IDicomVolumeImageSource : public boost::noncopyable 507 class IDicomVolumeImageSource : public boost::noncopyable
318 { 508 {
319 public: 509 public:
320 virtual ~IDicomVolumeImageSource() 510 virtual ~IDicomVolumeImageSource()
321 { 511 {
322 } 512 }
323 513
324 virtual const DicomVolumeImage& GetVolume() const = 0; 514 virtual const DicomSeriesVolumeImage& GetVolume() const = 0;
325 515
326 virtual void NotifyAxialSliceAccessed(unsigned int sliceIndex) = 0; 516 virtual void NotifyAxialSliceAccessed(unsigned int sliceIndex) = 0;
327 }; 517 };
328 518
329 519
330 520
331 class VolumeSeriesOrthancLoader : 521 class OrthancSeriesVolumeProgressiveLoader :
332 public IObserver, 522 public IObserver,
333 public IDicomVolumeImageSource 523 public IDicomVolumeImageSource
334 { 524 {
335 private: 525 private:
336 static const unsigned int LOW_QUALITY = 0; 526 static const unsigned int LOW_QUALITY = 0;
420 } 610 }
421 611
422 if (volume_.GetSlicesCount() != 0) 612 if (volume_.GetSlicesCount() != 0)
423 { 613 {
424 strategy_.reset(new BasicFetchingStrategy( 614 strategy_.reset(new BasicFetchingStrategy(
425 new BasicFetchingItemsSorter(volume_.GetSlicesCount()), BEST_QUALITY)); 615 sorter_->CreateSorter(volume_.GetSlicesCount()), BEST_QUALITY));
426 616
427 for (unsigned int i = 0; i < 4; i++) // Schedule up to 4 simultaneous downloads (TODO - parameter) 617 assert(simultaneousDownloads_ != 0);
618 for (unsigned int i = 0; i < simultaneousDownloads_; i++)
428 { 619 {
429 ScheduleNextSliceDownload(); 620 ScheduleNextSliceDownload();
430 } 621 }
431 } 622 }
432 } 623 }
465 } 656 }
466 657
467 658
468 IOracle& oracle_; 659 IOracle& oracle_;
469 bool active_; 660 bool active_;
470 DicomVolumeImage volume_; 661 DicomSeriesVolumeImage volume_;
471 662 unsigned int simultaneousDownloads_;
472 std::auto_ptr<IFetchingStrategy> strategy_; 663
664 std::auto_ptr<IFetchingItemsSorter::IFactory> sorter_;
665 std::auto_ptr<IFetchingStrategy> strategy_;
473 666
474 public: 667 public:
475 VolumeSeriesOrthancLoader(IOracle& oracle, 668 OrthancSeriesVolumeProgressiveLoader(IOracle& oracle,
476 IObservable& oracleObservable) : 669 IObservable& oracleObservable) :
477 IObserver(oracleObservable.GetBroker()), 670 IObserver(oracleObservable.GetBroker()),
478 oracle_(oracle), 671 oracle_(oracle),
479 active_(false) 672 active_(false),
673 simultaneousDownloads_(4),
674 sorter_(new BasicFetchingItemsSorter::Factory)
480 { 675 {
481 oracleObservable.RegisterObserverCallback( 676 oracleObservable.RegisterObserverCallback(
482 new Callable<VolumeSeriesOrthancLoader, OrthancRestApiCommand::SuccessMessage> 677 new Callable<OrthancSeriesVolumeProgressiveLoader, OrthancRestApiCommand::SuccessMessage>
483 (*this, &VolumeSeriesOrthancLoader::LoadGeometry)); 678 (*this, &OrthancSeriesVolumeProgressiveLoader::LoadGeometry));
484 679
485 oracleObservable.RegisterObserverCallback( 680 oracleObservable.RegisterObserverCallback(
486 new Callable<VolumeSeriesOrthancLoader, GetOrthancImageCommand::SuccessMessage> 681 new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancImageCommand::SuccessMessage>
487 (*this, &VolumeSeriesOrthancLoader::LoadBestQualitySliceContent)); 682 (*this, &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent));
488 683
489 oracleObservable.RegisterObserverCallback( 684 oracleObservable.RegisterObserverCallback(
490 new Callable<VolumeSeriesOrthancLoader, GetOrthancWebViewerJpegCommand::SuccessMessage> 685 new Callable<OrthancSeriesVolumeProgressiveLoader, GetOrthancWebViewerJpegCommand::SuccessMessage>
491 (*this, &VolumeSeriesOrthancLoader::LoadJpegSliceContent)); 686 (*this, &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent));
687 }
688
689 void SetSimultaneousDownloads(unsigned int count)
690 {
691 if (active_)
692 {
693 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
694 }
695 else if (count == 0)
696 {
697 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
698 }
699 else
700 {
701 simultaneousDownloads_ = count;
702 }
492 } 703 }
493 704
494 void LoadSeries(const std::string& seriesId) 705 void LoadSeries(const std::string& seriesId)
495 { 706 {
496 if (active_) 707 if (active_)
497 { 708 {
498 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 709 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
499 } 710 }
500 711 else
501 active_ = true; 712 {
502 713 active_ = true;
503 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); 714
504 command->SetUri("/series/" + seriesId + "/instances-tags"); 715 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
505 716 command->SetUri("/series/" + seriesId + "/instances-tags");
506 oracle_.Schedule(*this, command.release()); 717
718 oracle_.Schedule(*this, command.release());
719 }
507 } 720 }
508 721
509 722
510 virtual const DicomVolumeImage& GetVolume() const 723 virtual const DicomSeriesVolumeImage& GetVolume() const
511 { 724 {
512 return volume_; 725 return volume_;
513 } 726 }
514 727
515 728
551 oracle_.Schedule(*this, command.release()); 764 oracle_.Schedule(*this, command.release());
552 } 765 }
553 #endif 766 #endif
554 767
555 768
556 /* class VolumeSlicerBase : public IVolumeSlicer 769 /* class VolumeSlicerBase : public OLD_IVolumeSlicer
557 { 770 {
558 private: 771 private:
559 Scene2D& scene_; 772 Scene2D& scene_;
560 int layerDepth_; 773 int layerDepth_;
561 bool first_; 774 bool first_;
562 CoordinateSystem3D lastPlane_; 775 CoordinateSystem3D lastPlane_;
563 776
564 protected: 777 protected:
565 bool HasViewportPlaneChanged(const CoordinateSystem3D& plane) const 778 bool HasCuttingPlaneChanged(const CoordinateSystem3D& plane) const
566 { 779 {
567 if (first_ || 780 if (first_ ||
568 !LinearAlgebra::IsCloseToZero( 781 !LinearAlgebra::IsCloseToZero(
569 boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal()))) 782 boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal())))
570 { 783 {
577 double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin()); 790 double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin());
578 return LinearAlgebra::IsCloseToZero(offset2 - offset1); 791 return LinearAlgebra::IsCloseToZero(offset2 - offset1);
579 } 792 }
580 } 793 }
581 794
582 void SetLastViewportPlane(const CoordinateSystem3D& plane) 795 void SetLastCuttingPlane(const CoordinateSystem3D& plane)
583 { 796 {
584 first_ = false; 797 first_ = false;
585 lastPlane_ = plane; 798 lastPlane_ = plane;
586 } 799 }
587 800
605 } 818 }
606 };*/ 819 };*/
607 820
608 821
609 822
610 class IVolumeSlicer : public boost::noncopyable 823 class OLD_IVolumeSlicer : public boost::noncopyable
611 { 824 {
612 public: 825 public:
613 virtual ~IVolumeSlicer() 826 virtual ~OLD_IVolumeSlicer()
614 { 827 {
615 } 828 }
616 829
617 virtual void SetViewportPlane(const CoordinateSystem3D& plane) = 0; 830 virtual void SetCuttingPlane(Scene2D& scene,
831 const CoordinateSystem3D& plane) = 0;
618 }; 832 };
619 833
620 834
621 class DicomVolumeMPRSlicer : public IVolumeSlicer 835 class DicomVolumeMPRSlicer : public OLD_IVolumeSlicer
622 { 836 {
623 private: 837 private:
624 bool linearInterpolation_; 838 bool linearInterpolation_;
625 Scene2D& scene_;
626 int layerDepth_; 839 int layerDepth_;
627 IDicomVolumeImageSource& source_; 840 IDicomVolumeImageSource& source_;
628 bool first_; 841 bool first_;
629 VolumeProjection lastProjection_; 842 VolumeProjection lastProjection_;
630 unsigned int lastSliceIndex_; 843 unsigned int lastSliceIndex_;
633 public: 846 public:
634 DicomVolumeMPRSlicer(Scene2D& scene, 847 DicomVolumeMPRSlicer(Scene2D& scene,
635 int layerDepth, 848 int layerDepth,
636 IDicomVolumeImageSource& source) : 849 IDicomVolumeImageSource& source) :
637 linearInterpolation_(false), 850 linearInterpolation_(false),
638 scene_(scene),
639 layerDepth_(layerDepth), 851 layerDepth_(layerDepth),
640 source_(source), 852 source_(source),
641 first_(true) 853 first_(true)
642 { 854 {
643 } 855 }
650 bool IsLinearInterpolation() const 862 bool IsLinearInterpolation() const
651 { 863 {
652 return linearInterpolation_; 864 return linearInterpolation_;
653 } 865 }
654 866
655 virtual void SetViewportPlane(const CoordinateSystem3D& plane) 867 virtual void SetCuttingPlane(Scene2D& scene,
868 const CoordinateSystem3D& plane)
656 { 869 {
657 if (!source_.GetVolume().HasGeometry() || 870 if (!source_.GetVolume().HasGeometry() ||
658 source_.GetVolume().GetSlicesCount() == 0) 871 source_.GetVolume().GetSlicesCount() == 0)
659 { 872 {
660 scene_.DeleteLayer(layerDepth_); 873 scene.DeleteLayer(layerDepth_);
661 return; 874 return;
662 } 875 }
663 876
664 const VolumeImageGeometry& geometry = source_.GetVolume().GetGeometry(); 877 const VolumeImageGeometry& geometry = source_.GetVolume().GetGeometry();
665 878
667 unsigned int sliceIndex; 880 unsigned int sliceIndex;
668 if (!geometry.DetectSlice(projection, sliceIndex, plane)) 881 if (!geometry.DetectSlice(projection, sliceIndex, plane))
669 { 882 {
670 // The cutting plane is neither axial, nor coronal, nor 883 // The cutting plane is neither axial, nor coronal, nor
671 // sagittal. Could use "VolumeReslicer" here. 884 // sagittal. Could use "VolumeReslicer" here.
672 scene_.DeleteLayer(layerDepth_); 885 scene.DeleteLayer(layerDepth_);
673 return; 886 return;
674 } 887 }
675 888
676 uint64_t sliceRevision; 889 uint64_t sliceRevision;
677 if (projection == VolumeProjection_Axial) 890 if (projection == VolumeProjection_Axial)
695 if (first_ || 908 if (first_ ||
696 lastProjection_ != projection || 909 lastProjection_ != projection ||
697 lastSliceIndex_ != sliceIndex || 910 lastSliceIndex_ != sliceIndex ||
698 lastSliceRevision_ != sliceRevision) 911 lastSliceRevision_ != sliceRevision)
699 { 912 {
700 // Either the viewport plane, or the content of the slice have not 913 // Either the cutting plane, or the content of the slice have not
701 // changed since the last time the layer was set: Update is needed 914 // changed since the last time the layer was set: Update is needed
702 915
703 first_ = false; 916 first_ = false;
704 lastProjection_ = projection; 917 lastProjection_ = projection;
705 lastSliceIndex_ = sliceIndex; 918 lastSliceIndex_ = sliceIndex;
734 geometry.GetVoxelDimensions(projection); 947 geometry.GetVoxelDimensions(projection);
735 texture->SetPixelSpacing(tmp[0], tmp[1]); 948 texture->SetPixelSpacing(tmp[0], tmp[1]);
736 949
737 texture->SetLinearInterpolation(linearInterpolation_); 950 texture->SetLinearInterpolation(linearInterpolation_);
738 951
739 scene_.SetLayer(layerDepth_, texture.release()); 952 scene.SetLayer(layerDepth_, texture.release());
740 } 953 }
741 } 954 }
742 }; 955 };
743 956
744 957
885 1098
886 void Run(OrthancStone::NativeApplicationContext& context, 1099 void Run(OrthancStone::NativeApplicationContext& context,
887 OrthancStone::IOracle& oracle) 1100 OrthancStone::IOracle& oracle)
888 { 1101 {
889 std::auto_ptr<Toto> toto; 1102 std::auto_ptr<Toto> toto;
890 std::auto_ptr<OrthancStone::VolumeSeriesOrthancLoader> loader1, loader2; 1103 std::auto_ptr<OrthancStone::OrthancSeriesVolumeProgressiveLoader> loader1, loader2;
891 1104
892 { 1105 {
893 OrthancStone::NativeApplicationContext::WriterLock lock(context); 1106 OrthancStone::NativeApplicationContext::WriterLock lock(context);
894 toto.reset(new Toto(lock.GetOracleObservable())); 1107 toto.reset(new Toto(lock.GetOracleObservable()));
895 loader1.reset(new OrthancStone::VolumeSeriesOrthancLoader(oracle, lock.GetOracleObservable())); 1108 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable()));
896 loader2.reset(new OrthancStone::VolumeSeriesOrthancLoader(oracle, lock.GetOracleObservable())); 1109 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable()));
897 } 1110 }
898 1111
899 if (0) 1112 if (0)
900 { 1113 {
901 Json::Value v = Json::objectValue; 1114 Json::Value v = Json::objectValue;