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