Mercurial > hg > orthanc-stone
annotate Framework/Widgets/LayerWidget.cpp @ 77:f5f54ed8d307 wasm
refactoring
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 24 May 2017 21:13:29 +0200 |
parents | 30c768873d47 |
children | 93b917b02fee |
rev | line source |
---|---|
66 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017 Osimis, Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "LayerWidget.h" | |
23 | |
24 #include "../../Resources/Orthanc/Core/Logging.h" | |
25 | |
26 namespace OrthancStone | |
27 { | |
28 class LayerWidget::Scene : public boost::noncopyable | |
29 { | |
30 private: | |
31 SliceGeometry slice_; | |
32 size_t countMissing_; | |
33 std::vector<ILayerRenderer*> renderers_; | |
34 | |
35 void DeleteLayer(size_t index) | |
36 { | |
37 if (index >= renderers_.size()) | |
38 { | |
39 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
40 } | |
41 | |
42 assert(countMissing_ <= renderers_.size()); | |
43 | |
44 if (renderers_[index] != NULL) | |
45 { | |
46 assert(countMissing_ < renderers_.size()); | |
47 delete renderers_[index]; | |
48 renderers_[index] = NULL; | |
49 countMissing_++; | |
50 } | |
51 } | |
52 | |
53 public: | |
54 Scene(const SliceGeometry& slice, | |
55 size_t countLayers) : | |
56 slice_(slice), | |
57 countMissing_(countLayers), | |
58 renderers_(countLayers, NULL) | |
59 { | |
60 } | |
61 | |
62 ~Scene() | |
63 { | |
64 for (size_t i = 0; i < renderers_.size(); i++) | |
65 { | |
66 DeleteLayer(i); | |
67 } | |
68 } | |
69 | |
70 void SetLayer(size_t index, | |
71 ILayerRenderer* renderer) // Takes ownership | |
72 { | |
73 if (renderer == NULL) | |
74 { | |
75 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
76 } | |
77 | |
78 DeleteLayer(index); | |
79 | |
80 renderers_[index] = renderer; | |
81 countMissing_--; | |
82 } | |
83 | |
84 const SliceGeometry& GetSlice() const | |
85 { | |
86 return slice_; | |
87 } | |
88 | |
89 bool IsComplete() const | |
90 { | |
91 return countMissing_ == 0; | |
92 } | |
93 | |
94 bool IsSamePlane(const SliceGeometry& slice, | |
95 double sliceThickness) | |
96 { | |
97 return slice_.IsSamePlane(slice, sliceThickness); | |
98 } | |
99 | |
100 bool RenderScene(CairoContext& context, | |
101 const ViewportGeometry& view) | |
102 { | |
103 bool fullQuality = true; | |
104 | |
105 for (size_t i = 0; i < renderers_.size(); i++) | |
106 { | |
107 if (renderers_[i] != NULL && | |
77 | 108 !renderers_[i]->RenderLayer(context, view, slice_)) |
66 | 109 { |
110 return false; | |
111 } | |
112 | |
113 if (renderers_[i] != NULL && | |
114 !renderers_[i]->IsFullQuality()) | |
115 { | |
116 fullQuality = false; | |
117 } | |
118 } | |
119 | |
120 if (!fullQuality) | |
121 { | |
122 double x, y; | |
123 view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10); | |
124 | |
125 cairo_t *cr = context.GetObject(); | |
126 cairo_translate(cr, x, y); | |
127 cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2 * M_PI); | |
128 cairo_set_line_width(cr, 2.0 / view.GetZoom()); | |
129 cairo_set_source_rgb(cr, 1, 1, 1); | |
130 cairo_stroke_preserve(cr); | |
131 cairo_set_source_rgb(cr, 1, 0, 0); | |
132 cairo_fill(cr); | |
133 } | |
134 | |
135 return true; | |
136 } | |
137 | |
138 void SetLayerStyle(size_t index, | |
139 const RenderStyle& style) | |
140 { | |
141 if (renderers_[index] != NULL) | |
142 { | |
143 renderers_[index]->SetLayerStyle(style); | |
144 } | |
145 } | |
146 }; | |
147 | |
148 | |
149 bool LayerWidget::LookupLayer(size_t& index /* out */, | |
150 ILayerSource& layer) const | |
151 { | |
152 LayersIndex::const_iterator found = layersIndex_.find(&layer); | |
153 | |
154 if (found == layersIndex_.end()) | |
155 { | |
156 return false; | |
157 } | |
158 else | |
159 { | |
160 index = found->second; | |
161 assert(index < layers_.size() && | |
162 layers_[index] == &layer); | |
163 return true; | |
164 } | |
165 } | |
166 | |
167 | |
168 void LayerWidget::GetSceneExtent(double& x1, | |
169 double& y1, | |
170 double& x2, | |
171 double& y2) | |
172 { | |
173 bool first = true; | |
174 | |
175 for (size_t i = 0; i < layers_.size(); i++) | |
176 { | |
177 double ax, ay, bx, by; | |
178 | |
179 assert(layers_[i] != NULL); | |
180 if (layers_[i]->GetExtent(ax, ay, bx, by, slice_)) | |
181 { | |
182 if (ax > bx) | |
183 { | |
184 std::swap(ax, bx); | |
185 } | |
186 | |
187 if (ay > by) | |
188 { | |
189 std::swap(ay, by); | |
190 } | |
191 | |
71
30c768873d47
OrthancSliceLoader::ScheduleLoadInstance
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
192 LOG(INFO) << "Extent of layer " << i << ": (" << ax << "," << ay << ")->(" << bx << "," << by << ")"; |
66 | 193 |
194 if (first) | |
195 { | |
196 x1 = ax; | |
197 y1 = ay; | |
198 x2 = bx; | |
199 y2 = by; | |
200 first = false; | |
201 } | |
202 else | |
203 { | |
204 x1 = std::min(x1, ax); | |
205 y1 = std::min(y1, ay); | |
206 x2 = std::max(x2, bx); | |
207 y2 = std::max(y2, by); | |
208 } | |
209 } | |
210 } | |
211 | |
212 if (first) | |
213 { | |
214 // Set a default extent of (-1,-1) -> (0,0) | |
215 x1 = -1; | |
216 y1 = -1; | |
217 x2 = 1; | |
218 y2 = 1; | |
219 } | |
220 | |
221 // Ensure the extent is non-empty | |
222 if (x1 >= x2) | |
223 { | |
224 double tmp = x1; | |
225 x1 = tmp - 0.5; | |
226 x2 = tmp + 0.5; | |
227 } | |
228 | |
229 if (y1 >= y2) | |
230 { | |
231 double tmp = y1; | |
232 y1 = tmp - 0.5; | |
233 y2 = tmp + 0.5; | |
234 } | |
235 } | |
236 | |
237 | |
238 bool LayerWidget::RenderScene(CairoContext& context, | |
239 const ViewportGeometry& view) | |
240 { | |
241 if (currentScene_.get() != NULL) | |
242 { | |
243 return currentScene_->RenderScene(context, view); | |
244 } | |
245 else | |
246 { | |
247 return true; | |
248 } | |
249 } | |
250 | |
251 | |
252 void LayerWidget::ResetPendingScene() | |
253 { | |
254 pendingScene_.reset(new Scene(slice_, layers_.size())); | |
255 } | |
256 | |
257 | |
258 void LayerWidget::UpdateLayer(size_t index, | |
259 ILayerRenderer* renderer, | |
77 | 260 const Slice& slice) |
66 | 261 { |
71
30c768873d47
OrthancSliceLoader::ScheduleLoadInstance
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
262 LOG(INFO) << "Updating layer " << index; |
66 | 263 |
264 std::auto_ptr<ILayerRenderer> tmp(renderer); | |
265 | |
266 if (renderer == NULL) | |
267 { | |
268 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
269 } | |
270 | |
271 if (index >= layers_.size()) | |
272 { | |
273 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
274 } | |
275 | |
276 assert(layers_.size() == styles_.size()); | |
277 renderer->SetLayerStyle(styles_[index]); | |
278 | |
279 if (currentScene_.get() != NULL && | |
77 | 280 currentScene_->IsSamePlane(slice.GetGeometry(), sliceThickness_)) |
66 | 281 { |
282 currentScene_->SetLayer(index, tmp.release()); | |
283 NotifyChange(); | |
284 } | |
285 else if (pendingScene_.get() != NULL && | |
77 | 286 pendingScene_->IsSamePlane(slice.GetGeometry(), sliceThickness_)) |
66 | 287 { |
288 pendingScene_->SetLayer(index, tmp.release()); | |
289 | |
290 if (currentScene_.get() == NULL || | |
291 pendingScene_->IsComplete()) | |
292 { | |
293 currentScene_ = pendingScene_; | |
294 NotifyChange(); | |
295 } | |
296 } | |
297 } | |
298 | |
299 | |
300 LayerWidget::LayerWidget() : | |
301 started_(false), | |
302 sliceThickness_(1) | |
303 { | |
304 SetBackgroundCleared(true); | |
305 } | |
306 | |
307 | |
308 LayerWidget::~LayerWidget() | |
309 { | |
310 for (size_t i = 0; i < layers_.size(); i++) | |
311 { | |
312 delete layers_[i]; | |
313 } | |
314 } | |
315 | |
316 | |
317 size_t LayerWidget::AddLayer(ILayerSource* layer) // Takes ownership | |
318 { | |
319 if (layer == NULL) | |
320 { | |
321 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
322 } | |
323 | |
324 size_t index = layers_.size(); | |
325 layers_.push_back(layer); | |
326 styles_.push_back(RenderStyle()); | |
327 layersIndex_[layer] = index; | |
328 | |
329 ResetPendingScene(); | |
330 layer->SetObserver(*this); | |
331 | |
332 return index; | |
333 } | |
334 | |
335 | |
336 void LayerWidget::SetLayerStyle(size_t layer, | |
337 const RenderStyle& style) | |
338 { | |
339 if (layer >= layers_.size()) | |
340 { | |
341 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
342 } | |
343 | |
344 assert(layers_.size() == styles_.size()); | |
345 styles_[layer] = style; | |
346 | |
347 if (currentScene_.get() != NULL) | |
348 { | |
349 currentScene_->SetLayerStyle(layer, style); | |
350 } | |
351 | |
352 if (pendingScene_.get() != NULL) | |
353 { | |
354 pendingScene_->SetLayerStyle(layer, style); | |
355 } | |
356 | |
357 NotifyChange(); | |
358 } | |
359 | |
360 | |
361 void LayerWidget::SetSlice(const SliceGeometry& slice, | |
362 double sliceThickness) | |
363 { | |
364 if (!slice_.IsSamePlane(slice, 100.0 * std::numeric_limits<double>::epsilon())) | |
365 { | |
366 if (currentScene_.get() == NULL || | |
367 (pendingScene_.get() != NULL && | |
368 pendingScene_->IsComplete())) | |
369 { | |
370 currentScene_ = pendingScene_; | |
371 } | |
372 | |
373 slice_ = slice; | |
374 sliceThickness_ = sliceThickness; | |
375 ResetPendingScene(); | |
376 | |
377 if (started_) | |
378 { | |
379 for (size_t i = 0; i < layers_.size(); i++) | |
380 { | |
381 assert(layers_[i] != NULL); | |
382 layers_[i]->ScheduleLayerCreation(slice_); | |
383 } | |
384 } | |
385 } | |
386 } | |
387 | |
388 | |
389 void LayerWidget::NotifyGeometryReady(ILayerSource& source) | |
390 { | |
391 size_t i; | |
392 if (LookupLayer(i, source)) | |
71
30c768873d47
OrthancSliceLoader::ScheduleLoadInstance
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
66
diff
changeset
|
393 LOG(INFO) << "Geometry ready for layer " << i; |
66 | 394 |
395 SetDefaultView(); | |
396 layers_[i]->ScheduleLayerCreation(slice_); | |
397 } | |
398 | |
399 | |
77 | 400 void LayerWidget::NotifyGeometryError(ILayerSource& source) |
401 { | |
402 LOG(ERROR) << "Cannot get geometry"; | |
403 } | |
404 | |
405 | |
66 | 406 void LayerWidget::NotifySourceChange(ILayerSource& source) |
407 { | |
408 source.ScheduleLayerCreation(slice_); | |
409 } | |
410 | |
411 | |
412 void LayerWidget::NotifySliceChange(ILayerSource& source, | |
77 | 413 const Slice& slice) |
66 | 414 { |
77 | 415 if (slice.ContainsPlane(slice_)) |
66 | 416 { |
417 source.ScheduleLayerCreation(slice_); | |
418 } | |
419 } | |
420 | |
421 | |
422 void LayerWidget::NotifyLayerReady(ILayerRenderer* renderer, | |
423 ILayerSource& source, | |
77 | 424 const Slice& slice) |
66 | 425 { |
426 std::auto_ptr<ILayerRenderer> tmp(renderer); | |
427 | |
428 size_t index; | |
429 if (LookupLayer(index, source)) | |
430 { | |
77 | 431 LOG(INFO) << "Renderer ready for layer " << index; |
432 UpdateLayer(index, tmp.release(), slice); | |
66 | 433 } |
434 } | |
435 | |
436 | |
437 void LayerWidget::NotifyLayerError(ILayerSource& source, | |
438 const SliceGeometry& viewportSlice) | |
439 { | |
440 size_t i; | |
441 if (LookupLayer(i, source)) | |
442 LOG(ERROR) << "Error on layer " << i; | |
443 } | |
444 | |
445 | |
446 void LayerWidget::Start() | |
447 { | |
448 if (started_) | |
449 { | |
450 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
451 } | |
452 | |
453 for (size_t i = 0; i < layers_.size(); i++) | |
454 { | |
455 assert(layers_[i] != NULL); | |
456 layers_[i]->Start(); | |
457 } | |
458 } | |
459 } |