comparison Samples/Common/RtViewerView.cpp @ 1404:3e644f6fadd4

Three-viewport is now OK in SDL and Wasm
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 29 Apr 2020 22:06:24 +0200
parents Samples/Common/RtViewer.cpp@27e0a00bd3e8
children 5d7ee14dc1eb
comparison
equal deleted inserted replaced
1395:62dc0d737e7b 1404:3e644f6fadd4
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-2020 Osimis S.A., 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 // Sample app
22 #include "RtViewerView.h"
23 #include "RtViewerApp.h"
24 #include "SampleHelpers.h"
25
26 // Stone of Orthanc
27 #include <Framework/StoneInitialization.h>
28 #include <Framework/Scene2D/CairoCompositor.h>
29 #include <Framework/Scene2D/ColorTextureSceneLayer.h>
30 #include <Framework/Scene2D/OpenGLCompositor.h>
31 #include <Framework/Scene2D/PanSceneTracker.h>
32 #include <Framework/Scene2D/ZoomSceneTracker.h>
33 #include <Framework/Scene2D/RotateSceneTracker.h>
34
35 #include <Framework/Scene2DViewport/UndoStack.h>
36 #include <Framework/Scene2DViewport/CreateLineMeasureTracker.h>
37 #include <Framework/Scene2DViewport/CreateAngleMeasureTracker.h>
38 #include <Framework/Scene2DViewport/IFlexiblePointerTracker.h>
39 #include <Framework/Scene2DViewport/MeasureTool.h>
40 #include <Framework/Scene2DViewport/PredeclaredTypes.h>
41 #include <Framework/Volumes/VolumeSceneLayerSource.h>
42
43 #include <Framework/Oracle/GetOrthancWebViewerJpegCommand.h>
44 #include <Framework/Scene2D/GrayscaleStyleConfigurator.h>
45 #include <Framework/Scene2D/LookupTableStyleConfigurator.h>
46 #include <Framework/Volumes/DicomVolumeImageMPRSlicer.h>
47 #include <Framework/StoneException.h>
48
49 // Orthanc
50 #include <Core/Logging.h>
51 #include <Core/OrthancException.h>
52
53 // System
54 #include <boost/shared_ptr.hpp>
55 #include <boost/weak_ptr.hpp>
56 #include <boost/make_shared.hpp>
57
58 #include <stdio.h>
59
60
61 namespace OrthancStone
62 {
63 boost::shared_ptr<RtViewerApp> RtViewerView::GetApp()
64 {
65 return app_.lock();
66 }
67
68 void RtViewerView::DisplayInfoText()
69 {
70 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
71 ViewportController& controller = lock->GetController();
72 Scene2D& scene = controller.GetScene();
73
74 // do not try to use stuff too early!
75 OrthancStone::ICompositor& compositor = lock->GetCompositor();
76
77 std::stringstream msg;
78
79 for (std::map<std::string, std::string>::const_iterator kv = infoTextMap_.begin();
80 kv != infoTextMap_.end(); ++kv)
81 {
82 msg << kv->first << " : " << kv->second << std::endl;
83 }
84 std::string msgS = msg.str();
85
86 TextSceneLayer* layerP = NULL;
87 if (scene.HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX))
88 {
89 TextSceneLayer& layer = dynamic_cast<TextSceneLayer&>(
90 scene.GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX));
91 layerP = &layer;
92 }
93 else
94 {
95 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
96 layerP = layer.get();
97 layer->SetColor(0, 255, 0);
98 layer->SetFontIndex(1);
99 layer->SetBorder(20);
100 layer->SetAnchor(BitmapAnchor_TopLeft);
101 //layer->SetPosition(0,0);
102 scene.SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release());
103 }
104 // position the fixed info text in the upper right corner
105 layerP->SetText(msgS.c_str());
106 double cX = compositor.GetCanvasWidth() * (-0.5);
107 double cY = compositor.GetCanvasHeight() * (-0.5);
108 scene.GetCanvasToSceneTransform().Apply(cX, cY);
109 layerP->SetPosition(cX, cY);
110 lock->Invalidate();
111 }
112
113 void RtViewerView::DisplayFloatingCtrlInfoText(const PointerEvent& e)
114 {
115 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
116 ViewportController& controller = lock->GetController();
117 Scene2D& scene = controller.GetScene();
118
119 ScenePoint2D p = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform());
120
121 char buf[128];
122 sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)",
123 p.GetX(), p.GetY(),
124 e.GetMainPosition().GetX(), e.GetMainPosition().GetY());
125
126 if (scene.HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX))
127 {
128 TextSceneLayer& layer =
129 dynamic_cast<TextSceneLayer&>(scene.GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX));
130 layer.SetText(buf);
131 layer.SetPosition(p.GetX(), p.GetY());
132 }
133 else
134 {
135 std::unique_ptr<TextSceneLayer> layer(new TextSceneLayer);
136 layer->SetColor(0, 255, 0);
137 layer->SetText(buf);
138 layer->SetBorder(20);
139 layer->SetAnchor(BitmapAnchor_BottomCenter);
140 layer->SetPosition(p.GetX(), p.GetY());
141 scene.SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release());
142 }
143 }
144
145 void RtViewerView::HideInfoText()
146 {
147 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
148 ViewportController& controller = lock->GetController();
149 Scene2D& scene = controller.GetScene();
150
151 scene.DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX);
152 }
153
154 void RtViewerView::OnSceneTransformChanged(
155 const ViewportController::SceneTransformChanged& message)
156 {
157 DisplayInfoText();
158 }
159
160 void RtViewerView::Invalidate()
161 {
162 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
163 lock->GetCompositor().FitContent(lock->GetController().GetScene());
164 lock->Invalidate();
165 }
166
167 void RtViewerView::FitContent()
168 {
169 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
170 lock->GetCompositor().FitContent(lock->GetController().GetScene());
171 lock->Invalidate();
172 }
173
174 void RtViewerView::RetrieveGeometry()
175 {
176 const VolumeImageGeometry& geometry = GetApp()->GetMainGeometry();
177
178 const unsigned int depth = geometry.GetProjectionDepth(projection_);
179 currentPlane_ = depth / 2;
180
181 planes_.resize(depth);
182
183 for (unsigned int z = 0; z < depth; z++)
184 {
185 planes_[z] = geometry.GetProjectionSlice(projection_, z);
186 }
187
188 UpdateLayers();
189 }
190
191 void RtViewerView::UpdateLayers()
192 {
193 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
194
195 if (planes_.size() == 0)
196 {
197 RetrieveGeometry();
198 }
199
200 if (currentPlane_ < planes_.size())
201 {
202 if (ctVolumeLayerSource_.get() != NULL)
203 {
204 ctVolumeLayerSource_->Update(planes_[currentPlane_]);
205 }
206 if (doseVolumeLayerSource_.get() != NULL)
207 {
208 doseVolumeLayerSource_->Update(planes_[currentPlane_]);
209 }
210 if (structLayerSource_.get() != NULL)
211 {
212 structLayerSource_->Update(planes_[currentPlane_]);
213 }
214 }
215 lock->Invalidate();
216 }
217
218 void RtViewerView::PrepareViewport()
219 {
220 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
221 ViewportController& controller = lock->GetController();
222 Scene2D& scene = controller.GetScene();
223 ICompositor& compositor = lock->GetCompositor();
224
225 // False means we do NOT let a hi-DPI aware desktop managedr treat this as a legacy application that requires
226 // scaling.
227 controller.FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight());
228
229
230 compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT,
231 FONT_SIZE_0, Orthanc::Encoding_Latin1);
232 compositor.SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT,
233 FONT_SIZE_1, Orthanc::Encoding_Latin1);
234 }
235
236 void RtViewerView::SetInfoDisplayMessage(
237 std::string key, std::string value)
238 {
239 if (value == "")
240 infoTextMap_.erase(key);
241 else
242 infoTextMap_[key] = value;
243 DisplayInfoText();
244 }
245
246 void RtViewerView::RegisterMessages()
247 {
248 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
249 ViewportController& controller = lock->GetController();
250 Scene2D& scene = controller.GetScene();
251 Register<ViewportController::SceneTransformChanged>(controller, &RtViewerView::OnSceneTransformChanged);
252 }
253
254 void RtViewerView::CreateLayers(boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> ctLoader,
255 boost::shared_ptr<OrthancMultiframeVolumeLoader> doseLoader,
256 boost::shared_ptr<DicomVolumeImage> doseVolume,
257 boost::shared_ptr<DicomStructureSetLoader> rtstructLoader)
258 {
259 /**
260 Configure the CT
261 */
262 std::auto_ptr<GrayscaleStyleConfigurator> style(new GrayscaleStyleConfigurator);
263 style->SetLinearInterpolation(true);
264
265 this->SetCtVolumeSlicer(ctLoader, style.release());
266
267 {
268 std::unique_ptr<LookupTableStyleConfigurator> config(new LookupTableStyleConfigurator);
269 config->SetLookupTable(Orthanc::EmbeddedResources::COLORMAP_HOT);
270
271 boost::shared_ptr<DicomVolumeImageMPRSlicer> tmp(new DicomVolumeImageMPRSlicer(doseVolume));
272 this->SetDoseVolumeSlicer(tmp, config.release());
273 }
274
275 this->SetStructureSet(rtstructLoader);
276 }
277
278 void RtViewerView::SetCtVolumeSlicer(const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
279 OrthancStone::ILayerStyleConfigurator* style)
280 {
281 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
282 ViewportController& controller = lock->GetController();
283 Scene2D& scene = controller.GetScene();
284 int depth = scene.GetMaxDepth() + 1;
285
286 ctVolumeLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(scene, depth, volume));
287
288 if (style != NULL)
289 {
290 ctVolumeLayerSource_->SetConfigurator(style);
291 }
292 }
293
294 void RtViewerView::SetDoseVolumeSlicer(const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume,
295 OrthancStone::ILayerStyleConfigurator* style)
296 {
297 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
298 ViewportController& controller = lock->GetController();
299 Scene2D& scene = controller.GetScene();
300 int depth = scene.GetMaxDepth() + 1;
301
302 doseVolumeLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(scene, depth, volume));
303
304 if (style != NULL)
305 {
306 doseVolumeLayerSource_->SetConfigurator(style);
307 }
308 }
309
310 void RtViewerView::SetStructureSet(const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume)
311 {
312 std::unique_ptr<IViewport::ILock> lock(viewport_->Lock());
313 ViewportController& controller = lock->GetController();
314 Scene2D& scene = controller.GetScene();
315 int depth = scene.GetMaxDepth() + 1;
316
317 structLayerSource_.reset(new OrthancStone::VolumeSceneLayerSource(scene, depth, volume));
318 }
319 }