Mercurial > hg > orthanc-stone
annotate Framework/Widgets/WorldSceneWidget.cpp @ 331:7ccf919faff0 am-2
simplify WorldSceneWidget
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 17 Oct 2018 15:18:48 +0200 |
parents | 7a364e44fbb4 |
children | 50e5ec1bdd46 |
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. | |
281 | 16 * |
47 | 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> |
313 | 27 #include "Core/Logging.h" |
0 | 28 |
29 namespace OrthancStone | |
30 { | |
31 static void MapMouseToScene(double& sceneX, | |
32 double& sceneY, | |
33 const ViewportGeometry& view, | |
34 int mouseX, | |
35 int mouseY) | |
36 { | |
37 // Take the center of the pixel | |
38 double x, y; | |
39 x = static_cast<double>(mouseX) + 0.5; | |
40 y = static_cast<double>(mouseY) + 0.5; | |
41 | |
42 view.MapDisplayToScene(sceneX, sceneY, x, y); | |
43 } | |
44 | |
45 | |
281 | 46 // this is an adapter between a IWorldSceneMouseTracker |
47 // that is tracking a mouse in scene coordinates/mm and | |
48 // an IMouseTracker that is tracking a mouse | |
49 // in screen coordinates/pixels. | |
0 | 50 class WorldSceneWidget::SceneMouseTracker : public IMouseTracker |
51 { | |
52 private: | |
53 ViewportGeometry view_; | |
54 std::auto_ptr<IWorldSceneMouseTracker> tracker_; | |
281 | 55 |
0 | 56 public: |
57 SceneMouseTracker(const ViewportGeometry& view, | |
58 IWorldSceneMouseTracker* tracker) : | |
59 view_(view), | |
60 tracker_(tracker) | |
61 { | |
62 assert(tracker != NULL); | |
63 } | |
64 | |
65 virtual void Render(Orthanc::ImageAccessor& target) | |
66 { | |
67 CairoSurface surface(target); | |
281 | 68 CairoContext context(surface); |
0 | 69 view_.ApplyTransform(context); |
70 tracker_->Render(context, view_.GetZoom()); | |
71 } | |
72 | |
281 | 73 virtual void MouseUp() |
0 | 74 { |
75 tracker_->MouseUp(); | |
76 } | |
77 | |
281 | 78 virtual void MouseMove(int x, |
0 | 79 int y) |
80 { | |
81 double sceneX, sceneY; | |
82 MapMouseToScene(sceneX, sceneY, view_, x, y); | |
83 tracker_->MouseMove(sceneX, sceneY); | |
84 } | |
85 }; | |
86 | |
87 | |
281 | 88 WorldSceneWidget::PanMouseTracker::PanMouseTracker(WorldSceneWidget& that, |
89 int x, | |
90 int y) : | |
91 that_(that), | |
92 downX_(x), | |
93 downY_(y) | |
0 | 94 { |
281 | 95 that_.view_.GetPan(previousPanX_, previousPanY_); |
96 } | |
97 | |
329
b10dfdb96866
removing WorldSceneWidget::IWorldObserver
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
327
diff
changeset
|
98 |
281 | 99 void WorldSceneWidget::PanMouseTracker::MouseMove(int x, int y) |
100 { | |
101 that_.view_.SetPan(previousPanX_ + x - downX_, | |
102 previousPanY_ + y - downY_); | |
103 } | |
0 | 104 |
329
b10dfdb96866
removing WorldSceneWidget::IWorldObserver
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
327
diff
changeset
|
105 |
281 | 106 WorldSceneWidget::ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that, |
107 int x, | |
108 int y) : | |
109 that_(that), | |
110 downX_(x), | |
111 downY_(y) | |
112 { | |
113 oldZoom_ = that_.view_.GetZoom(); | |
114 MapMouseToScene(centerX_, centerY_, that_.view_, downX_, downY_); | |
115 } | |
116 | |
117 void WorldSceneWidget::ZoomMouseTracker::MouseMove(int x, | |
118 int y) | |
119 { | |
120 static const double MIN_ZOOM = -4; | |
121 static const double MAX_ZOOM = 4; | |
122 | |
123 if (that_.view_.GetDisplayHeight() <= 3) | |
0 | 124 { |
313 | 125 LOG(WARNING) << "image is too small to zoom (current height = " << that_.view_.GetDisplayHeight() << ")"; |
126 return; | |
0 | 127 } |
128 | |
281 | 129 double dy = (static_cast<double>(y - downY_) / |
130 static_cast<double>(that_.view_.GetDisplayHeight() - 1)); // In the range [-1,1] | |
131 double z; | |
0 | 132 |
281 | 133 // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] |
134 if (dy < -1.0) | |
0 | 135 { |
281 | 136 z = MIN_ZOOM; |
0 | 137 } |
281 | 138 else if (dy > 1.0) |
0 | 139 { |
281 | 140 z = MAX_ZOOM; |
0 | 141 } |
281 | 142 else |
0 | 143 { |
281 | 144 z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; |
0 | 145 } |
146 | |
281 | 147 z = pow(2.0, z); |
0 | 148 |
281 | 149 that_.view_.SetZoom(oldZoom_ * z); |
0 | 150 |
281 | 151 // Correct the pan so that the original click point is kept at |
152 // the same location on the display | |
153 double panX, panY; | |
154 that_.view_.GetPan(panX, panY); | |
0 | 155 |
281 | 156 int tx, ty; |
157 that_.view_.MapSceneToDisplay(tx, ty, centerX_, centerY_); | |
158 that_.view_.SetPan(panX + static_cast<double>(downX_ - tx), | |
159 panY + static_cast<double>(downY_ - ty)); | |
160 } | |
0 | 161 |
162 | |
163 bool WorldSceneWidget::RenderCairo(CairoContext& context) | |
164 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
165 view_.ApplyTransform(context); |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
166 return RenderScene(context, view_); |
0 | 167 } |
168 | |
169 | |
170 void WorldSceneWidget::RenderMouseOverCairo(CairoContext& context, | |
171 int x, | |
172 int y) | |
173 { | |
174 ViewportGeometry view = GetView(); | |
175 view.ApplyTransform(context); | |
176 | |
177 double sceneX, sceneY; | |
178 MapMouseToScene(sceneX, sceneY, view, x, y); | |
331
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
179 |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
180 if (interactor_) |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
181 { |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
182 interactor_->MouseOver(context, *this, view, sceneX, sceneY, GetStatusBar()); |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
183 } |
0 | 184 } |
185 | |
186 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
187 void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) |
0 | 188 { |
109
53bd9277b025
using the Extent class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
91
diff
changeset
|
189 view.SetSceneExtent(GetSceneExtent()); |
0 | 190 } |
191 | |
192 | |
193 void WorldSceneWidget::SetSize(unsigned int width, | |
194 unsigned int height) | |
195 { | |
196 CairoWidget::SetSize(width, height); | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
197 view_.SetDisplaySize(width, height); |
0 | 198 } |
199 | |
200 | |
201 void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) | |
202 { | |
203 interactor_ = &interactor; | |
204 } | |
205 | |
206 | |
330 | 207 void WorldSceneWidget::FitContent() |
0 | 208 { |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
209 SetSceneExtent(view_); |
330 | 210 view_.FitContent(); |
0 | 211 |
278 | 212 NotifyContentChanged(); |
0 | 213 } |
214 | |
215 | |
216 void WorldSceneWidget::SetView(const ViewportGeometry& view) | |
217 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
218 view_ = view; |
0 | 219 |
278 | 220 NotifyContentChanged(); |
0 | 221 } |
222 | |
223 | |
224 ViewportGeometry WorldSceneWidget::GetView() | |
225 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
226 return view_; |
0 | 227 } |
228 | |
229 | |
230 IMouseTracker* WorldSceneWidget::CreateMouseTracker(MouseButton button, | |
231 int x, | |
232 int y, | |
233 KeyboardModifiers modifiers) | |
234 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
235 double sceneX, sceneY; |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
236 MapMouseToScene(sceneX, sceneY, view_, x, y); |
0 | 237 |
281 | 238 // asks the Widget Interactor to provide a mouse tracker |
331
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
239 std::auto_ptr<IWorldSceneMouseTracker> tracker; |
0 | 240 |
331
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
241 if (interactor_) |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
242 { |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
243 tracker.reset(interactor_->CreateMouseTracker(*this, view_, button, modifiers, sceneX, sceneY, GetStatusBar())); |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
244 } |
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
245 |
0 | 246 if (tracker.get() != NULL) |
247 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
248 return new SceneMouseTracker(view_, tracker.release()); |
0 | 249 } |
331
7ccf919faff0
simplify WorldSceneWidget
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
330
diff
changeset
|
250 |
281 | 251 //TODO: allow Interactor to create Pan & Zoom |
0 | 252 switch (button) |
253 { | |
281 | 254 case MouseButton_Middle: |
255 return new PanMouseTracker(*this, x, y); | |
0 | 256 |
281 | 257 case MouseButton_Right: |
258 return new ZoomMouseTracker(*this, x, y); | |
0 | 259 |
281 | 260 default: |
261 return NULL; | |
0 | 262 } |
263 } | |
264 | |
265 | |
266 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, | |
267 int x, | |
268 int y, | |
281 | 269 KeyboardModifiers modifiers) |
0 | 270 { |
271 if (interactor_) | |
272 { | |
273 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); | |
274 } | |
275 } | |
276 | |
277 | |
327 | 278 void WorldSceneWidget::KeyPressed(KeyboardKeys key, |
279 char keyChar, | |
0 | 280 KeyboardModifiers modifiers) |
281 { | |
282 if (interactor_) | |
283 { | |
327 | 284 interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar()); |
0 | 285 } |
286 } | |
287 } |