Mercurial > hg > orthanc-stone
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; |