comparison Framework/dev.h @ 318:3a4ca166fafa am-2

ImageAccessor refactoring + implemented Image Cache in SmartLoader
author am@osimis.io
date Mon, 08 Oct 2018 17:10:08 +0200
parents b4abaeb783b1
children 8716176ff7f0
comparison
equal deleted inserted replaced
317:b66d13708f40 318:3a4ca166fafa
11 * 11 *
12 * This program is distributed in the hope that it will be useful, but 12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details. 15 * Affero General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU Affero General Public License 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/>. 18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/ 19 **/
20 20
21 21
39 39
40 40
41 namespace OrthancStone 41 namespace OrthancStone
42 { 42 {
43 // TODO: Handle errors while loading 43 // TODO: Handle errors while loading
44 class OrthancVolumeImage : 44 class OrthancVolumeImage :
45 public SlicedVolumeBase, 45 public SlicedVolumeBase,
46 public OrthancStone::IObserver 46 public OrthancStone::IObserver
47 { 47 {
48 private: 48 private:
49 OrthancSlicesLoader loader_; 49 OrthancSlicesLoader loader_;
50 std::auto_ptr<ImageBuffer3D> image_; 50 std::auto_ptr<ImageBuffer3D> image_;
51 std::auto_ptr<DownloadStack> downloadStack_; 51 std::auto_ptr<DownloadStack> downloadStack_;
52 bool computeRange_; 52 bool computeRange_;
62 loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Jpeg90); 62 loader_.ScheduleLoadSliceImage(slice, SliceImageQuality_Jpeg90);
63 } 63 }
64 } 64 }
65 65
66 66
67 static bool IsCompatible(const Slice& a, 67 static bool IsCompatible(const Slice& a,
68 const Slice& b) 68 const Slice& b)
69 { 69 {
70 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), 70 if (!GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(),
71 b.GetGeometry().GetNormal())) 71 b.GetGeometry().GetNormal()))
72 { 72 {
96 96
97 return true; 97 return true;
98 } 98 }
99 99
100 100
101 static double GetDistance(const Slice& a, 101 static double GetDistance(const Slice& a,
102 const Slice& b) 102 const Slice& b)
103 { 103 {
104 return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - 104 return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) -
105 a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin())); 105 a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin()));
106 } 106 }
107 107
108 108
109 void OnSliceGeometryReady(const OrthancSlicesLoader& loader) 109 void OnSliceGeometryReady(const OrthancSlicesLoader& loader)
172 172
173 SlicedVolumeBase::NotifyGeometryReady(); 173 SlicedVolumeBase::NotifyGeometryReady();
174 } 174 }
175 175
176 virtual void OnSliceImageReady(const OrthancSlicesLoader& loader, 176 virtual void OnSliceImageReady(const OrthancSlicesLoader& loader,
177 unsigned int sliceIndex, 177 unsigned int sliceIndex,
178 const Slice& slice, 178 const Slice& slice,
179 std::auto_ptr<Orthanc::ImageAccessor>& image, 179 const boost::shared_ptr<Orthanc::ImageAccessor>& image,
180 SliceImageQuality quality) 180 SliceImageQuality quality)
181 { 181 {
182 { 182 {
183 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex); 183 ImageBuffer3D::SliceWriter writer(*image_, VolumeProjection_Axial, sliceIndex);
184 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), *image); 184 Orthanc::ImageProcessing::Copy(writer.GetAccessor(), *image);
185 } 185 }
219 msg.image_, 219 msg.image_,
220 msg.effectiveQuality_); 220 msg.effectiveQuality_);
221 }; break; 221 }; break;
222 case MessageType_SliceLoader_ImageError: 222 case MessageType_SliceLoader_ImageError:
223 { 223 {
224 const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast<const OrthancSlicesLoader::SliceImageErrorMessage&>(message); 224 const OrthancSlicesLoader::SliceImageErrorMessage& msg = dynamic_cast<const OrthancSlicesLoader::SliceImageErrorMessage&>(message);
225 LOG(ERROR) << "Cannot download slice " << msg.sliceIndex_ << " in a volume image"; 225 LOG(ERROR) << "Cannot download slice " << msg.sliceIndex_ << " in a volume image";
226 ScheduleSliceDownload(); 226 ScheduleSliceDownload();
227 }; break; 227 }; break;
228 default: 228 default:
229 VLOG("unhandled message type" << message.GetType()); 229 VLOG("unhandled message type" << message.GetType());
230 } 230 }
231 } 231 }
232 232
233 public: 233 public:
234 OrthancVolumeImage(MessageBroker& broker, 234 OrthancVolumeImage(MessageBroker& broker,
235 OrthancApiClient& orthanc, 235 OrthancApiClient& orthanc,
236 bool computeRange) : 236 bool computeRange) :
237 OrthancStone::IObserver(broker), 237 OrthancStone::IObserver(broker),
238 loader_(broker, orthanc), 238 loader_(broker, orthanc),
239 computeRange_(computeRange), 239 computeRange_(computeRange),
240 pendingSlices_(0) 240 pendingSlices_(0)
241 { 241 {
242 // TODO: replace with new callables loader_.RegisterObserver(*this); 242 // TODO: replace with new callables loader_.RegisterObserver(*this);
243 } 243 }
244 244
245 void ScheduleLoadSeries(const std::string& seriesId) 245 void ScheduleLoadSeries(const std::string& seriesId)
246 { 246 {
247 loader_.ScheduleLoadSeries(seriesId); 247 loader_.ScheduleLoadSeries(seriesId);
369 Vector origin = axial.GetGeometry().GetOrigin(); 369 Vector origin = axial.GetGeometry().GetOrigin();
370 origin += (static_cast<double>(volume.GetSliceCount() - 1) * 370 origin += (static_cast<double>(volume.GetSliceCount() - 1) *
371 axialThickness * axial.GetGeometry().GetNormal()); 371 axialThickness * axial.GetGeometry().GetNormal());
372 372
373 reference_ = CoordinateSystem3D(origin, 373 reference_ = CoordinateSystem3D(origin,
374 axial.GetGeometry().GetAxisX(), 374 axial.GetGeometry().GetAxisX(),
375 -axial.GetGeometry().GetNormal()); 375 -axial.GetGeometry().GetNormal());
376 } 376 }
377 377
378 void SetupSagittal(const OrthancVolumeImage& volume) 378 void SetupSagittal(const OrthancVolumeImage& volume)
379 { 379 {
391 Vector origin = axial.GetGeometry().GetOrigin(); 391 Vector origin = axial.GetGeometry().GetOrigin();
392 origin += (static_cast<double>(volume.GetSliceCount() - 1) * 392 origin += (static_cast<double>(volume.GetSliceCount() - 1) *
393 axialThickness * axial.GetGeometry().GetNormal()); 393 axialThickness * axial.GetGeometry().GetNormal());
394 394
395 reference_ = CoordinateSystem3D(origin, 395 reference_ = CoordinateSystem3D(origin,
396 axial.GetGeometry().GetAxisY(), 396 axial.GetGeometry().GetAxisY(),
397 axial.GetGeometry().GetNormal()); 397 axial.GetGeometry().GetNormal());
398 } 398 }
399 399
400 public: 400 public:
401 VolumeImageGeometry(const OrthancVolumeImage& volume, 401 VolumeImageGeometry(const OrthancVolumeImage& volume,
408 408
409 converter_ = volume.GetSlice(0).GetConverter(); 409 converter_ = volume.GetSlice(0).GetConverter();
410 410
411 switch (projection) 411 switch (projection)
412 { 412 {
413 case VolumeProjection_Axial: 413 case VolumeProjection_Axial:
414 SetupAxial(volume); 414 SetupAxial(volume);
415 break; 415 break;
416 416
417 case VolumeProjection_Coronal: 417 case VolumeProjection_Coronal:
418 SetupCoronal(volume); 418 SetupCoronal(volume);
419 break; 419 break;
420 420
421 case VolumeProjection_Sagittal: 421 case VolumeProjection_Sagittal:
422 SetupSagittal(volume); 422 SetupSagittal(volume);
423 break; 423 break;
424 424
425 default: 425 default:
426 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); 426 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
427 } 427 }
428 } 428 }
429 429
430 size_t GetSliceCount() const 430 size_t GetSliceCount() const
431 { 431 {
485 }; 485 };
486 486
487 487
488 488
489 class VolumeImageSource : 489 class VolumeImageSource :
490 public LayerSourceBase, 490 public LayerSourceBase,
491 private ISlicedVolume::IObserver 491 private ISlicedVolume::IObserver
492 { 492 {
493 private: 493 private:
494 OrthancVolumeImage& volume_; 494 OrthancVolumeImage& volume_;
495 std::auto_ptr<VolumeImageGeometry> axialGeometry_; 495 std::auto_ptr<VolumeImageGeometry> axialGeometry_;
496 std::auto_ptr<VolumeImageGeometry> coronalGeometry_; 496 std::auto_ptr<VolumeImageGeometry> coronalGeometry_;
510 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal)); 510 coronalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Coronal));
511 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal)); 511 sagittalGeometry_.reset(new VolumeImageGeometry(volume_, VolumeProjection_Sagittal));
512 512
513 LayerSourceBase::NotifyGeometryReady(); 513 LayerSourceBase::NotifyGeometryReady();
514 } 514 }
515 515
516 virtual void NotifyGeometryError(const ISlicedVolume& volume) 516 virtual void NotifyGeometryError(const ISlicedVolume& volume)
517 { 517 {
518 LayerSourceBase::NotifyGeometryError(); 518 LayerSourceBase::NotifyGeometryError();
519 } 519 }
520 520
521 virtual void NotifyContentChange(const ISlicedVolume& volume) 521 virtual void NotifyContentChange(const ISlicedVolume& volume)
522 { 522 {
523 LayerSourceBase::NotifyContentChange(); 523 LayerSourceBase::NotifyContentChange();
524 } 524 }
525 525
544 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 544 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
545 } 545 }
546 546
547 switch (projection) 547 switch (projection)
548 { 548 {
549 case VolumeProjection_Axial: 549 case VolumeProjection_Axial:
550 return *axialGeometry_; 550 return *axialGeometry_;
551 551
552 case VolumeProjection_Sagittal: 552 case VolumeProjection_Sagittal:
553 return *sagittalGeometry_; 553 return *sagittalGeometry_;
554 554
555 case VolumeProjection_Coronal: 555 case VolumeProjection_Coronal:
556 return *coronalGeometry_; 556 return *coronalGeometry_;
557 557
558 default: 558 default:
559 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 559 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
560 } 560 }
561 } 561 }
562 562
563 563
564 bool DetectProjection(VolumeProjection& projection, 564 bool DetectProjection(VolumeProjection& projection,
611 !DetectProjection(projection, viewportSlice)) 611 !DetectProjection(projection, viewportSlice))
612 { 612 {
613 return false; 613 return false;
614 } 614 }
615 else 615 else
616 { 616 {
617 // As the slices of the volumic image are arranged in a box, 617 // As the slices of the volumic image are arranged in a box,
618 // we only consider one single reference slice (the one with index 0). 618 // we only consider one single reference slice (the one with index 0).
619 std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0)); 619 std::auto_ptr<Slice> slice(GetProjectionGeometry(projection).GetSlice(0));
620 slice->GetExtent(points); 620 slice->GetExtent(points);
621 621
648 frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); 648 frame.reset(Orthanc::Image::Clone(reader.GetAccessor()));
649 } 649 }
650 650
651 std::auto_ptr<Slice> slice(geometry.GetSlice(closest)); 651 std::auto_ptr<Slice> slice(geometry.GetSlice(closest));
652 LayerSourceBase::NotifyLayerReady( 652 LayerSourceBase::NotifyLayerReady(
653 FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality), 653 FrameRenderer::CreateRenderer(frame.release(), *slice, isFullQuality),
654 //new SliceOutlineRenderer(slice), 654 //new SliceOutlineRenderer(slice),
655 slice->GetGeometry(), false); 655 slice->GetGeometry(), false);
656 return; 656 return;
657 } 657 }
658 } 658 }
659 659
660 // Error 660 // Error
663 } 663 }
664 }; 664 };
665 665
666 666
667 class VolumeImageInteractor : 667 class VolumeImageInteractor :
668 public IWorldSceneInteractor, 668 public IWorldSceneInteractor,
669 protected ISlicedVolume::IObserver 669 protected ISlicedVolume::IObserver
670 { 670 {
671 private: 671 private:
672 LayerWidget& widget_; 672 LayerWidget& widget_;
673 VolumeProjection projection_; 673 VolumeProjection projection_;
674 std::auto_ptr<VolumeImageGeometry> slices_; 674 std::auto_ptr<VolumeImageGeometry> slices_;
685 SetSlice(slices_->GetSliceCount() / 2); 685 SetSlice(slices_->GetSliceCount() / 2);
686 686
687 widget_.SetDefaultView(); 687 widget_.SetDefaultView();
688 } 688 }
689 } 689 }
690 690
691 virtual void NotifyGeometryError(const ISlicedVolume& volume) 691 virtual void NotifyGeometryError(const ISlicedVolume& volume)
692 { 692 {
693 } 693 }
694 694
695 virtual void NotifyContentChange(const ISlicedVolume& volume) 695 virtual void NotifyContentChange(const ISlicedVolume& volume)
696 { 696 {
697 } 697 }
698 698
699 virtual void NotifySliceChange(const ISlicedVolume& volume, 699 virtual void NotifySliceChange(const ISlicedVolume& volume,
729 MouseWheelDirection direction, 729 MouseWheelDirection direction,
730 KeyboardModifiers modifiers, 730 KeyboardModifiers modifiers,
731 IStatusBar* statusBar) 731 IStatusBar* statusBar)
732 { 732 {
733 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1); 733 int scale = (modifiers & KeyboardModifiers_Control ? 10 : 1);
734 734
735 switch (direction) 735 switch (direction)
736 { 736 {
737 case MouseWheelDirection_Up: 737 case MouseWheelDirection_Up:
738 OffsetSlice(-scale); 738 OffsetSlice(-scale);
739 break; 739 break;
740 740
741 case MouseWheelDirection_Down: 741 case MouseWheelDirection_Down:
742 OffsetSlice(scale); 742 OffsetSlice(scale);
743 break; 743 break;
744 744
745 default: 745 default:
746 break; 746 break;
747 } 747 }
748 } 748 }
749 749
750 virtual void KeyPressed(WorldSceneWidget& widget, 750 virtual void KeyPressed(WorldSceneWidget& widget,
751 char key, 751 char key,
752 KeyboardModifiers modifiers, 752 KeyboardModifiers modifiers,
753 IStatusBar* statusBar) 753 IStatusBar* statusBar)
754 { 754 {
755 switch (key) 755 switch (key)
756 { 756 {
757 case 's': 757 case 's':
758 widget.SetDefaultView(); 758 widget.SetDefaultView();
759 break; 759 break;
760 760
761 default: 761 default:
762 break; 762 break;
763 } 763 }
764 } 764 }
765 765
766 public: 766 public:
767 VolumeImageInteractor(OrthancVolumeImage& volume, 767 VolumeImageInteractor(OrthancVolumeImage& volume,
768 LayerWidget& widget, 768 LayerWidget& widget,
769 VolumeProjection projection) : 769 VolumeProjection projection) :
770 widget_(widget), 770 widget_(widget),
805 if (slice >= static_cast<int>(slices_->GetSliceCount())) 805 if (slice >= static_cast<int>(slices_->GetSliceCount()))
806 { 806 {
807 slice = slices_->GetSliceCount() - 1; 807 slice = slices_->GetSliceCount() - 1;
808 } 808 }
809 809
810 if (slice != static_cast<int>(slice_)) 810 if (slice != static_cast<int>(slice_))
811 { 811 {
812 SetSlice(slice); 812 SetSlice(slice);
813 } 813 }
814 } 814 }
815 } 815 }
816 816
817 void SetSlice(size_t slice) 817 void SetSlice(size_t slice)
818 { 818 {
819 if (slices_.get() != NULL) 819 if (slices_.get() != NULL)
820 { 820 {
821 slice_ = slice; 821 slice_ = slice;
854 Vector p, d; 854 Vector p, d;
855 855
856 const CoordinateSystem3D& slice = otherPlane_.GetSlice(); 856 const CoordinateSystem3D& slice = otherPlane_.GetSlice();
857 857
858 // Compute the line of intersection between the two slices 858 // Compute the line of intersection between the two slices
859 if (!GeometryToolbox::IntersectTwoPlanes(p, d, 859 if (!GeometryToolbox::IntersectTwoPlanes(p, d,
860 slice.GetOrigin(), slice.GetNormal(), 860 slice.GetOrigin(), slice.GetNormal(),
861 viewportSlice.GetOrigin(), viewportSlice.GetNormal())) 861 viewportSlice.GetOrigin(), viewportSlice.GetNormal()))
862 { 862 {
863 // The two slice are parallel, don't try and display the intersection 863 // The two slice are parallel, don't try and display the intersection
864 NotifyLayerReady(NULL, reference.GetGeometry(), false); 864 NotifyLayerReady(NULL, reference.GetGeometry(), false);
869 viewportSlice.ProjectPoint(x1, y1, p); 869 viewportSlice.ProjectPoint(x1, y1, p);
870 viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); 870 viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d);
871 871
872 const Extent2D extent = otherPlane_.GetSceneExtent(); 872 const Extent2D extent = otherPlane_.GetSceneExtent();
873 873
874 if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, 874 if (GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2,
875 x1, y1, x2, y2, 875 x1, y1, x2, y2,
876 extent.GetX1(), extent.GetY1(), 876 extent.GetX1(), extent.GetY1(),
877 extent.GetX2(), extent.GetY2())) 877 extent.GetX2(), extent.GetY2()))
878 { 878 {
879 NotifyLayerReady(new LineLayerRenderer(x1, y1, x2, y2, slice), reference.GetGeometry(), false); 879 NotifyLayerReady(new LineLayerRenderer(x1, y1, x2, y2, slice), reference.GetGeometry(), false);
882 { 882 {
883 // Parallel slices 883 // Parallel slices
884 NotifyLayerReady(NULL, reference.GetGeometry(), false); 884 NotifyLayerReady(NULL, reference.GetGeometry(), false);
885 } 885 }
886 } 886 }
887 } 887 }
888 }; 888 };
889 } 889 }