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