comparison Applications/Samples/SingleFrameEditorApplication.h @ 415:c0589c3173fd

finished reorganization
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 13 Nov 2018 10:36:53 +0100
parents f7616c010056
children aee3d7941c9b
comparison
equal deleted inserted replaced
414:f7616c010056 415:c0589c3173fd
21 21
22 #pragma once 22 #pragma once
23 23
24 #include "SampleApplicationBase.h" 24 #include "SampleApplicationBase.h"
25 25
26 #include "../../Framework/Radiography/RadiographyLayerCropTracker.h"
26 #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h" 27 #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h"
28 #include "../../Framework/Radiography/RadiographyLayerResizeTracker.h"
27 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h" 29 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h"
28 #include "../../Framework/Radiography/RadiographyScene.h" 30 #include "../../Framework/Radiography/RadiographyScene.h"
29 #include "../../Framework/Radiography/RadiographySceneCommand.h" 31 #include "../../Framework/Radiography/RadiographySceneCommand.h"
30 #include "../../Framework/Radiography/RadiographyWidget.h" 32 #include "../../Framework/Radiography/RadiographyWidget.h"
31 33 #include "../../Framework/Radiography/RadiographyWindowingTracker.h"
32 #include "../../Framework/Toolbox/UndoRedoStack.h"
33 34
34 #include <Core/Images/FontRegistry.h> 35 #include <Core/Images/FontRegistry.h>
35 #include <Core/Images/Image.h>
36 #include <Core/Images/ImageProcessing.h>
37 #include <Core/Images/PamReader.h>
38 #include <Core/Images/PamWriter.h>
39 #include <Core/Images/PngWriter.h>
40 #include <Core/Logging.h> 36 #include <Core/Logging.h>
41 #include <Core/OrthancException.h> 37 #include <Core/OrthancException.h>
42 #include <Core/Toolbox.h>
43 #include <Plugins/Samples/Common/DicomDatasetReader.h>
44 #include <Plugins/Samples/Common/FullOrthancDataset.h>
45 38
46 39
47 // Export using PAM is faster than using PNG, but requires Orthanc 40 // Export using PAM is faster than using PNG, but requires Orthanc
48 // core >= 1.4.3 41 // core >= 1.4.3
49 #define EXPORT_USING_PAM 1 42 #define EXPORT_USING_PAM 1
50 43
51 44
52 #include <boost/math/special_functions/round.hpp>
53
54
55 namespace OrthancStone 45 namespace OrthancStone
56 { 46 {
57 class RadiographyLayerCropTracker : public IWorldSceneMouseTracker
58 {
59 private:
60 UndoRedoStack& undoRedoStack_;
61 RadiographyScene::LayerAccessor accessor_;
62 Corner corner_;
63 unsigned int cropX_;
64 unsigned int cropY_;
65 unsigned int cropWidth_;
66 unsigned int cropHeight_;
67
68 class UndoRedoCommand : public RadiographySceneCommand
69 {
70 private:
71 unsigned int sourceCropX_;
72 unsigned int sourceCropY_;
73 unsigned int sourceCropWidth_;
74 unsigned int sourceCropHeight_;
75 unsigned int targetCropX_;
76 unsigned int targetCropY_;
77 unsigned int targetCropWidth_;
78 unsigned int targetCropHeight_;
79
80 protected:
81 virtual void UndoInternal(RadiographyLayer& layer) const
82 {
83 layer.SetCrop(sourceCropX_, sourceCropY_, sourceCropWidth_, sourceCropHeight_);
84 }
85
86 virtual void RedoInternal(RadiographyLayer& layer) const
87 {
88 layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_);
89 }
90
91 public:
92 UndoRedoCommand(const RadiographyLayerCropTracker& tracker) :
93 RadiographySceneCommand(tracker.accessor_),
94 sourceCropX_(tracker.cropX_),
95 sourceCropY_(tracker.cropY_),
96 sourceCropWidth_(tracker.cropWidth_),
97 sourceCropHeight_(tracker.cropHeight_)
98 {
99 tracker.accessor_.GetLayer().GetCrop(targetCropX_, targetCropY_,
100 targetCropWidth_, targetCropHeight_);
101 }
102 };
103
104
105 public:
106 RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack,
107 RadiographyScene& scene,
108 const ViewportGeometry& view,
109 size_t layer,
110 double x,
111 double y,
112 Corner corner) :
113 undoRedoStack_(undoRedoStack),
114 accessor_(scene, layer),
115 corner_(corner)
116 {
117 if (accessor_.IsValid())
118 {
119 accessor_.GetLayer().GetCrop(cropX_, cropY_, cropWidth_, cropHeight_);
120 }
121 }
122
123 virtual bool HasRender() const
124 {
125 return false;
126 }
127
128 virtual void Render(CairoContext& context,
129 double zoom)
130 {
131 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
132 }
133
134 virtual void MouseUp()
135 {
136 if (accessor_.IsValid())
137 {
138 undoRedoStack_.Add(new UndoRedoCommand(*this));
139 }
140 }
141
142 virtual void MouseMove(int displayX,
143 int displayY,
144 double sceneX,
145 double sceneY)
146 {
147 if (accessor_.IsValid())
148 {
149 unsigned int x, y;
150
151 RadiographyLayer& layer = accessor_.GetLayer();
152 if (layer.GetPixel(x, y, sceneX, sceneY))
153 {
154 unsigned int targetX, targetWidth;
155
156 if (corner_ == Corner_TopLeft ||
157 corner_ == Corner_BottomLeft)
158 {
159 targetX = std::min(x, cropX_ + cropWidth_);
160 targetWidth = cropX_ + cropWidth_ - targetX;
161 }
162 else
163 {
164 targetX = cropX_;
165 targetWidth = std::max(x, cropX_) - cropX_;
166 }
167
168 unsigned int targetY, targetHeight;
169
170 if (corner_ == Corner_TopLeft ||
171 corner_ == Corner_TopRight)
172 {
173 targetY = std::min(y, cropY_ + cropHeight_);
174 targetHeight = cropY_ + cropHeight_ - targetY;
175 }
176 else
177 {
178 targetY = cropY_;
179 targetHeight = std::max(y, cropY_) - cropY_;
180 }
181
182 layer.SetCrop(targetX, targetY, targetWidth, targetHeight);
183 }
184 }
185 }
186 };
187
188
189 class RadiographyLayerResizeTracker : public IWorldSceneMouseTracker
190 {
191 private:
192 UndoRedoStack& undoRedoStack_;
193 RadiographyScene::LayerAccessor accessor_;
194 bool roundScaling_;
195 double originalSpacingX_;
196 double originalSpacingY_;
197 double originalPanX_;
198 double originalPanY_;
199 Corner oppositeCorner_;
200 double oppositeX_;
201 double oppositeY_;
202 double baseScaling_;
203
204 static double ComputeDistance(double x1,
205 double y1,
206 double x2,
207 double y2)
208 {
209 double dx = x1 - x2;
210 double dy = y1 - y2;
211 return sqrt(dx * dx + dy * dy);
212 }
213
214 class UndoRedoCommand : public RadiographySceneCommand
215 {
216 private:
217 double sourceSpacingX_;
218 double sourceSpacingY_;
219 double sourcePanX_;
220 double sourcePanY_;
221 double targetSpacingX_;
222 double targetSpacingY_;
223 double targetPanX_;
224 double targetPanY_;
225
226 protected:
227 virtual void UndoInternal(RadiographyLayer& layer) const
228 {
229 layer.SetPixelSpacing(sourceSpacingX_, sourceSpacingY_);
230 layer.SetPan(sourcePanX_, sourcePanY_);
231 }
232
233 virtual void RedoInternal(RadiographyLayer& layer) const
234 {
235 layer.SetPixelSpacing(targetSpacingX_, targetSpacingY_);
236 layer.SetPan(targetPanX_, targetPanY_);
237 }
238
239 public:
240 UndoRedoCommand(const RadiographyLayerResizeTracker& tracker) :
241 RadiographySceneCommand(tracker.accessor_),
242 sourceSpacingX_(tracker.originalSpacingX_),
243 sourceSpacingY_(tracker.originalSpacingY_),
244 sourcePanX_(tracker.originalPanX_),
245 sourcePanY_(tracker.originalPanY_),
246 targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()),
247 targetSpacingY_(tracker.accessor_.GetLayer().GetPixelSpacingY()),
248 targetPanX_(tracker.accessor_.GetLayer().GetPanX()),
249 targetPanY_(tracker.accessor_.GetLayer().GetPanY())
250 {
251 }
252 };
253
254
255 public:
256 RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack,
257 RadiographyScene& scene,
258 size_t layer,
259 double x,
260 double y,
261 Corner corner,
262 bool roundScaling) :
263 undoRedoStack_(undoRedoStack),
264 accessor_(scene, layer),
265 roundScaling_(roundScaling)
266 {
267 if (accessor_.IsValid() &&
268 accessor_.GetLayer().IsResizeable())
269 {
270 originalSpacingX_ = accessor_.GetLayer().GetPixelSpacingX();
271 originalSpacingY_ = accessor_.GetLayer().GetPixelSpacingY();
272 originalPanX_ = accessor_.GetLayer().GetPanX();
273 originalPanY_ = accessor_.GetLayer().GetPanY();
274
275 switch (corner)
276 {
277 case Corner_TopLeft:
278 oppositeCorner_ = Corner_BottomRight;
279 break;
280
281 case Corner_TopRight:
282 oppositeCorner_ = Corner_BottomLeft;
283 break;
284
285 case Corner_BottomLeft:
286 oppositeCorner_ = Corner_TopRight;
287 break;
288
289 case Corner_BottomRight:
290 oppositeCorner_ = Corner_TopLeft;
291 break;
292
293 default:
294 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
295 }
296
297 accessor_.GetLayer().GetCorner(oppositeX_, oppositeY_, oppositeCorner_);
298
299 double d = ComputeDistance(x, y, oppositeX_, oppositeY_);
300 if (d >= std::numeric_limits<float>::epsilon())
301 {
302 baseScaling_ = 1.0 / d;
303 }
304 else
305 {
306 // Avoid division by zero in extreme cases
307 accessor_.Invalidate();
308 }
309 }
310 }
311
312 virtual bool HasRender() const
313 {
314 return false;
315 }
316
317 virtual void Render(CairoContext& context,
318 double zoom)
319 {
320 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
321 }
322
323 virtual void MouseUp()
324 {
325 if (accessor_.IsValid() &&
326 accessor_.GetLayer().IsResizeable())
327 {
328 undoRedoStack_.Add(new UndoRedoCommand(*this));
329 }
330 }
331
332 virtual void MouseMove(int displayX,
333 int displayY,
334 double sceneX,
335 double sceneY)
336 {
337 static const double ROUND_SCALING = 0.1;
338
339 if (accessor_.IsValid() &&
340 accessor_.GetLayer().IsResizeable())
341 {
342 double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_;
343
344 if (roundScaling_)
345 {
346 scaling = boost::math::round<double>((scaling / ROUND_SCALING) * ROUND_SCALING);
347 }
348
349 RadiographyLayer& layer = accessor_.GetLayer();
350 layer.SetPixelSpacing(scaling * originalSpacingX_,
351 scaling * originalSpacingY_);
352
353 // Keep the opposite corner at a fixed location
354 double ox, oy;
355 layer.GetCorner(ox, oy, oppositeCorner_);
356 layer.SetPan(layer.GetPanX() + oppositeX_ - ox,
357 layer.GetPanY() + oppositeY_ - oy);
358 }
359 }
360 };
361
362
363 class RadiographyWindowingTracker : public IWorldSceneMouseTracker
364 {
365 public:
366 enum Action
367 {
368 Action_IncreaseWidth,
369 Action_DecreaseWidth,
370 Action_IncreaseCenter,
371 Action_DecreaseCenter
372 };
373
374 private:
375 UndoRedoStack& undoRedoStack_;
376 RadiographyScene& scene_;
377 int clickX_;
378 int clickY_;
379 Action leftAction_;
380 Action rightAction_;
381 Action upAction_;
382 Action downAction_;
383 float strength_;
384 float sourceCenter_;
385 float sourceWidth_;
386
387 static void ComputeAxisEffect(int& deltaCenter,
388 int& deltaWidth,
389 int delta,
390 Action actionNegative,
391 Action actionPositive)
392 {
393 if (delta < 0)
394 {
395 switch (actionNegative)
396 {
397 case Action_IncreaseWidth:
398 deltaWidth = -delta;
399 break;
400
401 case Action_DecreaseWidth:
402 deltaWidth = delta;
403 break;
404
405 case Action_IncreaseCenter:
406 deltaCenter = -delta;
407 break;
408
409 case Action_DecreaseCenter:
410 deltaCenter = delta;
411 break;
412
413 default:
414 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
415 }
416 }
417 else if (delta > 0)
418 {
419 switch (actionPositive)
420 {
421 case Action_IncreaseWidth:
422 deltaWidth = delta;
423 break;
424
425 case Action_DecreaseWidth:
426 deltaWidth = -delta;
427 break;
428
429 case Action_IncreaseCenter:
430 deltaCenter = delta;
431 break;
432
433 case Action_DecreaseCenter:
434 deltaCenter = -delta;
435 break;
436
437 default:
438 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
439 }
440 }
441 }
442
443
444 class UndoRedoCommand : public UndoRedoStack::ICommand
445 {
446 private:
447 RadiographyScene& scene_;
448 float sourceCenter_;
449 float sourceWidth_;
450 float targetCenter_;
451 float targetWidth_;
452
453 public:
454 UndoRedoCommand(const RadiographyWindowingTracker& tracker) :
455 scene_(tracker.scene_),
456 sourceCenter_(tracker.sourceCenter_),
457 sourceWidth_(tracker.sourceWidth_)
458 {
459 scene_.GetWindowingWithDefault(targetCenter_, targetWidth_);
460 }
461
462 virtual void Undo() const
463 {
464 scene_.SetWindowing(sourceCenter_, sourceWidth_);
465 }
466
467 virtual void Redo() const
468 {
469 scene_.SetWindowing(targetCenter_, targetWidth_);
470 }
471 };
472
473
474 public:
475 RadiographyWindowingTracker(UndoRedoStack& undoRedoStack,
476 RadiographyScene& scene,
477 int x,
478 int y,
479 Action leftAction,
480 Action rightAction,
481 Action upAction,
482 Action downAction) :
483 undoRedoStack_(undoRedoStack),
484 scene_(scene),
485 clickX_(x),
486 clickY_(y),
487 leftAction_(leftAction),
488 rightAction_(rightAction),
489 upAction_(upAction),
490 downAction_(downAction)
491 {
492 scene_.GetWindowingWithDefault(sourceCenter_, sourceWidth_);
493
494 float minValue, maxValue;
495 scene.GetRange(minValue, maxValue);
496
497 assert(minValue <= maxValue);
498
499 float tmp;
500
501 float delta = (maxValue - minValue);
502 if (delta <= 1)
503 {
504 tmp = 0;
505 }
506 else
507 {
508 // NB: Visual Studio 2008 does not provide "log2f()", so we
509 // implement it by ourselves
510 tmp = logf(delta) / logf(2.0f);
511 }
512
513 strength_ = tmp - 7;
514 if (strength_ < 1)
515 {
516 strength_ = 1;
517 }
518 }
519
520 virtual bool HasRender() const
521 {
522 return false;
523 }
524
525 virtual void Render(CairoContext& context,
526 double zoom)
527 {
528 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
529 }
530
531 virtual void MouseUp()
532 {
533 undoRedoStack_.Add(new UndoRedoCommand(*this));
534 }
535
536
537 virtual void MouseMove(int displayX,
538 int displayY,
539 double sceneX,
540 double sceneY)
541 {
542 // https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/src/app/viewport/image-plugins/windowing-viewport-tool.class.js
543
544 static const float SCALE = 1.0;
545
546 int deltaCenter = 0;
547 int deltaWidth = 0;
548
549 ComputeAxisEffect(deltaCenter, deltaWidth, displayX - clickX_, leftAction_, rightAction_);
550 ComputeAxisEffect(deltaCenter, deltaWidth, displayY - clickY_, upAction_, downAction_);
551
552 float newCenter = sourceCenter_ + (deltaCenter / SCALE * strength_);
553 float newWidth = sourceWidth_ + (deltaWidth / SCALE * strength_);
554 scene_.SetWindowing(newCenter, newWidth);
555 }
556 };
557
558
559
560
561 namespace Samples 47 namespace Samples
562 { 48 {
563 class RadiographyEditorInteractor : 49 class RadiographyEditorInteractor :
564 public IWorldSceneInteractor, 50 public IWorldSceneInteractor,
565 public IObserver 51 public IObserver