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