comparison Applications/Samples/Common/RtViewerView.cpp @ 1538:d1806b4e4839

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