comparison Framework/SmartLoader.cpp @ 421:f87f28624b96 cache-in-radiography

tentative to make SmartLoader and RadiographyScene work together (not really working)
author am@osimis.io
date Tue, 20 Nov 2018 16:35:29 +0100
parents 5d359b115b29
children
comparison
equal deleted inserted replaced
420:8bf717c4e497 421:f87f28624b96
25 #include "Core/Images/Image.h" 25 #include "Core/Images/Image.h"
26 #include "Framework/Widgets/SliceViewerWidget.h" 26 #include "Framework/Widgets/SliceViewerWidget.h"
27 #include "Framework/StoneException.h" 27 #include "Framework/StoneException.h"
28 #include "Framework/Layers/FrameRenderer.h" 28 #include "Framework/Layers/FrameRenderer.h"
29 #include "Core/Logging.h" 29 #include "Core/Logging.h"
30 #include "Radiography/RadiographyScene.h"
30 31
31 namespace OrthancStone 32 namespace OrthancStone
32 { 33 {
33 enum CachedSliceStatus 34 enum CachedSliceStatus
34 { 35 {
60 } 61 }
61 }; 62 };
62 63
63 unsigned int sliceIndex_; 64 unsigned int sliceIndex_;
64 std::auto_ptr<Slice> slice_; 65 std::auto_ptr<Slice> slice_;
66 std::auto_ptr<OrthancPlugins::FullOrthancDataset> dicomTags_;
67
65 boost::shared_ptr<Orthanc::ImageAccessor> image_; 68 boost::shared_ptr<Orthanc::ImageAccessor> image_;
66 SliceImageQuality effectiveQuality_; 69 SliceImageQuality effectiveQuality_;
67 CachedSliceStatus status_; 70 CachedSliceStatus status_;
68 71
69 public: 72 public:
93 if (status_ == CachedSliceStatus_ImageLoaded) 96 if (status_ == CachedSliceStatus_ImageLoaded)
94 { 97 {
95 LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId(); 98 LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId();
96 99
97 RendererFactory factory(*this); 100 RendererFactory factory(*this);
101 EmitMessage(IVolumeSlicer::FrameReadyMessage(*this, image_));
98 EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry())); 102 EmitMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry()));
99 } 103 }
100 else 104 else
101 { 105 {
102 LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId(); 106 LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId();
125 imageQuality_(SliceImageQuality_FullPam), 129 imageQuality_(SliceImageQuality_FullPam),
126 orthancApiClient_(orthancApiClient) 130 orthancApiClient_(orthancApiClient)
127 { 131 {
128 } 132 }
129 133
134 void SmartLoader::SetFrameInRadiographyScene(RadiographyScene& scene, const std::string& instanceId, unsigned int frame)
135 {
136 // create the frame loader
137 std::auto_ptr<IVolumeSlicer> layerSource(GetFrameLoader(instanceId, frame));
138 IVolumeSlicer* layerSource2 = layerSource.get();
139
140 // make sure that the widget registers the events before we trigger them (once we start loading the frame)
141 scene.SetFrame(layerSource.release());
142
143 // start loading
144 LoadFrame(layerSource2, instanceId, frame);
145 }
146
147
148 IVolumeSlicer* SmartLoader::GetFrameLoader(const std::string &instanceId, unsigned int frame)
149 {
150 std::auto_ptr<IVolumeSlicer> layerSource;
151 std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame);
152
153
154 if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded)
155 { // if the image is cached, return a clone of the cached image
156 layerSource.reset(cachedSlices_[sliceKeyId]->Clone());
157 }
158 else
159 { // return a standard frame loader
160 layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
161 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
162 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::TagsReadyMessage>(*this, &SmartLoader::OnLayerTagsReady));
163 layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
164 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
165 }
166
167 return layerSource.release();
168 }
169
170 void SmartLoader::LoadFrame(IVolumeSlicer *frameLoader, const std::string &instanceId, unsigned int frame)
171 {
172 SmartLoader::CachedSlice* cachedSlice = dynamic_cast<SmartLoader::CachedSlice*>(frameLoader);
173
174 if (cachedSlice != NULL)
175 {
176 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
177 EmitMessage(IVolumeSlicer::TagsReadyMessage(*cachedSlice, *(cachedSlice->dicomTags_.get())));
178 }
179 else
180 {
181 DicomSeriesVolumeSlicer* volumeLoader = dynamic_cast<DicomSeriesVolumeSlicer*>(frameLoader);
182 volumeLoader->LoadFrame(instanceId, frame);
183 }
184
185 }
186
130 void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer, 187 void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer,
131 size_t layerIndex, 188 size_t layerIndex,
132 const std::string& instanceId, 189 const std::string& instanceId,
133 unsigned int frame) 190 unsigned int frame)
134 { 191 {
135 // TODO: check if this frame has already been loaded or is already being loaded. 192 // create the frame loader
136 // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately" 193 std::auto_ptr<IVolumeSlicer> layerSource(GetFrameLoader(instanceId, frame));
137 // (it can not be immediate because Observers needs to register first and this is done after this method returns) 194 IVolumeSlicer* layerSource2 = layerSource.get();
138 // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward 195
139 // the messages to its observables 196 // make sure that the widget registers the events before we trigger them (once we start loading the frame)
140 // in both cases, we must be carefull about objects lifecycle !!! 197 if (sliceViewer.GetLayerCount() == layerIndex)
141 198 {
142 std::auto_ptr<IVolumeSlicer> layerSource; 199 sliceViewer.AddLayer(layerSource.release());
143 std::string sliceKeyId = instanceId + ":" + boost::lexical_cast<std::string>(frame); 200 }
144 SmartLoader::CachedSlice* cachedSlice = NULL; 201 else if (sliceViewer.GetLayerCount() > layerIndex)
145 202 {
146 if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded) 203 sliceViewer.ReplaceLayer(layerIndex, layerSource.release());
147 {
148 layerSource.reset(cachedSlices_[sliceKeyId]->Clone());
149 cachedSlice = dynamic_cast<SmartLoader::CachedSlice*>(layerSource.get());
150 } 204 }
151 else 205 else
152 { 206 {
153 layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
154 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
155 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady));
156 layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
157 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
158 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
159 }
160
161 // make sure that the widget registers the events before we trigger them
162 if (sliceViewer.GetLayerCount() == layerIndex)
163 {
164 sliceViewer.AddLayer(layerSource.release());
165 }
166 else if (sliceViewer.GetLayerCount() > layerIndex)
167 {
168 sliceViewer.ReplaceLayer(layerIndex, layerSource.release());
169 }
170 else
171 {
172 throw StoneException(ErrorCode_CanOnlyAddOneLayerAtATime); 207 throw StoneException(ErrorCode_CanOnlyAddOneLayerAtATime);
173 } 208 }
174 209
175 if (cachedSlice != NULL) 210 // start loading
176 { 211 LoadFrame(layerSource2, instanceId, frame);
177 EmitMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice));
178 }
179
180 } 212 }
181 213
182 void SmartLoader::PreloadSlice(const std::string instanceId, 214 void SmartLoader::PreloadSlice(const std::string instanceId,
183 unsigned int frame) 215 unsigned int frame)
184 { 216 {
199 cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice); 231 cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
200 232
201 std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); 233 std::auto_ptr<IVolumeSlicer> layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_));
202 234
203 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_); 235 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->SetImageQuality(imageQuality_);
204 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::GeometryReadyMessage>(*this, &SmartLoader::OnLayerGeometryReady)); 236 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::TagsReadyMessage>(*this, &SmartLoader::OnLayerTagsReady));
205 layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady)); 237 layerSource->RegisterObserverCallback(new Callable<SmartLoader, DicomSeriesVolumeSlicer::FrameReadyMessage>(*this, &SmartLoader::OnFrameReady));
206 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady)); 238 layerSource->RegisterObserverCallback(new Callable<SmartLoader, IVolumeSlicer::LayerReadyMessage>(*this, &SmartLoader::OnLayerReady));
207 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame); 239 dynamic_cast<DicomSeriesVolumeSlicer*>(layerSource.get())->LoadFrame(instanceId, frame);
208 240
209 // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache 241 // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache
220 // { 252 // {
221 // /* TODO */ 253 // /* TODO */
222 // } 254 // }
223 255
224 256
225 void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message) 257 void SmartLoader::OnLayerTagsReady(const IVolumeSlicer::TagsReadyMessage& message)
226 { 258 {
227 const DicomSeriesVolumeSlicer& source = 259 const DicomSeriesVolumeSlicer& source =
228 dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin()); 260 dynamic_cast<const DicomSeriesVolumeSlicer&>(message.GetOrigin());
229 261
230 // save/replace the slice in cache 262 // save/replace the slice in cache
236 268
237 boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker())); 269 boost::shared_ptr<CachedSlice> cachedSlice(new CachedSlice(IObserver::GetBroker()));
238 cachedSlice->slice_.reset(slice.Clone()); 270 cachedSlice->slice_.reset(slice.Clone());
239 cachedSlice->effectiveQuality_ = source.GetImageQuality(); 271 cachedSlice->effectiveQuality_ = source.GetImageQuality();
240 cachedSlice->status_ = CachedSliceStatus_GeometryLoaded; 272 cachedSlice->status_ = CachedSliceStatus_GeometryLoaded;
273 cachedSlice->dicomTags_.reset(message.GetDicomTags().Clone());
241 274
242 cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice); 275 cachedSlices_[sliceKeyId] = boost::shared_ptr<CachedSlice>(cachedSlice);
243 276
244 // re-emit original Layer message to observers 277 // re-emit original Layer message to observers
245 EmitMessage(message); 278 // EmitMessage(message);
246 } 279 }
247 280
248 281
249 void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message) 282 void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message)
250 { 283 {
262 cachedSlice->status_ = CachedSliceStatus_ImageLoaded; 295 cachedSlice->status_ = CachedSliceStatus_ImageLoaded;
263 296
264 cachedSlices_[sliceKeyId] = cachedSlice; 297 cachedSlices_[sliceKeyId] = cachedSlice;
265 298
266 // re-emit original Layer message to observers 299 // re-emit original Layer message to observers
267 EmitMessage(message); 300 // EmitMessage(IVolumeSlicer::FrameReadyMessage(*(cachedSlice.get()), cachedSlice->image_));
268 } 301 }
269 302
270 303
271 void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message) 304 void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message)
272 { 305 {
284 { 317 {
285 preloadingInstances_.erase(sliceKeyId); 318 preloadingInstances_.erase(sliceKeyId);
286 } 319 }
287 320
288 // re-emit original Layer message to observers 321 // re-emit original Layer message to observers
289 EmitMessage(message); 322 // EmitMessage(message);
290 } 323 }
291 } 324 }