Mercurial > hg > orthanc-stone
comparison Samples/Common/RtViewerApp.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 | |
children | 07fac4fdbe07 |
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 "RtViewerApp.h" | |
23 #include "RtViewerView.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 const char* RtViewerGuiToolToString(size_t i) | |
64 { | |
65 static const char* descs[] = { | |
66 "RtViewerGuiTool_Rotate", | |
67 "RtViewerGuiTool_Pan", | |
68 "RtViewerGuiTool_Zoom", | |
69 "RtViewerGuiTool_LineMeasure", | |
70 "RtViewerGuiTool_CircleMeasure", | |
71 "RtViewerGuiTool_AngleMeasure", | |
72 "RtViewerGuiTool_EllipseMeasure", | |
73 "RtViewerGuiTool_LAST" | |
74 }; | |
75 if (i >= RtViewerGuiTool_LAST) | |
76 { | |
77 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Wrong tool index"); | |
78 } | |
79 return descs[i]; | |
80 } | |
81 | |
82 void RtViewerApp::SelectNextTool() | |
83 { | |
84 currentTool_ = static_cast<RtViewerGuiTool>(currentTool_ + 1); | |
85 if (currentTool_ == RtViewerGuiTool_LAST) | |
86 currentTool_ = static_cast<RtViewerGuiTool>(0);; | |
87 printf("Current tool is now: %s\n", RtViewerGuiToolToString(currentTool_)); | |
88 } | |
89 | |
90 void RtViewerApp::InvalidateAllViewports() | |
91 { | |
92 for (size_t i = 0; i < views_.size(); ++i) | |
93 { | |
94 views_[i]->Invalidate(); | |
95 } | |
96 } | |
97 | |
98 const VolumeImageGeometry& RtViewerApp::GetMainGeometry() | |
99 { | |
100 ORTHANC_ASSERT(geometryProvider_.get() != NULL); | |
101 ORTHANC_ASSERT(geometryProvider_->HasGeometry()); | |
102 const VolumeImageGeometry& geometry = geometryProvider_->GetImageGeometry(); | |
103 return geometry; | |
104 } | |
105 | |
106 RtViewerApp::RtViewerApp() | |
107 : currentTool_(RtViewerGuiTool_Rotate) | |
108 , undoStack_(new UndoStack) | |
109 { | |
110 // Create the volumes that will be filled later on | |
111 ctVolume_ = boost::make_shared<DicomVolumeImage>(); | |
112 doseVolume_ = boost::make_shared<DicomVolumeImage>(); | |
113 } | |
114 | |
115 boost::shared_ptr<RtViewerApp> RtViewerApp::Create() | |
116 { | |
117 boost::shared_ptr<RtViewerApp> thisOne(new RtViewerApp()); | |
118 return thisOne; | |
119 } | |
120 | |
121 void RtViewerApp::DisableTracker() | |
122 { | |
123 if (activeTracker_) | |
124 { | |
125 activeTracker_->Cancel(); | |
126 activeTracker_.reset(); | |
127 } | |
128 } | |
129 | |
130 void RtViewerApp::CreateView(const std::string& canvasId, VolumeProjection projection) | |
131 { | |
132 boost::shared_ptr<RtViewerView> | |
133 view(new RtViewerView(shared_from_this(), canvasId, projection)); | |
134 | |
135 view->RegisterMessages(); | |
136 | |
137 view->CreateLayers(ctLoader_, doseLoader_, doseVolume_, rtstructLoader_); | |
138 | |
139 views_.push_back(view); | |
140 } | |
141 | |
142 void RtViewerApp::CreateLoaders() | |
143 { | |
144 // the viewport hosts the scene | |
145 { | |
146 // "true" means use progressive quality (jpeg 50 --> jpeg 90 --> 16-bit raw) | |
147 // "false" means only using hi quality | |
148 // TODO: add flag for quality | |
149 ctLoader_ = OrthancSeriesVolumeProgressiveLoader::Create(*loadersContext_, ctVolume_, true); | |
150 | |
151 // we need to store the CT loader to ask from geometry details later on when geometry is loaded | |
152 geometryProvider_ = ctLoader_; | |
153 | |
154 doseLoader_ = OrthancMultiframeVolumeLoader::Create(*loadersContext_, doseVolume_); | |
155 rtstructLoader_ = DicomStructureSetLoader::Create(*loadersContext_); | |
156 } | |
157 | |
158 /** | |
159 Register for notifications issued by the loaders | |
160 */ | |
161 | |
162 Register<DicomVolumeImage::GeometryReadyMessage> | |
163 (*ctLoader_, &RtViewerApp::HandleGeometryReady); | |
164 | |
165 Register<OrthancSeriesVolumeProgressiveLoader::VolumeImageReadyInHighQuality> | |
166 (*ctLoader_, &RtViewerApp::HandleCTLoaded); | |
167 | |
168 Register<DicomVolumeImage::ContentUpdatedMessage> | |
169 (*ctLoader_, &RtViewerApp::HandleCTContentUpdated); | |
170 | |
171 Register<DicomVolumeImage::ContentUpdatedMessage> | |
172 (*doseLoader_, &RtViewerApp::HandleDoseLoaded); | |
173 | |
174 Register<DicomStructureSetLoader::StructuresReady> | |
175 (*rtstructLoader_, &RtViewerApp::HandleStructuresReady); | |
176 | |
177 Register<DicomStructureSetLoader::StructuresUpdated> | |
178 (*rtstructLoader_, &RtViewerApp::HandleStructuresUpdated); | |
179 } | |
180 | |
181 void RtViewerApp::StartLoaders() | |
182 { | |
183 ORTHANC_ASSERT(HasArgument("ctseries") && HasArgument("rtdose") && HasArgument("rtstruct")); | |
184 | |
185 LOG(INFO) << "About to load:"; | |
186 LOG(INFO) << " CT : " << GetArgument("ctseries"); | |
187 LOG(INFO) << " RTDOSE : " << GetArgument("rtdose"); | |
188 LOG(INFO) << " RTSTRUCT : " << GetArgument("rtstruct"); | |
189 ctLoader_->LoadSeries(GetArgument("ctseries")); | |
190 doseLoader_->LoadInstance(GetArgument("rtdose")); | |
191 rtstructLoader_->LoadInstanceFullVisibility(GetArgument("rtstruct")); | |
192 } | |
193 | |
194 void RtViewerApp::HandleGeometryReady(const DicomVolumeImage::GeometryReadyMessage& message) | |
195 { | |
196 for (size_t i = 0; i < views_.size(); ++i) | |
197 { | |
198 views_[i]->RetrieveGeometry(); | |
199 } | |
200 FitContent(); | |
201 UpdateLayersInAllViews(); | |
202 } | |
203 | |
204 void RtViewerApp::FitContent() | |
205 { | |
206 for (size_t i = 0; i < views_.size(); ++i) | |
207 { | |
208 views_[i]->FitContent(); | |
209 } | |
210 } | |
211 | |
212 void RtViewerApp::UpdateLayersInAllViews() | |
213 { | |
214 for (size_t i = 0; i < views_.size(); ++i) | |
215 { | |
216 views_[i]->UpdateLayers(); | |
217 } | |
218 } | |
219 | |
220 void RtViewerApp::HandleCTLoaded(const OrthancSeriesVolumeProgressiveLoader::VolumeImageReadyInHighQuality& message) | |
221 { | |
222 for (size_t i = 0; i < views_.size(); ++i) | |
223 { | |
224 views_[i]->RetrieveGeometry(); | |
225 } | |
226 UpdateLayersInAllViews(); | |
227 } | |
228 | |
229 void RtViewerApp::HandleCTContentUpdated(const DicomVolumeImage::ContentUpdatedMessage& message) | |
230 { | |
231 UpdateLayersInAllViews(); | |
232 } | |
233 | |
234 void RtViewerApp::HandleDoseLoaded(const DicomVolumeImage::ContentUpdatedMessage& message) | |
235 { | |
236 //TODO: compute dose extent, with outlier rejection | |
237 UpdateLayersInAllViews(); | |
238 } | |
239 | |
240 void RtViewerApp::HandleStructuresReady(const DicomStructureSetLoader::StructuresReady& message) | |
241 { | |
242 UpdateLayersInAllViews(); | |
243 } | |
244 | |
245 void RtViewerApp::HandleStructuresUpdated(const DicomStructureSetLoader::StructuresUpdated& message) | |
246 { | |
247 UpdateLayersInAllViews(); | |
248 } | |
249 | |
250 void RtViewerApp::SetArgument(const std::string& key, const std::string& value) | |
251 { | |
252 if (key == "loglevel") | |
253 OrthancStoneHelpers::SetLogLevel(value); | |
254 else | |
255 arguments_[key] = value; | |
256 } | |
257 | |
258 const std::string& RtViewerApp::GetArgument(const std::string& key) const | |
259 { | |
260 ORTHANC_ASSERT(HasArgument(key)); | |
261 return arguments_.at(key); | |
262 } | |
263 | |
264 bool RtViewerApp::HasArgument(const std::string& key) const | |
265 { | |
266 return (arguments_.find(key) != arguments_.end()); | |
267 } | |
268 } | |
269 |