comparison Framework/SmartLoader.cpp @ 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 b66d13708f40
children a902a07769d4
comparison
equal deleted inserted replaced
317:b66d13708f40 318:3a4ca166fafa
20 20
21 21
22 #include "SmartLoader.h" 22 #include "SmartLoader.h"
23 #include "Layers/OrthancFrameLayerSource.h" 23 #include "Layers/OrthancFrameLayerSource.h"
24 #include "Messages/MessageForwarder.h" 24 #include "Messages/MessageForwarder.h"
25 #include "Core/Images/Image.h"
26 #include "Framework/Widgets/LayerWidget.h"
27 #include "Framework/StoneException.h"
28 #include "Framework/Layers/FrameRenderer.h"
25 29
26 namespace OrthancStone 30 namespace OrthancStone
27 { 31 {
32 enum CachedSliceStatus
33 {
34 CachedSliceStatus_Loading,
35 CachedSliceStatus_Loaded
36 };
37
38 class SmartLoader::CachedSlice : public LayerSourceBase
39 {
40 public:
41 unsigned int sliceIndex_;
42 std::auto_ptr<Slice> slice_;
43 boost::shared_ptr<Orthanc::ImageAccessor> image_;
44 SliceImageQuality effectiveQuality_;
45 CachedSliceStatus status_;
46
47 public:
48
49 CachedSlice(MessageBroker& broker)
50 : LayerSourceBase(broker)
51 {}
52
53 virtual bool GetExtent(std::vector<Vector>& points,
54 const CoordinateSystem3D& viewportSlice)
55 {
56 // TODO: viewportSlice is not used !!!!
57 slice_->GetExtent(points);
58 return true;
59 }
60
61 virtual void ScheduleLayerCreation(const CoordinateSystem3D& viewportSlice)
62 {
63 // TODO: viewportSlice is not used !!!!
64
65 // it has already been loaded -> trigger the "layer ready" message immediately
66 bool isFull = (effectiveQuality_ == SliceImageQuality_FullPng || effectiveQuality_ == SliceImageQuality_FullPam);
67 std::auto_ptr<Orthanc::ImageAccessor> accessor(new Orthanc::ImageAccessor());
68 image_->GetReadOnlyAccessor(*accessor);
69 LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(accessor.release(), *slice_, isFull),
70 slice_->GetGeometry(), false);
71 }
72
73 CachedSlice* Clone() const
74 {
75 CachedSlice* output = new CachedSlice(broker_);
76 output->sliceIndex_ = sliceIndex_;
77 output->slice_.reset(slice_->Clone());
78 output->image_ = image_;
79 output->effectiveQuality_ = effectiveQuality_;
80 output->status_ = status_;
81
82 return output;
83 }
84
85 };
86
87
28 SmartLoader::SmartLoader(MessageBroker& broker, OrthancApiClient& orthancApiClient) : 88 SmartLoader::SmartLoader(MessageBroker& broker, OrthancApiClient& orthancApiClient) :
29 IObservable(broker), 89 IObservable(broker),
30 IObserver(broker), 90 IObserver(broker),
31 imageQuality_(SliceImageQuality_FullPam), 91 imageQuality_(SliceImageQuality_FullPam),
32 orthancApiClient_(orthancApiClient) 92 orthancApiClient_(orthancApiClient)
33 { 93 {
34 } 94 }
35 95
36 ILayerSource* SmartLoader::GetFrame(const std::string& instanceId, unsigned int frame) 96 void SmartLoader::SetFrameInWidget(LayerWidget& layerWidget, size_t layerIndex, const std::string& instanceId, unsigned int frame)
37 { 97 {
38 // TODO: check if this frame has already been loaded or is already being loaded. 98 // TODO: check if this frame has already been loaded or is already being loaded.
39 // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately" 99 // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately"
40 // (it can not be immediate because Observers needs to register first and this is done after this method returns) 100 // (it can not be immediate because Observers needs to register first and this is done after this method returns)
41 // - if currently loading, we need to return an object that will observe the existing LayerSource and forward 101 // - if currently loading, we need to return an object that will observe the existing LayerSource and forward
42 // the messages to its observables 102 // the messages to its observables
43 // in both cases, we must be carefull about objects lifecycle !!! 103 // in both cases, we must be carefull about objects lifecycle !!!
44 std::auto_ptr<OrthancFrameLayerSource> layerSource (new OrthancFrameLayerSource(IObserver::broker_, orthancApiClient_)); 104
45 layerSource->SetImageQuality(imageQuality_); 105 std::auto_ptr<ILayerSource> layerSource;
46 layerSource->RegisterObserverCallback(new MessageForwarder<ILayerSource::GeometryReadyMessage>(IObserver::broker_, *this)); 106
47 layerSource->RegisterObserverCallback(new MessageForwarder<ILayerSource::LayerReadyMessage>(IObserver::broker_, *this)); 107 if (cachedSlices_.find(instanceId) != cachedSlices_.end() && cachedSlices_[instanceId]->status_ == CachedSliceStatus_Loaded)
48 layerSource->LoadFrame(instanceId, frame); 108 {
49 109 layerSource.reset(cachedSlices_[instanceId]->Clone());
50 return layerSource.release(); 110 }
51 } 111 else
112 {
113 layerSource.reset(new OrthancFrameLayerSource(IObserver::broker_, orthancApiClient_));
114 dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->SetImageQuality(imageQuality_);
115 layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
116 layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::ImageReadyMessage>(*this, &SmartLoader::OnImageReady));
117 layerSource->RegisterObserverCallback(new Callable<SmartLoader, ILayerSource::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
118 dynamic_cast<OrthancFrameLayerSource*>(layerSource.get())->LoadFrame(instanceId, frame);
119 }
120
121 // make sure that the widget registers the events before we trigger them
122 if (layerWidget.GetLayerCount() == layerIndex)
123 {
124 layerWidget.AddLayer(layerSource.release());
125 }
126 else if (layerWidget.GetLayerCount() > layerIndex)
127 {
128 layerWidget.ReplaceLayer(layerIndex, layerSource.release());
129 }
130 else
131 {
132 throw StoneException(ErrorCode_CanOnlyAddOneLayerAtATime);
133 }
134
135 SmartLoader::CachedSlice* cachedSlice = dynamic_cast<SmartLoader::CachedSlice*>(layerSource.get());
136 if (cachedSlice != NULL)
137 {
138 cachedSlice->NotifyGeometryReady();
139 }
140
141 }
142
52 143
53 void SmartLoader::LoadStudyList() 144 void SmartLoader::LoadStudyList()
54 { 145 {
55 // orthancApiClient_.ScheduleGetJsonRequest("/studies"); 146 // orthancApiClient_.ScheduleGetJsonRequest("/studies");
56 } 147 }
57 148
58 void PreloadStudy(const std::string studyId) 149 void PreloadStudy(const std::string studyId)
59 { 150 {
60 /* TODO */ 151 /* TODO */
64 { 155 {
65 /* TODO */ 156 /* TODO */
66 } 157 }
67 158
68 159
160 void SmartLoader::OnLayerGeometryReady(const ILayerSource::GeometryReadyMessage& message)
161 {
162 OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.origin_);
163 // save the slice
164 const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount()
165 std::string instanceId = slice.GetOrthancInstanceId();
166
167 CachedSlice* cachedSlice = new CachedSlice(IObserver::broker_);
168 cachedSlice->slice_.reset(slice.Clone());
169 cachedSlice->effectiveQuality_ = source.GetImageQuality();
170 cachedSlice->status_ = CachedSliceStatus_Loading;
171
172 cachedSlices_[instanceId] = boost::shared_ptr<CachedSlice>(cachedSlice);
173
174 // re-emit original Layer message to observers
175 EmitMessage(message);
176 }
177
178 void SmartLoader::OnImageReady(const ILayerSource::ImageReadyMessage& message)
179 {
180 OrthancFrameLayerSource& source = dynamic_cast<OrthancFrameLayerSource&>(message.origin_);
181
182 // save the slice
183 const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ?
184 std::string instanceId = slice.GetOrthancInstanceId();
185
186 boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::broker_));
187 cachedSlice->image_ = message.image_;
188 cachedSlice->effectiveQuality_ = message.imageQuality_;
189 cachedSlice->slice_.reset(message.slice_.Clone());
190 cachedSlice->status_ = CachedSliceStatus_Loaded;
191
192 cachedSlices_[instanceId] = cachedSlice;
193
194 // re-emit original Layer message to observers
195 EmitMessage(message);
196 }
197
198 void SmartLoader::OnLayerReady(const ILayerSource::LayerReadyMessage& message)
199 {
200 // re-emit original Layer message to observers
201 EmitMessage(message);
202 }
203
69 } 204 }