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 }