Mercurial > hg > orthanc-stone
comparison Framework/dev.h @ 405:3942123602ba
removing ObserversRegistry
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 11 Nov 2018 17:50:11 +0100 |
parents | 72355b637945 |
children | 5d359b115b29 |
comparison
equal
deleted
inserted
replaced
404:ba4ace20454e | 405:3942123602ba |
---|---|
26 #include "Layers/SliceOutlineRenderer.h" | 26 #include "Layers/SliceOutlineRenderer.h" |
27 #include "Toolbox/DownloadStack.h" | 27 #include "Toolbox/DownloadStack.h" |
28 #include "Toolbox/GeometryToolbox.h" | 28 #include "Toolbox/GeometryToolbox.h" |
29 #include "Toolbox/OrthancSlicesLoader.h" | 29 #include "Toolbox/OrthancSlicesLoader.h" |
30 #include "Volumes/ImageBuffer3D.h" | 30 #include "Volumes/ImageBuffer3D.h" |
31 #include "Volumes/SlicedVolumeBase.h" | 31 #include "Volumes/ISlicedVolume.h" |
32 #include "Widgets/SliceViewerWidget.h" | 32 #include "Widgets/SliceViewerWidget.h" |
33 | 33 |
34 #include <Core/Logging.h> | 34 #include <Core/Logging.h> |
35 #include <Core/Images/ImageProcessing.h> | 35 #include <Core/Images/ImageProcessing.h> |
36 #include <Core/OrthancException.h> | |
36 | 37 |
37 #include <boost/math/special_functions/round.hpp> | 38 #include <boost/math/special_functions/round.hpp> |
38 | 39 |
39 | 40 |
40 namespace OrthancStone | 41 namespace OrthancStone |
41 { | 42 { |
42 // TODO: Handle errors while loading | 43 // TODO: Handle errors while loading |
43 class OrthancVolumeImage : | 44 class OrthancVolumeImage : |
44 public SlicedVolumeBase, | 45 public ISlicedVolume, |
45 public OrthancStone::IObserver | 46 public IObserver |
46 { | 47 { |
47 private: | 48 private: |
48 OrthancSlicesLoader loader_; | 49 OrthancSlicesLoader loader_; |
49 std::auto_ptr<ImageBuffer3D> image_; | 50 std::auto_ptr<ImageBuffer3D> image_; |
50 std::auto_ptr<DownloadStack> downloadStack_; | 51 std::auto_ptr<DownloadStack> downloadStack_; |
108 void OnSliceGeometryReady(const OrthancSlicesLoader& loader) | 109 void OnSliceGeometryReady(const OrthancSlicesLoader& loader) |
109 { | 110 { |
110 if (loader.GetSliceCount() == 0) | 111 if (loader.GetSliceCount() == 0) |
111 { | 112 { |
112 LOG(ERROR) << "Empty volume image"; | 113 LOG(ERROR) << "Empty volume image"; |
113 SlicedVolumeBase::NotifyGeometryError(); | 114 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
114 return; | 115 return; |
115 } | 116 } |
116 | 117 |
117 for (size_t i = 1; i < loader.GetSliceCount(); i++) | 118 for (size_t i = 1; i < loader.GetSliceCount(); i++) |
118 { | 119 { |
119 if (!IsCompatible(loader.GetSlice(0), loader.GetSlice(i))) | 120 if (!IsCompatible(loader.GetSlice(0), loader.GetSlice(i))) |
120 { | 121 { |
121 SlicedVolumeBase::NotifyGeometryError(); | 122 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
122 return; | 123 return; |
123 } | 124 } |
124 } | 125 } |
125 | 126 |
126 double spacingZ; | 127 double spacingZ; |
140 { | 141 { |
141 if (!LinearAlgebra::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)), | 142 if (!LinearAlgebra::IsNear(spacingZ, GetDistance(loader.GetSlice(i - 1), loader.GetSlice(i)), |
142 0.001 /* this is expressed in mm */)) | 143 0.001 /* this is expressed in mm */)) |
143 { | 144 { |
144 LOG(ERROR) << "The distance between successive slices is not constant in a volume image"; | 145 LOG(ERROR) << "The distance between successive slices is not constant in a volume image"; |
145 SlicedVolumeBase::NotifyGeometryError(); | 146 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
146 return; | 147 return; |
147 } | 148 } |
148 } | 149 } |
149 | 150 |
150 unsigned int width = loader.GetSlice(0).GetWidth(); | 151 unsigned int width = loader.GetSlice(0).GetWidth(); |
167 ScheduleSliceDownload(); | 168 ScheduleSliceDownload(); |
168 } | 169 } |
169 | 170 |
170 // TODO Check the DicomFrameConverter are constant | 171 // TODO Check the DicomFrameConverter are constant |
171 | 172 |
172 SlicedVolumeBase::NotifyGeometryReady(); | 173 EmitMessage(ISlicedVolume::GeometryReadyMessage(*this)); |
173 } | 174 } |
174 | 175 |
175 virtual void OnSliceImageReady(const OrthancSlicesLoader& loader, | 176 void OnSliceImageReady(const OrthancSlicesLoader& loader, |
176 unsigned int sliceIndex, | 177 unsigned int sliceIndex, |
177 const Slice& slice, | 178 const Slice& slice, |
178 const Orthanc::ImageAccessor& image, | 179 const Orthanc::ImageAccessor& image, |
179 SliceImageQuality quality) | 180 SliceImageQuality quality) |
180 { | 181 { |
181 { | 182 { |
182 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex); | 183 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex); |
183 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); | 184 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image); |
184 } | 185 } |
185 | 186 |
186 SlicedVolumeBase::NotifySliceContentChange(sliceIndex, slice); | 187 EmitMessage(ISlicedVolume::SliceContentChangedMessage(*this, sliceIndex, slice)); |
187 | 188 |
188 if (pendingSlices_ == 1) | 189 if (pendingSlices_ == 1) |
189 { | 190 { |
190 SlicedVolumeBase::NotifyVolumeReady(); | 191 EmitMessage(ISlicedVolume::VolumeReadyMessage(*this)); |
191 pendingSlices_ = 0; | 192 pendingSlices_ = 0; |
192 } | 193 } |
193 else if (pendingSlices_ > 1) | 194 else if (pendingSlices_ > 1) |
194 { | 195 { |
195 pendingSlices_ -= 1; | 196 pendingSlices_ -= 1; |
206 OnSliceGeometryReady(dynamic_cast<const OrthancSlicesLoader&>(from)); | 207 OnSliceGeometryReady(dynamic_cast<const OrthancSlicesLoader&>(from)); |
207 break; | 208 break; |
208 | 209 |
209 case MessageType_SliceLoader_GeometryError: | 210 case MessageType_SliceLoader_GeometryError: |
210 LOG(ERROR) << "Unable to download a volume image"; | 211 LOG(ERROR) << "Unable to download a volume image"; |
211 SlicedVolumeBase::NotifyGeometryError(); | 212 EmitMessage(ISlicedVolume::GeometryErrorMessage(*this)); |
212 break; | 213 break; |
213 | 214 |
214 case MessageType_SliceLoader_ImageReady: | 215 case MessageType_SliceLoader_ImageReady: |
215 { | 216 { |
216 const OrthancSlicesLoader::SliceImageReadyMessage& msg = | 217 const OrthancSlicesLoader::SliceImageReadyMessage& msg = |
239 | 240 |
240 public: | 241 public: |
241 OrthancVolumeImage(MessageBroker& broker, | 242 OrthancVolumeImage(MessageBroker& broker, |
242 OrthancApiClient& orthanc, | 243 OrthancApiClient& orthanc, |
243 bool computeRange) : | 244 bool computeRange) : |
244 OrthancStone::IObserver(broker), | 245 ISlicedVolume(broker), |
246 IObserver(broker), | |
245 loader_(broker, orthanc), | 247 loader_(broker, orthanc), |
246 computeRange_(computeRange), | 248 computeRange_(computeRange), |
247 pendingSlices_(0) | 249 pendingSlices_(0) |
248 { | 250 { |
249 // TODO: replace with new callables loader_.RegisterObserver(*this); | 251 // TODO: replace with new callables loader_.RegisterObserver(*this); |
493 | 495 |
494 | 496 |
495 | 497 |
496 class VolumeImageMPRSlicer : | 498 class VolumeImageMPRSlicer : |
497 public IVolumeSlicer, | 499 public IVolumeSlicer, |
498 private ISlicedVolume::IObserver | 500 public IObserver |
499 { | 501 { |
500 private: | 502 private: |
501 class RendererFactory : public LayerReadyMessage::IRendererFactory | 503 class RendererFactory : public LayerReadyMessage::IRendererFactory |
502 { | 504 { |
503 private: | 505 private: |
530 | 532 |
531 bool IsGeometryReady() const | 533 bool IsGeometryReady() const |
532 { | 534 { |
533 return axialGeometry_.get() != NULL; | 535 return axialGeometry_.get() != NULL; |
534 } | 536 } |
535 | |
536 | 537 |
537 virtual void NotifyGeometryReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE | 538 void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) |
538 { | 539 { |
540 assert(&message.GetOrigin() == &volume_); | |
541 | |
539 // These 3 values are only used to speed up the IVolumeSlicer | 542 // These 3 values are only used to speed up the IVolumeSlicer |
540 axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial)); | 543 axialGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Axial)); |
541 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); | 544 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); |
542 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); | 545 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); |
543 | 546 |
544 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); | 547 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*this)); |
545 } | 548 } |
546 | 549 |
547 virtual void NotifyGeometryError(const ISlicedVolume& volume) ORTHANC_OVERRIDE | 550 void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message) |
548 { | 551 { |
552 assert(&message.GetOrigin() == &volume_); | |
553 | |
549 EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this)); | 554 EmitMessage(IVolumeSlicer::GeometryErrorMessage(*this)); |
550 } | 555 } |
551 | 556 |
552 virtual void NotifyContentChange(const ISlicedVolume& volume) ORTHANC_OVERRIDE | 557 void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message) |
553 { | 558 { |
559 assert(&message.GetOrigin() == &volume_); | |
560 | |
554 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); | 561 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); |
555 } | 562 } |
556 | 563 |
557 virtual void NotifySliceContentChange(const ISlicedVolume& volume, | 564 void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message) |
558 const size_t& sliceIndex, | 565 { |
559 const Slice& slice) ORTHANC_OVERRIDE | 566 assert(&message.GetOrigin() == &volume_); |
560 { | 567 |
561 //IVolumeSlicer::NotifySliceContentChange(slice); | 568 //IVolumeSlicer::OnSliceContentChange(slice); |
562 | 569 |
563 // TODO Improve this? | 570 // TODO Improve this? |
564 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); | 571 EmitMessage(IVolumeSlicer::ContentChangedMessage(*this)); |
565 } | |
566 | |
567 virtual void NotifyVolumeReady(const ISlicedVolume& volume) ORTHANC_OVERRIDE | |
568 { | |
569 } | 572 } |
570 | 573 |
571 const VolumeImageGeometry& GetProjectionGeometry(VolumeProjection projection) | 574 const VolumeImageGeometry& GetProjectionGeometry(VolumeProjection projection) |
572 { | 575 { |
573 if (!IsGeometryReady()) | 576 if (!IsGeometryReady()) |
627 | 630 |
628 public: | 631 public: |
629 VolumeImageMPRSlicer(MessageBroker& broker, | 632 VolumeImageMPRSlicer(MessageBroker& broker, |
630 OrthancVolumeImage& volume) : | 633 OrthancVolumeImage& volume) : |
631 IVolumeSlicer(broker), | 634 IVolumeSlicer(broker), |
635 IObserver(broker), | |
632 volume_(volume) | 636 volume_(volume) |
633 { | 637 { |
634 volume_.Register(*this); | 638 volume_.RegisterObserverCallback( |
635 } | 639 new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryReadyMessage> |
636 | 640 (*this, &VolumeImageMPRSlicer::OnGeometryReady)); |
637 virtual ~VolumeImageMPRSlicer() | 641 |
638 { | 642 volume_.RegisterObserverCallback( |
643 new Callable<VolumeImageMPRSlicer, ISlicedVolume::GeometryErrorMessage> | |
644 (*this, &VolumeImageMPRSlicer::OnGeometryError)); | |
645 | |
646 volume_.RegisterObserverCallback( | |
647 new Callable<VolumeImageMPRSlicer, ISlicedVolume::ContentChangedMessage> | |
648 (*this, &VolumeImageMPRSlicer::OnContentChanged)); | |
649 | |
650 volume_.RegisterObserverCallback( | |
651 new Callable<VolumeImageMPRSlicer, ISlicedVolume::SliceContentChangedMessage> | |
652 (*this, &VolumeImageMPRSlicer::OnSliceContentChanged)); | |
639 } | 653 } |
640 | 654 |
641 virtual bool GetExtent(std::vector<Vector>& points, | 655 virtual bool GetExtent(std::vector<Vector>& points, |
642 const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE | 656 const CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE |
643 { | 657 { |
700 }; | 714 }; |
701 | 715 |
702 | 716 |
703 class VolumeImageInteractor : | 717 class VolumeImageInteractor : |
704 public IWorldSceneInteractor, | 718 public IWorldSceneInteractor, |
705 protected ISlicedVolume::IObserver | 719 public IObserver |
706 { | 720 { |
707 private: | 721 private: |
708 SliceViewerWidget& widget_; | 722 SliceViewerWidget& widget_; |
709 VolumeProjection projection_; | 723 VolumeProjection projection_; |
710 std::auto_ptr<VolumeImageGeometry> slices_; | 724 std::auto_ptr<VolumeImageGeometry> slices_; |
711 size_t slice_; | 725 size_t slice_; |
712 | 726 |
713 protected: | 727 protected: |
714 virtual void NotifyGeometryReady(const ISlicedVolume& volume) | 728 void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) |
715 { | 729 { |
716 if (slices_.get() == NULL) | 730 if (slices_.get() == NULL) |
717 { | 731 { |
718 const OrthancVolumeImage& image = dynamic_cast<const OrthancVolumeImage&>(volume); | 732 const OrthancVolumeImage& image = |
733 dynamic_cast<const OrthancVolumeImage&>(message.GetOrigin()); | |
719 | 734 |
720 slices_.reset(new VolumeImageGeometry(image, projection_)); | 735 slices_.reset(new VolumeImageGeometry(image, projection_)); |
721 SetSlice(slices_->GetSliceCount() / 2); | 736 SetSlice(slices_->GetSliceCount() / 2); |
722 | 737 |
723 widget_.FitContent(); | 738 widget_.FitContent(); |
724 } | 739 } |
725 } | |
726 | |
727 virtual void NotifyGeometryError(const ISlicedVolume& volume) | |
728 { | |
729 } | |
730 | |
731 virtual void NotifyContentChange(const ISlicedVolume& volume) | |
732 { | |
733 } | |
734 | |
735 virtual void NotifySliceContentChange(const ISlicedVolume& volume, | |
736 const size_t& sliceIndex, | |
737 const Slice& slice) | |
738 { | |
739 } | |
740 | |
741 virtual void NotifyVolumeReady(const ISlicedVolume& volume) | |
742 { | |
743 } | 740 } |
744 | 741 |
745 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, | 742 virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, |
746 const ViewportGeometry& view, | 743 const ViewportGeometry& view, |
747 MouseButton button, | 744 MouseButton button, |
799 break; | 796 break; |
800 } | 797 } |
801 } | 798 } |
802 | 799 |
803 public: | 800 public: |
804 VolumeImageInteractor(OrthancVolumeImage& volume, | 801 VolumeImageInteractor(MessageBroker& broker, |
802 OrthancVolumeImage& volume, | |
805 SliceViewerWidget& widget, | 803 SliceViewerWidget& widget, |
806 VolumeProjection projection) : | 804 VolumeProjection projection) : |
805 IObserver(broker), | |
807 widget_(widget), | 806 widget_(widget), |
808 projection_(projection) | 807 projection_(projection) |
809 { | 808 { |
810 volume.Register(*this); | |
811 widget.SetInteractor(*this); | 809 widget.SetInteractor(*this); |
810 | |
811 volume.RegisterObserverCallback( | |
812 new Callable<VolumeImageInteractor, ISlicedVolume::GeometryReadyMessage> | |
813 (*this, &VolumeImageInteractor::OnGeometryReady)); | |
812 } | 814 } |
813 | 815 |
814 bool IsGeometryReady() const | 816 bool IsGeometryReady() const |
815 { | 817 { |
816 return slices_.get() != NULL; | 818 return slices_.get() != NULL; |