Mercurial > hg > orthanc-stone
annotate Framework/Widgets/WorldSceneWidget.cpp @ 262:77fdab5b5d6e am-2
cleanup + todos
author | am@osimis.io |
---|---|
date | Tue, 17 Jul 2018 18:28:12 +0200 |
parents | fccffbf99ba1 |
children | 8a86695fcbc3 |
rev | line source |
---|---|
0 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
134
4cff7b1ed31d
upgrade to year 2018
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
47
diff
changeset
|
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
47 | 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. | |
0 | 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 | |
47 | 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 | |
0 | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | |
20 | |
21 | |
22 #include "WorldSceneWidget.h" | |
23 | |
110
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
109
diff
changeset
|
24 #include <math.h> |
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
109
diff
changeset
|
25 #include <memory> |
53025eecbc95
renamed SliceGeometry as CoordinateSystem3D
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
109
diff
changeset
|
26 #include <cassert> |
0 | 27 |
28 namespace OrthancStone | |
29 { | |
30 static void MapMouseToScene(double& sceneX, | |
31 double& sceneY, | |
32 const ViewportGeometry& view, | |
33 int mouseX, | |
34 int mouseY) | |
35 { | |
36 // Take the center of the pixel | |
37 double x, y; | |
38 x = static_cast<double>(mouseX) + 0.5; | |
39 y = static_cast<double>(mouseY) + 0.5; | |
40 | |
41 view.MapDisplayToScene(sceneX, sceneY, x, y); | |
42 } | |
43 | |
44 | |
45 struct WorldSceneWidget::SizeChangeFunctor | |
46 { | |
47 ViewportGeometry& view_; | |
48 | |
49 SizeChangeFunctor(ViewportGeometry& view) : | |
50 view_(view) | |
51 { | |
52 } | |
53 | |
54 void operator() (IWorldObserver& observer, | |
55 const WorldSceneWidget& source) | |
56 { | |
57 observer.NotifySizeChange(source, view_); | |
58 } | |
59 }; | |
60 | |
61 | |
62 class WorldSceneWidget::SceneMouseTracker : public IMouseTracker | |
63 { | |
64 private: | |
65 ViewportGeometry view_; | |
66 std::auto_ptr<IWorldSceneMouseTracker> tracker_; | |
67 | |
68 public: | |
69 SceneMouseTracker(const ViewportGeometry& view, | |
70 IWorldSceneMouseTracker* tracker) : | |
71 view_(view), | |
72 tracker_(tracker) | |
73 { | |
74 assert(tracker != NULL); | |
75 } | |
76 | |
77 virtual void Render(Orthanc::ImageAccessor& target) | |
78 { | |
79 CairoSurface surface(target); | |
80 CairoContext context(surface); | |
81 view_.ApplyTransform(context); | |
82 tracker_->Render(context, view_.GetZoom()); | |
83 } | |
84 | |
85 virtual void MouseUp() | |
86 { | |
87 tracker_->MouseUp(); | |
88 } | |
89 | |
90 virtual void MouseMove(int x, | |
91 int y) | |
92 { | |
93 double sceneX, sceneY; | |
94 MapMouseToScene(sceneX, sceneY, view_, x, y); | |
95 tracker_->MouseMove(sceneX, sceneY); | |
96 } | |
97 }; | |
98 | |
99 | |
100 class WorldSceneWidget::PanMouseTracker : public IMouseTracker | |
101 { | |
102 private: | |
103 WorldSceneWidget& that_; | |
104 double previousPanX_; | |
105 double previousPanY_; | |
106 double downX_; | |
107 double downY_; | |
108 | |
109 public: | |
110 PanMouseTracker(WorldSceneWidget& that, | |
111 int x, | |
112 int y) : | |
113 that_(that), | |
114 downX_(x), | |
115 downY_(y) | |
116 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
117 that_.view_.GetPan(previousPanX_, previousPanY_); |
0 | 118 } |
119 | |
120 virtual void Render(Orthanc::ImageAccessor& surface) | |
121 { | |
122 } | |
123 | |
124 virtual void MouseUp() | |
125 { | |
126 } | |
127 | |
128 virtual void MouseMove(int x, | |
129 int y) | |
130 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
131 that_.view_.SetPan(previousPanX_ + x - downX_, |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
132 previousPanY_ + y - downY_); |
0 | 133 |
91 | 134 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
0 | 135 } |
136 }; | |
137 | |
138 | |
139 class WorldSceneWidget::ZoomMouseTracker : public IMouseTracker | |
140 { | |
141 private: | |
142 WorldSceneWidget& that_; | |
143 int downX_; | |
144 int downY_; | |
145 double centerX_; | |
146 double centerY_; | |
147 double oldZoom_; | |
148 | |
149 public: | |
150 ZoomMouseTracker(WorldSceneWidget& that, | |
151 int x, | |
152 int y) : | |
153 that_(that), | |
154 downX_(x), | |
155 downY_(y) | |
156 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
157 oldZoom_ = that_.view_.GetZoom(); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
158 MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); |
0 | 159 } |
160 | |
161 virtual void Render(Orthanc::ImageAccessor& surface) | |
162 { | |
163 } | |
164 | |
165 virtual void MouseUp() | |
166 { | |
167 } | |
168 | |
169 virtual void MouseMove(int x, | |
170 int y) | |
171 { | |
172 static const double MIN_ZOOM = -4; | |
173 static const double MAX_ZOOM = 4; | |
174 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
175 if (that_.view_.GetDisplayHeight() <= 3) |
0 | 176 { |
177 return; // Cannot zoom on such a small image | |
178 } | |
179 | |
180 double dy = (static_cast<double>(y - downY_) / | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
181 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] |
0 | 182 double z; |
183 | |
184 // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] | |
185 if (dy < -1.0) | |
186 { | |
187 z = MIN_ZOOM; | |
188 } | |
189 else if (dy > 1.0) | |
190 { | |
191 z = MAX_ZOOM; | |
192 } | |
193 else | |
194 { | |
195 z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; | |
196 } | |
197 | |
198 z = pow(2.0, z); | |
199 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
200 that_.view_.SetZoom(oldZoom_ * z); |
0 | 201 |
202 // Correct the pan so that the original click point is kept at | |
203 // the same location on the display | |
204 double panX, panY; | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
205 that_.view_.GetPan(panX, panY); |
0 | 206 |
207 int tx, ty; | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
208 that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
209 that_.view_.SetPan(panX + static_cast<double>(downX_ - tx), |
0 | 210 panY + static_cast<double>(downY_ - ty)); |
211 | |
91 | 212 that_.observers_.Apply(that_, &IWorldObserver::NotifyViewChange, that_.view_); |
0 | 213 } |
214 }; | |
215 | |
216 | |
217 bool WorldSceneWidget::RenderCairo(CairoContext& context) | |
218 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
219 view_.ApplyTransform(context); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
220 return RenderScene(context, view_); |
0 | 221 } |
222 | |
223 | |
224 void WorldSceneWidget::RenderMouseOverCairo(CairoContext& context, | |
225 int x, | |
226 int y) | |
227 { | |
228 ViewportGeometry view = GetView(); | |
229 view.ApplyTransform(context); | |
230 | |
231 double sceneX, sceneY; | |
232 MapMouseToScene(sceneX, sceneY, view, x, y); | |
233 RenderSceneMouseOver(context, view, sceneX, sceneY); | |
234 } | |
235 | |
236 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
237 void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) |
0 | 238 { |
109
53bd9277b025
using the Extent class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
91
diff
changeset
|
239 view.SetSceneExtent(GetSceneExtent()); |
0 | 240 } |
241 | |
242 | |
243 void WorldSceneWidget::SetSize(unsigned int width, | |
244 unsigned int height) | |
245 { | |
246 CairoWidget::SetSize(width, height); | |
247 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
248 view_.SetDisplaySize(width, height); |
0 | 249 |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
250 if (observers_.IsEmpty()) |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
251 { |
66 | 252 // Without a size observer, reset to the default view |
253 // view_.SetDefaultView(); | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
254 } |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
255 else |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
256 { |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
257 // With a size observer, let it decide which view to use |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
258 SizeChangeFunctor functor(view_); |
91 | 259 observers_.Notify(*this, functor); |
0 | 260 } |
261 } | |
262 | |
263 | |
264 void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) | |
265 { | |
266 interactor_ = &interactor; | |
267 } | |
268 | |
269 | |
270 void WorldSceneWidget::SetDefaultView() | |
271 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
272 SetSceneExtent(view_); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
273 view_.SetDefaultView(); |
0 | 274 |
275 NotifyChange(); | |
276 | |
91 | 277 observers_.Apply(*this, &IWorldObserver::NotifyViewChange, view_); |
0 | 278 } |
279 | |
280 | |
281 void WorldSceneWidget::SetView(const ViewportGeometry& view) | |
282 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
283 view_ = view; |
0 | 284 |
285 NotifyChange(); | |
286 | |
91 | 287 observers_.Apply(*this, &IWorldObserver::NotifyViewChange, view_); |
0 | 288 } |
289 | |
290 | |
291 ViewportGeometry WorldSceneWidget::GetView() | |
292 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
293 return view_; |
0 | 294 } |
295 | |
296 | |
297 IMouseTracker* WorldSceneWidget::CreateMouseTracker(MouseButton button, | |
298 int x, | |
299 int y, | |
300 KeyboardModifiers modifiers) | |
301 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
302 double sceneX, sceneY; |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
303 MapMouseToScene(sceneX, sceneY, view_, x, y); |
0 | 304 |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
305 std::auto_ptr<IWorldSceneMouseTracker> tracker |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
306 (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); |
0 | 307 |
308 if (tracker.get() != NULL) | |
309 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
310 return new SceneMouseTracker(view_, tracker.release()); |
0 | 311 } |
312 | |
313 switch (button) | |
314 { | |
315 case MouseButton_Middle: | |
316 return new PanMouseTracker(*this, x, y); | |
317 | |
318 case MouseButton_Right: | |
319 return new ZoomMouseTracker(*this, x, y); | |
320 | |
321 default: | |
322 return NULL; | |
323 } | |
324 } | |
325 | |
326 | |
327 void WorldSceneWidget::RenderSceneMouseOver(CairoContext& context, | |
328 const ViewportGeometry& view, | |
329 double x, | |
330 double y) | |
331 { | |
332 if (interactor_) | |
333 { | |
59 | 334 interactor_->MouseOver(context, *this, view, x, y, GetStatusBar()); |
0 | 335 } |
336 } | |
337 | |
338 IWorldSceneMouseTracker* WorldSceneWidget::CreateMouseSceneTracker(const ViewportGeometry& view, | |
339 MouseButton button, | |
340 double x, | |
341 double y, | |
342 KeyboardModifiers modifiers) | |
343 { | |
344 if (interactor_) | |
345 { | |
59 | 346 return interactor_->CreateMouseTracker(*this, view, button, x, y, GetStatusBar()); |
0 | 347 } |
348 else | |
349 { | |
350 return NULL; | |
351 } | |
352 } | |
353 | |
354 | |
355 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, | |
356 int x, | |
357 int y, | |
358 KeyboardModifiers modifiers) | |
359 { | |
360 if (interactor_) | |
361 { | |
362 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); | |
363 } | |
364 } | |
365 | |
366 | |
367 void WorldSceneWidget::KeyPressed(char key, | |
368 KeyboardModifiers modifiers) | |
369 { | |
370 if (interactor_) | |
371 { | |
372 interactor_->KeyPressed(*this, key, modifiers, GetStatusBar()); | |
373 } | |
374 } | |
375 } |