Mercurial > hg > orthanc-stone
comparison Framework/Layers/OrthancFrameLayerSource.cpp @ 77:f5f54ed8d307 wasm
refactoring
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 24 May 2017 21:13:29 +0200 |
parents | 298f375dcb68 |
children | bd48431ac285 |
comparison
equal
deleted
inserted
replaced
76:0aef120d7e1c | 77:f5f54ed8d307 |
---|---|
30 #include <boost/lexical_cast.hpp> | 30 #include <boost/lexical_cast.hpp> |
31 | 31 |
32 | 32 |
33 namespace OrthancStone | 33 namespace OrthancStone |
34 { | 34 { |
35 class OrthancFrameLayerSource::Operation : public Orthanc::IDynamicObject | 35 void OrthancFrameLayerSource::NotifyGeometryReady(const OrthancSlicesLoader& loader) |
36 { | 36 { |
37 private: | 37 if (loader.GetSliceCount() > 0) |
38 Content content_; | |
39 SliceGeometry viewportSlice_; | |
40 | |
41 public: | |
42 Operation(Content content) : content_(content) | |
43 { | 38 { |
39 // Make sure all the slices are parallel. TODO Alleviate this constraint | |
40 for (size_t i = 1; i < loader.GetSliceCount(); i++) | |
41 { | |
42 if (!GeometryToolbox::IsParallel(loader.GetSlice(i).GetGeometry().GetNormal(), | |
43 loader.GetSlice(0).GetGeometry().GetNormal())) | |
44 { | |
45 LayerSourceBase::NotifyGeometryError(); | |
46 return; | |
47 } | |
48 } | |
44 } | 49 } |
45 | 50 |
46 void SetViewportSlice(const SliceGeometry& slice) | 51 if (observer2_ != NULL) |
47 { | 52 { |
48 viewportSlice_ = slice; | 53 ParallelSlices slices; |
54 | |
55 for (size_t i = 0; i < loader.GetSliceCount(); i++) | |
56 { | |
57 slices.AddSlice(loader.GetSlice(i).GetGeometry()); | |
58 } | |
59 | |
60 observer2_->NotifySlicesAvailable(slices); | |
49 } | 61 } |
62 | |
63 LayerSourceBase::NotifyGeometryReady(); | |
64 } | |
50 | 65 |
51 const SliceGeometry& GetViewportSlice() const | 66 void OrthancFrameLayerSource::NotifyGeometryError(const OrthancSlicesLoader& loader) |
52 { | 67 { |
53 return viewportSlice_; | 68 LayerSourceBase::NotifyGeometryError(); |
54 } | 69 } |
55 | 70 |
56 Content GetContent() const | 71 void OrthancFrameLayerSource::NotifySliceImageReady(const OrthancSlicesLoader& loader, |
57 { | 72 unsigned int sliceIndex, |
58 return content_; | 73 const Slice& slice, |
59 } | 74 Orthanc::ImageAccessor* image) |
60 }; | 75 { |
61 | 76 LayerSourceBase::NotifyLayerReady(FrameRenderer::CreateRenderer(image, slice, true), slice); |
77 } | |
78 | |
79 void OrthancFrameLayerSource::NotifySliceImageError(const OrthancSlicesLoader& loader, | |
80 unsigned int sliceIndex, | |
81 const Slice& slice) | |
82 { | |
83 LayerSourceBase::NotifyLayerError(slice.GetGeometry()); | |
84 } | |
62 | 85 |
63 OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc, | 86 OrthancFrameLayerSource::OrthancFrameLayerSource(IWebService& orthanc, |
64 const std::string& instanceId, | 87 const std::string& instanceId, |
65 unsigned int frame) : | 88 unsigned int frame) : |
66 orthanc_(orthanc), | |
67 instanceId_(instanceId), | 89 instanceId_(instanceId), |
68 frame_(frame), | 90 frame_(frame), |
69 frameWidth_(0), | 91 loader_(*this, orthanc), |
70 frameHeight_(0), | |
71 pixelSpacingX_(1), | |
72 pixelSpacingY_(1), | |
73 observer2_(NULL) | 92 observer2_(NULL) |
74 { | 93 { |
75 } | 94 } |
76 | 95 |
77 | 96 |
78 void OrthancFrameLayerSource::StartInternal() | 97 void OrthancFrameLayerSource::StartInternal() |
79 { | 98 { |
80 orthanc_.ScheduleGetRequest(*this, | 99 loader_.ScheduleLoadInstance(instanceId_, frame_); |
81 "/instances/" + instanceId_ + "/tags", | |
82 new Operation(Content_Tags)); | |
83 } | 100 } |
84 | 101 |
85 | |
86 void OrthancFrameLayerSource::SetObserver(IObserver& observer) | |
87 { | |
88 LayerSourceBase::SetObserver(observer); | |
89 | |
90 if (dataset_.get() != NULL) | |
91 { | |
92 NotifySourceChange(); | |
93 } | |
94 } | |
95 | |
96 | 102 |
97 void OrthancFrameLayerSource::SetObserver(IVolumeSlicesObserver& observer) | 103 void OrthancFrameLayerSource::SetObserver(IVolumeSlicesObserver& observer) |
98 { | 104 { |
99 if (IsStarted()) | 105 if (IsStarted()) |
100 { | 106 { |
110 // Cannot add more than one observer | 116 // Cannot add more than one observer |
111 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 117 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
112 } | 118 } |
113 } | 119 } |
114 | 120 |
115 | |
116 void OrthancFrameLayerSource::NotifyError(const std::string& uri, | |
117 Orthanc::IDynamicObject* payload) | |
118 { | |
119 std::auto_ptr<Operation> operation(reinterpret_cast<Operation*>(payload)); | |
120 | |
121 LOG(ERROR) << "Cannot download " << uri; | |
122 NotifyLayerError(operation->GetViewportSlice()); | |
123 } | |
124 | |
125 | |
126 void OrthancFrameLayerSource::NotifySuccess(const std::string& uri, | |
127 const void* answer, | |
128 size_t answerSize, | |
129 Orthanc::IDynamicObject* payload) | |
130 { | |
131 std::auto_ptr<Operation> operation(reinterpret_cast<Operation*>(payload)); | |
132 | |
133 if (operation.get() == NULL) | |
134 { | |
135 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
136 } | |
137 else if (operation->GetContent() == Content_Tags) | |
138 { | |
139 dataset_.reset(new OrthancPlugins::FullOrthancDataset(answer, answerSize)); | |
140 | |
141 DicomFrameConverter converter; | |
142 converter.ReadParameters(*dataset_); | |
143 format_ = converter.GetExpectedPixelFormat(); | |
144 GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, *dataset_); | |
145 | |
146 OrthancPlugins::DicomDatasetReader reader(*dataset_); | |
147 if (!reader.GetUnsignedIntegerValue(frameWidth_, OrthancPlugins::DICOM_TAG_COLUMNS) || | |
148 !reader.GetUnsignedIntegerValue(frameHeight_, OrthancPlugins::DICOM_TAG_ROWS)) | |
149 { | |
150 frameWidth_ = 0; | |
151 frameHeight_ = 0; | |
152 LOG(WARNING) << "Missing tags in a DICOM image: Columns or Rows"; | |
153 } | |
154 | |
155 if (observer2_ != NULL) | |
156 { | |
157 ParallelSlices slices; | |
158 slices.AddSlice(SliceGeometry(*dataset_)); | |
159 observer2_->NotifySlicesAvailable(slices); | |
160 } | |
161 | |
162 NotifyGeometryReady(); | |
163 } | |
164 else if (operation->GetContent() == Content_Frame) | |
165 { | |
166 std::auto_ptr<Orthanc::PngReader> image(new Orthanc::PngReader); | |
167 image->ReadFromMemory(answer, answerSize); | |
168 | |
169 bool ok = (image->GetWidth() == frameWidth_ || | |
170 image->GetHeight() == frameHeight_); | |
171 | |
172 if (ok && | |
173 format_ == Orthanc::PixelFormat_SignedGrayscale16) | |
174 { | |
175 if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) | |
176 { | |
177 image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); | |
178 } | |
179 else | |
180 { | |
181 ok = false; | |
182 } | |
183 } | |
184 | |
185 if (ok) | |
186 { | |
187 SliceGeometry frameSlice(*dataset_); | |
188 NotifyLayerReady(FrameRenderer::CreateRenderer(image.release(), | |
189 operation->GetViewportSlice(), | |
190 frameSlice, *dataset_, | |
191 pixelSpacingX_, pixelSpacingY_, true), | |
192 operation->GetViewportSlice()); | |
193 } | |
194 else | |
195 { | |
196 NotifyLayerError(operation->GetViewportSlice()); | |
197 } | |
198 } | |
199 else | |
200 { | |
201 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
202 } | |
203 } | |
204 | |
205 | 121 |
206 bool OrthancFrameLayerSource::GetExtent(double& x1, | 122 bool OrthancFrameLayerSource::GetExtent(double& x1, |
207 double& y1, | 123 double& y1, |
208 double& x2, | 124 double& x2, |
209 double& y2, | 125 double& y2, |
210 const SliceGeometry& viewportSlice /* ignored */) | 126 const SliceGeometry& viewportSlice /* ignored */) |
211 { | 127 { |
212 if (!IsStarted() || | 128 bool ok = false; |
213 dataset_.get() == NULL) | 129 |
130 if (IsStarted() && | |
131 loader_.IsGeometryReady()) | |
214 { | 132 { |
215 return false; | 133 double tx1, ty1, tx2, ty2; |
134 | |
135 for (size_t i = 0; i < loader_.GetSliceCount(); i++) | |
136 { | |
137 if (FrameRenderer::ComputeFrameExtent(tx1, ty1, tx2, ty2, viewportSlice, loader_.GetSlice(i))) | |
138 { | |
139 if (ok) | |
140 { | |
141 x1 = std::min(x1, tx1); | |
142 y1 = std::min(y1, ty1); | |
143 x2 = std::min(x2, tx2); | |
144 y2 = std::min(y2, ty2); | |
145 } | |
146 else | |
147 { | |
148 // This is the first slice parallel to the viewport | |
149 x1 = tx1; | |
150 y1 = ty1; | |
151 x2 = tx2; | |
152 y2 = ty2; | |
153 ok = true; | |
154 } | |
155 } | |
156 } | |
216 } | 157 } |
217 else | 158 |
218 { | 159 return ok; |
219 SliceGeometry frameSlice(*dataset_); | |
220 return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, | |
221 viewportSlice, frameSlice, | |
222 frameWidth_, frameHeight_, | |
223 pixelSpacingX_, pixelSpacingY_); | |
224 } | |
225 } | 160 } |
226 | 161 |
227 | 162 |
228 void OrthancFrameLayerSource::ScheduleLayerCreation(const SliceGeometry& viewportSlice) | 163 void OrthancFrameLayerSource::ScheduleLayerCreation(const SliceGeometry& viewportSlice) |
229 { | 164 { |
230 if (!IsStarted()) | 165 size_t index; |
166 | |
167 if (!IsStarted() || | |
168 !loader_.IsGeometryReady()) | |
231 { | 169 { |
232 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 170 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
233 } | 171 } |
234 | 172 else if (loader_.LookupSlice(index, viewportSlice)) |
235 if (dataset_.get() == NULL) | |
236 { | 173 { |
237 NotifyLayerError(viewportSlice); | 174 loader_.ScheduleLoadSliceImage(index); |
238 } | 175 } |
239 else | 176 else |
240 { | 177 { |
241 std::string uri = ("/instances/" + instanceId_ + "/frames/" + | 178 LayerSourceBase::NotifyLayerError(viewportSlice); |
242 boost::lexical_cast<std::string>(frame_)); | |
243 | |
244 std::string compressed; | |
245 | |
246 switch (format_) | |
247 { | |
248 case Orthanc::PixelFormat_RGB24: | |
249 uri += "/preview"; | |
250 break; | |
251 | |
252 case Orthanc::PixelFormat_Grayscale16: | |
253 uri += "/image-uint16"; | |
254 break; | |
255 | |
256 case Orthanc::PixelFormat_SignedGrayscale16: | |
257 uri += "/image-int16"; | |
258 break; | |
259 | |
260 default: | |
261 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
262 } | |
263 | |
264 std::auto_ptr<Operation> operation(new Operation(Content_Frame)); | |
265 operation->SetViewportSlice(viewportSlice); | |
266 orthanc_.ScheduleGetRequest(*this, uri, operation.release()); | |
267 } | 179 } |
268 } | 180 } |
269 } | 181 } |