Mercurial > hg > orthanc-stone
annotate Framework/Widgets/WorldSceneWidget.cpp @ 330:7a364e44fbb4 am-2
renamed SetDefaultView in FitContent
author | am@osimis.io |
---|---|
date | Wed, 17 Oct 2018 12:45:52 +0200 |
parents | b10dfdb96866 |
children | 7ccf919faff0 |
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); | |
179 RenderSceneMouseOver(context, view, sceneX, sceneY); | |
180 } | |
181 | |
182 | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
183 void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) |
0 | 184 { |
109
53bd9277b025
using the Extent class
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
91
diff
changeset
|
185 view.SetSceneExtent(GetSceneExtent()); |
0 | 186 } |
187 | |
188 | |
189 void WorldSceneWidget::SetSize(unsigned int width, | |
190 unsigned int height) | |
191 { | |
192 CairoWidget::SetSize(width, height); | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
193 view_.SetDisplaySize(width, height); |
0 | 194 } |
195 | |
196 | |
197 void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) | |
198 { | |
199 interactor_ = &interactor; | |
200 } | |
201 | |
202 | |
330 | 203 void WorldSceneWidget::FitContent() |
0 | 204 { |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
205 SetSceneExtent(view_); |
330 | 206 view_.FitContent(); |
0 | 207 |
278 | 208 NotifyContentChanged(); |
0 | 209 } |
210 | |
211 | |
212 void WorldSceneWidget::SetView(const ViewportGeometry& view) | |
213 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
214 view_ = view; |
0 | 215 |
278 | 216 NotifyContentChanged(); |
0 | 217 } |
218 | |
219 | |
220 ViewportGeometry WorldSceneWidget::GetView() | |
221 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
222 return view_; |
0 | 223 } |
224 | |
225 | |
226 IMouseTracker* WorldSceneWidget::CreateMouseTracker(MouseButton button, | |
227 int x, | |
228 int y, | |
229 KeyboardModifiers modifiers) | |
230 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
231 double sceneX, sceneY; |
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
232 MapMouseToScene(sceneX, sceneY, view_, x, y); |
0 | 233 |
281 | 234 // asks the Widget Interactor to provide a mouse tracker |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
235 std::auto_ptr<IWorldSceneMouseTracker> tracker |
281 | 236 (CreateMouseSceneTracker(view_, button, sceneX, sceneY, modifiers)); |
0 | 237 |
238 if (tracker.get() != NULL) | |
239 { | |
53
c2dc924f1a63
removing threading out of the framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
48
diff
changeset
|
240 return new SceneMouseTracker(view_, tracker.release()); |
0 | 241 } |
281 | 242 //TODO: allow Interactor to create Pan & Zoom |
0 | 243 switch (button) |
244 { | |
281 | 245 case MouseButton_Middle: |
246 return new PanMouseTracker(*this, x, y); | |
0 | 247 |
281 | 248 case MouseButton_Right: |
249 return new ZoomMouseTracker(*this, x, y); | |
0 | 250 |
281 | 251 default: |
252 return NULL; | |
0 | 253 } |
254 } | |
255 | |
256 | |
257 void WorldSceneWidget::RenderSceneMouseOver(CairoContext& context, | |
258 const ViewportGeometry& view, | |
259 double x, | |
260 double y) | |
261 { | |
262 if (interactor_) | |
263 { | |
59 | 264 interactor_->MouseOver(context, *this, view, x, y, GetStatusBar()); |
0 | 265 } |
266 } | |
267 | |
268 IWorldSceneMouseTracker* WorldSceneWidget::CreateMouseSceneTracker(const ViewportGeometry& view, | |
269 MouseButton button, | |
270 double x, | |
271 double y, | |
272 KeyboardModifiers modifiers) | |
273 { | |
274 if (interactor_) | |
275 { | |
281 | 276 return interactor_->CreateMouseTracker(*this, view, button, modifiers, x, y, GetStatusBar()); |
0 | 277 } |
278 else | |
279 { | |
280 return NULL; | |
281 } | |
282 } | |
283 | |
284 | |
285 void WorldSceneWidget::MouseWheel(MouseWheelDirection direction, | |
286 int x, | |
287 int y, | |
281 | 288 KeyboardModifiers modifiers) |
0 | 289 { |
290 if (interactor_) | |
291 { | |
292 interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); | |
293 } | |
294 } | |
295 | |
296 | |
327 | 297 void WorldSceneWidget::KeyPressed(KeyboardKeys key, |
298 char keyChar, | |
0 | 299 KeyboardModifiers modifiers) |
300 { | |
301 if (interactor_) | |
302 { | |
327 | 303 interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar()); |
0 | 304 } |
305 } | |
306 } |