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