0
|
1 /**
|
|
2 * Stone of Orthanc
|
|
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
|
|
4 * Department, University Hospital of Liege, Belgium
|
|
5 *
|
|
6 * This program is free software: you can redistribute it and/or
|
|
7 * modify it under the terms of the GNU General Public License as
|
|
8 * published by the Free Software Foundation, either version 3 of the
|
|
9 * License, or (at your option) any later version.
|
|
10 *
|
|
11 * In addition, as a special exception, the copyright holders of this
|
|
12 * program give permission to link the code of its release with the
|
|
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
|
|
14 * that use the same license as the "OpenSSL" library), and distribute
|
|
15 * the linked executables. You must obey the GNU General Public License
|
|
16 * in all respects for all of the code used other than "OpenSSL". If you
|
|
17 * modify file(s) with this exception, you may extend this exception to
|
|
18 * your version of the file(s), but you are not obligated to do so. If
|
|
19 * you do not wish to do so, delete this exception statement from your
|
|
20 * version. If you delete this exception statement from all source files
|
|
21 * in the program, then also delete it here.
|
|
22 *
|
|
23 * This program is distributed in the hope that it will be useful, but
|
|
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
26 * General Public License for more details.
|
|
27 *
|
|
28 * You should have received a copy of the GNU General Public License
|
|
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
30 **/
|
|
31
|
|
32
|
|
33 #define _USE_MATH_DEFINES // To access M_PI in Visual Studio
|
|
34 #include <cmath>
|
|
35
|
|
36 #include "LayeredSceneWidget.h"
|
|
37
|
16
|
38 #include "../../Resources/Orthanc/Core/OrthancException.h"
|
0
|
39
|
|
40 namespace OrthancStone
|
|
41 {
|
|
42 class LayeredSceneWidget::Renderers : public boost::noncopyable
|
|
43 {
|
|
44 private:
|
|
45 boost::mutex mutex_;
|
|
46 std::vector<ILayerRenderer*> renderers_;
|
|
47 std::vector<bool> assigned_;
|
|
48
|
|
49 void Assign(size_t index,
|
|
50 ILayerRenderer* renderer)
|
|
51 {
|
|
52 if (index >= renderers_.size())
|
|
53 {
|
|
54 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
|
|
55 }
|
|
56
|
|
57 if (renderers_[index] != NULL)
|
|
58 {
|
|
59 delete renderers_[index];
|
|
60 }
|
|
61
|
|
62 renderers_[index] = renderer;
|
|
63 assigned_[index] = true;
|
|
64 }
|
|
65
|
|
66 public:
|
|
67 Renderers(size_t size)
|
|
68 {
|
|
69 renderers_.resize(size);
|
|
70 assigned_.resize(size, false);
|
|
71 }
|
|
72
|
|
73 ~Renderers()
|
|
74 {
|
|
75 for (size_t i = 0; i < renderers_.size(); i++)
|
|
76 {
|
|
77 Assign(i, NULL);
|
|
78 }
|
|
79 }
|
|
80
|
|
81 static void Merge(Renderers& target,
|
|
82 Renderers& source)
|
|
83 {
|
|
84 boost::mutex::scoped_lock lockSource(source.mutex_);
|
|
85 boost::mutex::scoped_lock lockTarget(target.mutex_);
|
|
86
|
|
87 size_t count = target.renderers_.size();
|
|
88 if (count != source.renderers_.size())
|
|
89 {
|
|
90 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
|
|
91 }
|
|
92
|
|
93 for (size_t i = 0; i < count; i++)
|
|
94 {
|
|
95 if (source.assigned_[i])
|
|
96 {
|
|
97 target.Assign(i, source.renderers_[i]); // Transfers ownership
|
|
98 source.renderers_[i] = NULL;
|
|
99 source.assigned_[i] = false;
|
|
100 }
|
|
101 }
|
|
102 }
|
|
103
|
|
104 void SetRenderer(size_t index,
|
|
105 ILayerRenderer* renderer) // Takes ownership
|
|
106 {
|
|
107 boost::mutex::scoped_lock lock(mutex_);
|
|
108 Assign(index, renderer);
|
|
109 }
|
|
110
|
|
111 bool RenderScene(CairoContext& context,
|
|
112 const ViewportGeometry& view)
|
|
113 {
|
|
114 boost::mutex::scoped_lock lock(mutex_);
|
|
115
|
|
116 bool fullQuality = true;
|
|
117
|
|
118 for (size_t i = 0; i < renderers_.size(); i++)
|
|
119 {
|
|
120 if (renderers_[i] != NULL &&
|
|
121 !renderers_[i]->RenderLayer(context, view))
|
|
122 {
|
|
123 return false;
|
|
124 }
|
|
125
|
|
126 if (renderers_[i] != NULL &&
|
|
127 !renderers_[i]->IsFullQuality())
|
|
128 {
|
|
129 fullQuality = false;
|
|
130 }
|
|
131 }
|
|
132
|
|
133 if (!fullQuality)
|
|
134 {
|
|
135 double x, y;
|
|
136 view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10);
|
|
137
|
|
138 cairo_t *cr = context.GetObject();
|
|
139 cairo_translate(cr, x, y);
|
|
140 cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2 * M_PI);
|
|
141 cairo_set_line_width(cr, 2.0 / view.GetZoom());
|
|
142 cairo_set_source_rgb(cr, 1, 1, 1);
|
|
143 cairo_stroke_preserve(cr);
|
|
144 cairo_set_source_rgb(cr, 1, 0, 0);
|
|
145 cairo_fill(cr);
|
|
146 }
|
|
147
|
|
148 return true;
|
|
149 }
|
|
150
|
|
151 void SetLayerStyle(size_t index,
|
|
152 const RenderStyle& style)
|
|
153 {
|
|
154 boost::mutex::scoped_lock lock(mutex_);
|
|
155
|
|
156 if (renderers_[index] != NULL)
|
|
157 {
|
|
158 renderers_[index]->SetLayerStyle(style);
|
|
159 }
|
|
160 }
|
|
161 };
|
|
162
|
|
163
|
|
164
|
|
165 class LayeredSceneWidget::PendingLayers : public boost::noncopyable
|
|
166 {
|
|
167 private:
|
|
168 boost::mutex mutex_;
|
|
169 boost::condition_variable elementAvailable_;
|
|
170 size_t layerCount_;
|
|
171 std::list<size_t> queue_;
|
|
172 std::vector<bool> layersToUpdate_;
|
|
173 bool continue_;
|
|
174
|
|
175 void TagAllLayers()
|
|
176 {
|
|
177 queue_.clear();
|
|
178
|
|
179 for (unsigned int i = 0; i < layerCount_; i++)
|
|
180 {
|
|
181 queue_.push_back(i);
|
|
182 layersToUpdate_[i] = true;
|
|
183 }
|
|
184
|
|
185 if (layerCount_ != 0)
|
|
186 {
|
|
187 elementAvailable_.notify_one();
|
|
188 }
|
|
189 }
|
|
190
|
|
191 public:
|
|
192 PendingLayers() :
|
|
193 layerCount_(0),
|
|
194 continue_(true)
|
|
195 {
|
|
196 }
|
|
197
|
|
198 void Stop()
|
|
199 {
|
|
200 continue_ = false;
|
|
201 elementAvailable_.notify_one();
|
|
202 }
|
|
203
|
|
204 void SetLayerCount(size_t count)
|
|
205 {
|
|
206 boost::mutex::scoped_lock lock(mutex_);
|
|
207
|
|
208 layerCount_ = count;
|
|
209 layersToUpdate_.resize(count);
|
|
210
|
|
211 TagAllLayers();
|
|
212 }
|
|
213
|
|
214 void InvalidateAllLayers()
|
|
215 {
|
|
216 boost::mutex::scoped_lock lock(mutex_);
|
|
217 TagAllLayers();
|
|
218 }
|
|
219
|
|
220 void InvalidateLayer(size_t layer)
|
|
221 {
|
|
222 boost::mutex::scoped_lock lock(mutex_);
|
|
223
|
|
224 if (layer < layerCount_)
|
|
225 {
|
|
226 if (layersToUpdate_[layer])
|
|
227 {
|
|
228 // The layer is already scheduled for update, ignore this
|
|
229 // invalidation
|
|
230 }
|
|
231 else
|
|
232 {
|
|
233 queue_.push_back(layer);
|
|
234 layersToUpdate_[layer] = true;
|
|
235 elementAvailable_.notify_one();
|
|
236 }
|
|
237 }
|
|
238 }
|
|
239
|
|
240 bool Dequeue(size_t& layer,
|
|
241 bool& isLast)
|
|
242 {
|
|
243 boost::mutex::scoped_lock lock(mutex_);
|
|
244
|
|
245 // WARNING: Do NOT use "timed_wait" on condition variables, as
|
|
246 // sleeping is not properly supported by Boost for Google NaCl
|
|
247 while (queue_.empty() &&
|
|
248 continue_)
|
|
249 {
|
|
250 elementAvailable_.wait(lock);
|
|
251 }
|
|
252
|
|
253 if (!continue_)
|
|
254 {
|
|
255 return false;
|
|
256 }
|
|
257
|
|
258 layer = queue_.front();
|
|
259 layersToUpdate_[layer] = false;
|
|
260 queue_.pop_front();
|
|
261
|
|
262 isLast = queue_.empty();
|
|
263
|
|
264 return true;
|
|
265 }
|
|
266 };
|
|
267
|
|
268
|
|
269 class LayeredSceneWidget::Layer : public ISliceableVolume::IChangeObserver
|
|
270 {
|
|
271 private:
|
|
272 boost::mutex mutex_;
|
|
273 std::auto_ptr<ILayerRendererFactory> factory_;
|
|
274 PendingLayers& layers_;
|
|
275 size_t index_;
|
|
276 std::auto_ptr<RenderStyle> style_;
|
|
277
|
|
278 public:
|
|
279 Layer(ILayerRendererFactory* factory,
|
|
280 PendingLayers& layers,
|
|
281 size_t index) :
|
|
282 factory_(factory),
|
|
283 layers_(layers),
|
|
284 index_(index)
|
|
285 {
|
|
286 if (factory == NULL)
|
|
287 {
|
|
288 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
|
|
289 }
|
|
290 }
|
|
291
|
|
292 virtual void NotifyChange(const OrthancStone::ISliceableVolume&)
|
|
293 {
|
|
294 layers_.InvalidateLayer(index_);
|
|
295 }
|
|
296
|
|
297 void Start()
|
|
298 {
|
|
299 if (factory_->HasSourceVolume())
|
|
300 {
|
|
301 factory_->GetSourceVolume().Register(*this);
|
|
302 }
|
|
303 }
|
|
304
|
|
305 void Stop()
|
|
306 {
|
|
307 if (factory_->HasSourceVolume())
|
|
308 {
|
|
309 factory_->GetSourceVolume().Unregister(*this);
|
|
310 }
|
|
311 }
|
|
312
|
|
313 bool GetExtent(double& x1,
|
|
314 double& y1,
|
|
315 double& x2,
|
|
316 double& y2,
|
|
317 const SliceGeometry& displaySlice)
|
|
318 {
|
|
319 boost::mutex::scoped_lock lock(mutex_);
|
|
320 assert(factory_.get() != NULL);
|
|
321 return factory_->GetExtent(x1, y1, x2, y2, displaySlice);
|
|
322 }
|
|
323
|
|
324 RenderStyle GetStyle()
|
|
325 {
|
|
326 boost::mutex::scoped_lock lock(mutex_);
|
|
327
|
|
328 if (style_.get() == NULL)
|
|
329 {
|
|
330 return RenderStyle();
|
|
331 }
|
|
332 else
|
|
333 {
|
|
334 return *style_;
|
|
335 }
|
|
336 }
|
|
337
|
|
338 void SetStyle(const RenderStyle& style)
|
|
339 {
|
|
340 boost::mutex::scoped_lock lock(mutex_);
|
|
341 style_.reset(new RenderStyle(style));
|
|
342 }
|
|
343
|
|
344
|
|
345 ILayerRenderer* CreateRenderer(const SliceGeometry& displaySlice)
|
|
346 {
|
|
347 boost::mutex::scoped_lock lock(mutex_);
|
|
348 assert(factory_.get() != NULL);
|
|
349
|
|
350 std::auto_ptr<ILayerRenderer> renderer(factory_->CreateLayerRenderer(displaySlice));
|
|
351
|
|
352 if (renderer.get() != NULL &&
|
|
353 style_.get() != NULL)
|
|
354 {
|
|
355 renderer->SetLayerStyle(*style_);
|
|
356 }
|
|
357
|
|
358 return renderer.release();
|
|
359 }
|
|
360 };
|
|
361
|
|
362
|
|
363
|
|
364 SliceGeometry LayeredSceneWidget::GetSlice()
|
|
365 {
|
|
366 boost::mutex::scoped_lock lock(sliceMutex_);
|
|
367 return slice_;
|
|
368 }
|
|
369
|
|
370
|
|
371 void LayeredSceneWidget::UpdateStep()
|
|
372 {
|
|
373 size_t layer = 0;
|
|
374 bool isLast = true;
|
|
375 if (!pendingLayers_->Dequeue(layer, isLast))
|
|
376 {
|
|
377 return;
|
|
378 }
|
|
379
|
|
380 SliceGeometry slice = GetSlice();
|
|
381
|
|
382 std::auto_ptr<ILayerRenderer> renderer;
|
|
383 renderer.reset(layers_[layer]->CreateRenderer(slice));
|
|
384
|
|
385 if (renderer.get() != NULL)
|
|
386 {
|
|
387 pendingRenderers_->SetRenderer(layer, renderer.release());
|
|
388 }
|
|
389 else
|
|
390 {
|
|
391 pendingRenderers_->SetRenderer(layer, NULL);
|
|
392 }
|
|
393
|
|
394 if (isLast)
|
|
395 {
|
|
396 Renderers::Merge(*renderers_, *pendingRenderers_);
|
|
397 NotifyChange();
|
|
398 }
|
|
399 }
|
|
400
|
|
401
|
|
402 bool LayeredSceneWidget::RenderScene(CairoContext& context,
|
|
403 const ViewportGeometry& view)
|
|
404 {
|
|
405 assert(IsStarted());
|
|
406 return renderers_->RenderScene(context, view);
|
|
407 }
|
|
408
|
|
409
|
|
410 LayeredSceneWidget::LayeredSceneWidget()
|
|
411 {
|
|
412 pendingLayers_.reset(new PendingLayers);
|
|
413 SetBackgroundCleared(true);
|
|
414 }
|
|
415
|
|
416
|
|
417 LayeredSceneWidget::~LayeredSceneWidget()
|
|
418 {
|
|
419 for (size_t i = 0; i < layers_.size(); i++)
|
|
420 {
|
|
421 assert(layers_[i] != NULL);
|
|
422 delete layers_[i];
|
|
423 }
|
|
424 }
|
|
425
|
|
426
|
|
427 void LayeredSceneWidget::GetSceneExtent(double& x1,
|
|
428 double& y1,
|
|
429 double& x2,
|
|
430 double& y2)
|
|
431 {
|
|
432 boost::mutex::scoped_lock lock(sliceMutex_);
|
|
433
|
|
434 bool first = true;
|
|
435
|
|
436 for (size_t i = 0; i < layers_.size(); i++)
|
|
437 {
|
|
438 double ax, ay, bx, by;
|
|
439
|
|
440 assert(layers_[i] != NULL);
|
|
441 if (layers_[i]->GetExtent(ax, ay, bx, by, slice_))
|
|
442 {
|
|
443 if (ax > bx)
|
|
444 {
|
|
445 std::swap(ax, bx);
|
|
446 }
|
|
447
|
|
448 if (ay > by)
|
|
449 {
|
|
450 std::swap(ay, by);
|
|
451 }
|
|
452
|
|
453 if (first)
|
|
454 {
|
|
455 x1 = ax;
|
|
456 y1 = ay;
|
|
457 x2 = bx;
|
|
458 y2 = by;
|
|
459 first = false;
|
|
460 }
|
|
461 else
|
|
462 {
|
|
463 x1 = std::min(x1, ax);
|
|
464 y1 = std::min(y1, ay);
|
|
465 x2 = std::max(x2, bx);
|
|
466 y2 = std::max(y2, by);
|
|
467 }
|
|
468 }
|
|
469 }
|
|
470
|
|
471 if (first)
|
|
472 {
|
|
473 x1 = -1;
|
|
474 y1 = -1;
|
|
475 x2 = 1;
|
|
476 y2 = 1;
|
|
477 }
|
|
478
|
|
479 // Ensure the extent is non-empty
|
|
480 if (x1 >= x2)
|
|
481 {
|
|
482 double tmp = x1;
|
|
483 x1 = tmp - 0.5;
|
|
484 x2 = tmp + 0.5;
|
|
485 }
|
|
486
|
|
487 if (y1 >= y2)
|
|
488 {
|
|
489 double tmp = y1;
|
|
490 y1 = tmp - 0.5;
|
|
491 y2 = tmp + 0.5;
|
|
492 }
|
|
493 }
|
|
494
|
|
495
|
|
496
|
|
497 ILayerRendererFactory& LayeredSceneWidget::AddLayer(size_t& layerIndex,
|
|
498 ILayerRendererFactory* factory)
|
|
499 {
|
|
500 if (IsStarted())
|
|
501 {
|
|
502 // Start() has already been invoked
|
|
503 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
|
|
504 }
|
|
505
|
|
506 layerIndex = layers_.size();
|
|
507 layers_.push_back(new Layer(factory, *pendingLayers_, layers_.size()));
|
|
508
|
|
509 return *factory;
|
|
510 }
|
|
511
|
|
512
|
|
513 void LayeredSceneWidget::AddLayer(ILayerRendererFactory* factory)
|
|
514 {
|
|
515 size_t layerIndex; // Ignored
|
|
516 AddLayer(layerIndex, factory);
|
|
517 }
|
|
518
|
|
519
|
|
520 RenderStyle LayeredSceneWidget::GetLayerStyle(size_t layer)
|
|
521 {
|
|
522 if (layer >= layers_.size())
|
|
523 {
|
|
524 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
|
|
525 }
|
|
526
|
|
527 return layers_[layer]->GetStyle();
|
|
528 }
|
|
529
|
|
530
|
|
531 void LayeredSceneWidget::SetLayerStyle(size_t layer,
|
|
532 const RenderStyle& style)
|
|
533 {
|
|
534 if (layer >= layers_.size())
|
|
535 {
|
|
536 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
|
|
537 }
|
|
538
|
|
539 layers_[layer]->SetStyle(style);
|
|
540
|
|
541 if (renderers_.get() != NULL)
|
|
542 {
|
|
543 renderers_->SetLayerStyle(layer, style);
|
|
544 }
|
|
545
|
|
546 InvalidateLayer(layer);
|
|
547 }
|
|
548
|
|
549
|
|
550
|
|
551 struct LayeredSceneWidget::SliceChangeFunctor
|
|
552 {
|
|
553 const SliceGeometry& slice_;
|
|
554
|
|
555 SliceChangeFunctor(const SliceGeometry& slice) :
|
|
556 slice_(slice)
|
|
557 {
|
|
558 }
|
|
559
|
|
560 void operator() (ISliceObserver& observer,
|
|
561 const LayeredSceneWidget& source)
|
|
562 {
|
|
563 observer.NotifySliceChange(source, slice_);
|
|
564 }
|
|
565 };
|
|
566
|
|
567
|
|
568 void LayeredSceneWidget::SetSlice(const SliceGeometry& slice)
|
|
569 {
|
|
570 {
|
|
571 boost::mutex::scoped_lock lock(sliceMutex_);
|
|
572 slice_ = slice;
|
|
573 }
|
|
574
|
|
575 InvalidateAllLayers();
|
|
576
|
|
577 SliceChangeFunctor functor(slice);
|
|
578 observers_.Notify(this, functor);
|
|
579 }
|
|
580
|
|
581
|
|
582 void LayeredSceneWidget::InvalidateLayer(unsigned int layer)
|
|
583 {
|
|
584 pendingLayers_->InvalidateLayer(layer);
|
|
585 //NotifyChange(); // TODO Understand why this makes the SDL engine not update the display subsequently
|
|
586 }
|
|
587
|
|
588
|
|
589 void LayeredSceneWidget::InvalidateAllLayers()
|
|
590 {
|
|
591 pendingLayers_->InvalidateAllLayers();
|
|
592 //NotifyChange(); // TODO Understand why this makes the SDL engine not update the display subsequently
|
|
593 }
|
|
594
|
|
595
|
|
596 void LayeredSceneWidget::Start()
|
|
597 {
|
|
598 if (IsStarted())
|
|
599 {
|
|
600 // Start() has already been invoked
|
|
601 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
|
|
602 }
|
|
603
|
|
604 for (size_t i = 0; i < layers_.size(); i++)
|
|
605 {
|
|
606 layers_[i]->Start();
|
|
607 }
|
|
608
|
|
609 renderers_.reset(new Renderers(layers_.size()));
|
|
610 pendingRenderers_.reset(new Renderers(layers_.size()));
|
|
611
|
|
612 pendingLayers_->SetLayerCount(layers_.size());
|
|
613
|
|
614 WorldSceneWidget::Start();
|
|
615 }
|
|
616
|
|
617
|
|
618 void LayeredSceneWidget::Stop()
|
|
619 {
|
|
620 if (!IsStarted())
|
|
621 {
|
|
622 // Stop() has already been invoked
|
|
623 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
|
|
624 }
|
|
625
|
|
626 pendingLayers_->Stop();
|
|
627 WorldSceneWidget::Stop();
|
|
628
|
|
629 renderers_.reset(NULL);
|
|
630 pendingRenderers_.reset(NULL);
|
|
631
|
|
632 for (size_t i = 0; i < layers_.size(); i++)
|
|
633 {
|
|
634 layers_[i]->Stop();
|
|
635 }
|
|
636 }
|
|
637 }
|