# HG changeset patch # User Sebastien Jodogne # Date 1542101813 -3600 # Node ID c0589c3173fd5bc5d3ee60a4e5b4f3ed3cc9237a # Parent f7616c010056cbc38ec02eebfff0e841568d4de5 finished reorganization diff -r f7616c010056 -r c0589c3173fd Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Mon Nov 12 18:00:48 2018 +0100 +++ b/Applications/Samples/SingleFrameEditorApplication.h Tue Nov 13 10:36:53 2018 +0100 @@ -23,25 +23,18 @@ #include "SampleApplicationBase.h" +#include "../../Framework/Radiography/RadiographyLayerCropTracker.h" #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h" +#include "../../Framework/Radiography/RadiographyLayerResizeTracker.h" #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h" #include "../../Framework/Radiography/RadiographyScene.h" #include "../../Framework/Radiography/RadiographySceneCommand.h" #include "../../Framework/Radiography/RadiographyWidget.h" - -#include "../../Framework/Toolbox/UndoRedoStack.h" +#include "../../Framework/Radiography/RadiographyWindowingTracker.h" #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include // Export using PAM is faster than using PNG, but requires Orthanc @@ -49,515 +42,8 @@ #define EXPORT_USING_PAM 1 -#include - - namespace OrthancStone { - class RadiographyLayerCropTracker : public IWorldSceneMouseTracker - { - private: - UndoRedoStack& undoRedoStack_; - RadiographyScene::LayerAccessor accessor_; - Corner corner_; - unsigned int cropX_; - unsigned int cropY_; - unsigned int cropWidth_; - unsigned int cropHeight_; - - class UndoRedoCommand : public RadiographySceneCommand - { - private: - unsigned int sourceCropX_; - unsigned int sourceCropY_; - unsigned int sourceCropWidth_; - unsigned int sourceCropHeight_; - unsigned int targetCropX_; - unsigned int targetCropY_; - unsigned int targetCropWidth_; - unsigned int targetCropHeight_; - - protected: - virtual void UndoInternal(RadiographyLayer& layer) const - { - layer.SetCrop(sourceCropX_, sourceCropY_, sourceCropWidth_, sourceCropHeight_); - } - - virtual void RedoInternal(RadiographyLayer& layer) const - { - layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); - } - - public: - UndoRedoCommand(const RadiographyLayerCropTracker& tracker) : - RadiographySceneCommand(tracker.accessor_), - sourceCropX_(tracker.cropX_), - sourceCropY_(tracker.cropY_), - sourceCropWidth_(tracker.cropWidth_), - sourceCropHeight_(tracker.cropHeight_) - { - tracker.accessor_.GetLayer().GetCrop(targetCropX_, targetCropY_, - targetCropWidth_, targetCropHeight_); - } - }; - - - public: - RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack, - RadiographyScene& scene, - const ViewportGeometry& view, - size_t layer, - double x, - double y, - Corner corner) : - undoRedoStack_(undoRedoStack), - accessor_(scene, layer), - corner_(corner) - { - if (accessor_.IsValid()) - { - accessor_.GetLayer().GetCrop(cropX_, cropY_, cropWidth_, cropHeight_); - } - } - - virtual bool HasRender() const - { - return false; - } - - virtual void Render(CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - virtual void MouseUp() - { - if (accessor_.IsValid()) - { - undoRedoStack_.Add(new UndoRedoCommand(*this)); - } - } - - virtual void MouseMove(int displayX, - int displayY, - double sceneX, - double sceneY) - { - if (accessor_.IsValid()) - { - unsigned int x, y; - - RadiographyLayer& layer = accessor_.GetLayer(); - if (layer.GetPixel(x, y, sceneX, sceneY)) - { - unsigned int targetX, targetWidth; - - if (corner_ == Corner_TopLeft || - corner_ == Corner_BottomLeft) - { - targetX = std::min(x, cropX_ + cropWidth_); - targetWidth = cropX_ + cropWidth_ - targetX; - } - else - { - targetX = cropX_; - targetWidth = std::max(x, cropX_) - cropX_; - } - - unsigned int targetY, targetHeight; - - if (corner_ == Corner_TopLeft || - corner_ == Corner_TopRight) - { - targetY = std::min(y, cropY_ + cropHeight_); - targetHeight = cropY_ + cropHeight_ - targetY; - } - else - { - targetY = cropY_; - targetHeight = std::max(y, cropY_) - cropY_; - } - - layer.SetCrop(targetX, targetY, targetWidth, targetHeight); - } - } - } - }; - - - class RadiographyLayerResizeTracker : public IWorldSceneMouseTracker - { - private: - UndoRedoStack& undoRedoStack_; - RadiographyScene::LayerAccessor accessor_; - bool roundScaling_; - double originalSpacingX_; - double originalSpacingY_; - double originalPanX_; - double originalPanY_; - Corner oppositeCorner_; - double oppositeX_; - double oppositeY_; - double baseScaling_; - - static double ComputeDistance(double x1, - double y1, - double x2, - double y2) - { - double dx = x1 - x2; - double dy = y1 - y2; - return sqrt(dx * dx + dy * dy); - } - - class UndoRedoCommand : public RadiographySceneCommand - { - private: - double sourceSpacingX_; - double sourceSpacingY_; - double sourcePanX_; - double sourcePanY_; - double targetSpacingX_; - double targetSpacingY_; - double targetPanX_; - double targetPanY_; - - protected: - virtual void UndoInternal(RadiographyLayer& layer) const - { - layer.SetPixelSpacing(sourceSpacingX_, sourceSpacingY_); - layer.SetPan(sourcePanX_, sourcePanY_); - } - - virtual void RedoInternal(RadiographyLayer& layer) const - { - layer.SetPixelSpacing(targetSpacingX_, targetSpacingY_); - layer.SetPan(targetPanX_, targetPanY_); - } - - public: - UndoRedoCommand(const RadiographyLayerResizeTracker& tracker) : - RadiographySceneCommand(tracker.accessor_), - sourceSpacingX_(tracker.originalSpacingX_), - sourceSpacingY_(tracker.originalSpacingY_), - sourcePanX_(tracker.originalPanX_), - sourcePanY_(tracker.originalPanY_), - targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()), - targetSpacingY_(tracker.accessor_.GetLayer().GetPixelSpacingY()), - targetPanX_(tracker.accessor_.GetLayer().GetPanX()), - targetPanY_(tracker.accessor_.GetLayer().GetPanY()) - { - } - }; - - - public: - RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack, - RadiographyScene& scene, - size_t layer, - double x, - double y, - Corner corner, - bool roundScaling) : - undoRedoStack_(undoRedoStack), - accessor_(scene, layer), - roundScaling_(roundScaling) - { - if (accessor_.IsValid() && - accessor_.GetLayer().IsResizeable()) - { - originalSpacingX_ = accessor_.GetLayer().GetPixelSpacingX(); - originalSpacingY_ = accessor_.GetLayer().GetPixelSpacingY(); - originalPanX_ = accessor_.GetLayer().GetPanX(); - originalPanY_ = accessor_.GetLayer().GetPanY(); - - switch (corner) - { - case Corner_TopLeft: - oppositeCorner_ = Corner_BottomRight; - break; - - case Corner_TopRight: - oppositeCorner_ = Corner_BottomLeft; - break; - - case Corner_BottomLeft: - oppositeCorner_ = Corner_TopRight; - break; - - case Corner_BottomRight: - oppositeCorner_ = Corner_TopLeft; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - accessor_.GetLayer().GetCorner(oppositeX_, oppositeY_, oppositeCorner_); - - double d = ComputeDistance(x, y, oppositeX_, oppositeY_); - if (d >= std::numeric_limits::epsilon()) - { - baseScaling_ = 1.0 / d; - } - else - { - // Avoid division by zero in extreme cases - accessor_.Invalidate(); - } - } - } - - virtual bool HasRender() const - { - return false; - } - - virtual void Render(CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - virtual void MouseUp() - { - if (accessor_.IsValid() && - accessor_.GetLayer().IsResizeable()) - { - undoRedoStack_.Add(new UndoRedoCommand(*this)); - } - } - - virtual void MouseMove(int displayX, - int displayY, - double sceneX, - double sceneY) - { - static const double ROUND_SCALING = 0.1; - - if (accessor_.IsValid() && - accessor_.GetLayer().IsResizeable()) - { - double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_; - - if (roundScaling_) - { - scaling = boost::math::round((scaling / ROUND_SCALING) * ROUND_SCALING); - } - - RadiographyLayer& layer = accessor_.GetLayer(); - layer.SetPixelSpacing(scaling * originalSpacingX_, - scaling * originalSpacingY_); - - // Keep the opposite corner at a fixed location - double ox, oy; - layer.GetCorner(ox, oy, oppositeCorner_); - layer.SetPan(layer.GetPanX() + oppositeX_ - ox, - layer.GetPanY() + oppositeY_ - oy); - } - } - }; - - - class RadiographyWindowingTracker : public IWorldSceneMouseTracker - { - public: - enum Action - { - Action_IncreaseWidth, - Action_DecreaseWidth, - Action_IncreaseCenter, - Action_DecreaseCenter - }; - - private: - UndoRedoStack& undoRedoStack_; - RadiographyScene& scene_; - int clickX_; - int clickY_; - Action leftAction_; - Action rightAction_; - Action upAction_; - Action downAction_; - float strength_; - float sourceCenter_; - float sourceWidth_; - - static void ComputeAxisEffect(int& deltaCenter, - int& deltaWidth, - int delta, - Action actionNegative, - Action actionPositive) - { - if (delta < 0) - { - switch (actionNegative) - { - case Action_IncreaseWidth: - deltaWidth = -delta; - break; - - case Action_DecreaseWidth: - deltaWidth = delta; - break; - - case Action_IncreaseCenter: - deltaCenter = -delta; - break; - - case Action_DecreaseCenter: - deltaCenter = delta; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - else if (delta > 0) - { - switch (actionPositive) - { - case Action_IncreaseWidth: - deltaWidth = delta; - break; - - case Action_DecreaseWidth: - deltaWidth = -delta; - break; - - case Action_IncreaseCenter: - deltaCenter = delta; - break; - - case Action_DecreaseCenter: - deltaCenter = -delta; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - } - - - class UndoRedoCommand : public UndoRedoStack::ICommand - { - private: - RadiographyScene& scene_; - float sourceCenter_; - float sourceWidth_; - float targetCenter_; - float targetWidth_; - - public: - UndoRedoCommand(const RadiographyWindowingTracker& tracker) : - scene_(tracker.scene_), - sourceCenter_(tracker.sourceCenter_), - sourceWidth_(tracker.sourceWidth_) - { - scene_.GetWindowingWithDefault(targetCenter_, targetWidth_); - } - - virtual void Undo() const - { - scene_.SetWindowing(sourceCenter_, sourceWidth_); - } - - virtual void Redo() const - { - scene_.SetWindowing(targetCenter_, targetWidth_); - } - }; - - - public: - RadiographyWindowingTracker(UndoRedoStack& undoRedoStack, - RadiographyScene& scene, - int x, - int y, - Action leftAction, - Action rightAction, - Action upAction, - Action downAction) : - undoRedoStack_(undoRedoStack), - scene_(scene), - clickX_(x), - clickY_(y), - leftAction_(leftAction), - rightAction_(rightAction), - upAction_(upAction), - downAction_(downAction) - { - scene_.GetWindowingWithDefault(sourceCenter_, sourceWidth_); - - float minValue, maxValue; - scene.GetRange(minValue, maxValue); - - assert(minValue <= maxValue); - - float tmp; - - float delta = (maxValue - minValue); - if (delta <= 1) - { - tmp = 0; - } - else - { - // NB: Visual Studio 2008 does not provide "log2f()", so we - // implement it by ourselves - tmp = logf(delta) / logf(2.0f); - } - - strength_ = tmp - 7; - if (strength_ < 1) - { - strength_ = 1; - } - } - - virtual bool HasRender() const - { - return false; - } - - virtual void Render(CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - virtual void MouseUp() - { - undoRedoStack_.Add(new UndoRedoCommand(*this)); - } - - - virtual void MouseMove(int displayX, - int displayY, - double sceneX, - double sceneY) - { - // https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/src/app/viewport/image-plugins/windowing-viewport-tool.class.js - - static const float SCALE = 1.0; - - int deltaCenter = 0; - int deltaWidth = 0; - - ComputeAxisEffect(deltaCenter, deltaWidth, displayX - clickX_, leftAction_, rightAction_); - ComputeAxisEffect(deltaCenter, deltaWidth, displayY - clickY_, upAction_, downAction_); - - float newCenter = sourceCenter_ + (deltaCenter / SCALE * strength_); - float newWidth = sourceWidth_ + (deltaWidth / SCALE * strength_); - scene_.SetWindowing(newCenter, newWidth); - } - }; - - - - namespace Samples { class RadiographyEditorInteractor : diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyLayerCropTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyLayerCropTracker.cpp Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,145 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "RadiographyLayerCropTracker.h" + +#include "RadiographySceneCommand.h" + +#include + +namespace OrthancStone +{ + class RadiographyLayerCropTracker::UndoRedoCommand : public RadiographySceneCommand + { + private: + unsigned int sourceCropX_; + unsigned int sourceCropY_; + unsigned int sourceCropWidth_; + unsigned int sourceCropHeight_; + unsigned int targetCropX_; + unsigned int targetCropY_; + unsigned int targetCropWidth_; + unsigned int targetCropHeight_; + + protected: + virtual void UndoInternal(RadiographyLayer& layer) const + { + layer.SetCrop(sourceCropX_, sourceCropY_, sourceCropWidth_, sourceCropHeight_); + } + + virtual void RedoInternal(RadiographyLayer& layer) const + { + layer.SetCrop(targetCropX_, targetCropY_, targetCropWidth_, targetCropHeight_); + } + + public: + UndoRedoCommand(const RadiographyLayerCropTracker& tracker) : + RadiographySceneCommand(tracker.accessor_), + sourceCropX_(tracker.cropX_), + sourceCropY_(tracker.cropY_), + sourceCropWidth_(tracker.cropWidth_), + sourceCropHeight_(tracker.cropHeight_) + { + tracker.accessor_.GetLayer().GetCrop(targetCropX_, targetCropY_, + targetCropWidth_, targetCropHeight_); + } + }; + + + RadiographyLayerCropTracker::RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + const ViewportGeometry& view, + size_t layer, + double x, + double y, + Corner corner) : + undoRedoStack_(undoRedoStack), + accessor_(scene, layer), + corner_(corner) + { + if (accessor_.IsValid()) + { + accessor_.GetLayer().GetCrop(cropX_, cropY_, cropWidth_, cropHeight_); + } + } + + + void RadiographyLayerCropTracker::Render(CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void RadiographyLayerCropTracker::MouseUp() + { + if (accessor_.IsValid()) + { + undoRedoStack_.Add(new UndoRedoCommand(*this)); + } + } + + + void RadiographyLayerCropTracker::MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY) + { + if (accessor_.IsValid()) + { + unsigned int x, y; + + RadiographyLayer& layer = accessor_.GetLayer(); + if (layer.GetPixel(x, y, sceneX, sceneY)) + { + unsigned int targetX, targetWidth; + + if (corner_ == Corner_TopLeft || + corner_ == Corner_BottomLeft) + { + targetX = std::min(x, cropX_ + cropWidth_); + targetWidth = cropX_ + cropWidth_ - targetX; + } + else + { + targetX = cropX_; + targetWidth = std::max(x, cropX_) - cropX_; + } + + unsigned int targetY, targetHeight; + + if (corner_ == Corner_TopLeft || + corner_ == Corner_TopRight) + { + targetY = std::min(y, cropY_ + cropHeight_); + targetHeight = cropY_ + cropHeight_ - targetY; + } + else + { + targetY = cropY_; + targetHeight = std::max(y, cropY_) - cropY_; + } + + layer.SetCrop(targetX, targetY, targetWidth, targetHeight); + } + } + } +} diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyLayerCropTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyLayerCropTracker.h Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,68 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../Toolbox/UndoRedoStack.h" +#include "../Toolbox/ViewportGeometry.h" +#include "../Widgets/IWorldSceneMouseTracker.h" +#include "RadiographyScene.h" + +namespace OrthancStone +{ + class RadiographyLayerCropTracker : public IWorldSceneMouseTracker + { + private: + class UndoRedoCommand; + + UndoRedoStack& undoRedoStack_; + RadiographyScene::LayerAccessor accessor_; + Corner corner_; + unsigned int cropX_; + unsigned int cropY_; + unsigned int cropWidth_; + unsigned int cropHeight_; + + public: + RadiographyLayerCropTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + const ViewportGeometry& view, + size_t layer, + double x, + double y, + Corner corner); + + virtual bool HasRender() const + { + return false; + } + + virtual void Render(CairoContext& context, + double zoom); + + virtual void MouseUp(); + + virtual void MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY); + }; +} diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyLayerResizeTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyLayerResizeTracker.cpp Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,187 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "RadiographyLayerResizeTracker.h" + +#include "RadiographySceneCommand.h" + +#include + +#include + + +namespace OrthancStone +{ + static double ComputeDistance(double x1, + double y1, + double x2, + double y2) + { + double dx = x1 - x2; + double dy = y1 - y2; + return sqrt(dx * dx + dy * dy); + } + + + class RadiographyLayerResizeTracker::UndoRedoCommand : public RadiographySceneCommand + { + private: + double sourceSpacingX_; + double sourceSpacingY_; + double sourcePanX_; + double sourcePanY_; + double targetSpacingX_; + double targetSpacingY_; + double targetPanX_; + double targetPanY_; + + protected: + virtual void UndoInternal(RadiographyLayer& layer) const + { + layer.SetPixelSpacing(sourceSpacingX_, sourceSpacingY_); + layer.SetPan(sourcePanX_, sourcePanY_); + } + + virtual void RedoInternal(RadiographyLayer& layer) const + { + layer.SetPixelSpacing(targetSpacingX_, targetSpacingY_); + layer.SetPan(targetPanX_, targetPanY_); + } + + public: + UndoRedoCommand(const RadiographyLayerResizeTracker& tracker) : + RadiographySceneCommand(tracker.accessor_), + sourceSpacingX_(tracker.originalSpacingX_), + sourceSpacingY_(tracker.originalSpacingY_), + sourcePanX_(tracker.originalPanX_), + sourcePanY_(tracker.originalPanY_), + targetSpacingX_(tracker.accessor_.GetLayer().GetPixelSpacingX()), + targetSpacingY_(tracker.accessor_.GetLayer().GetPixelSpacingY()), + targetPanX_(tracker.accessor_.GetLayer().GetPanX()), + targetPanY_(tracker.accessor_.GetLayer().GetPanY()) + { + } + }; + + + RadiographyLayerResizeTracker::RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + size_t layer, + double x, + double y, + Corner corner, + bool roundScaling) : + undoRedoStack_(undoRedoStack), + accessor_(scene, layer), + roundScaling_(roundScaling) + { + if (accessor_.IsValid() && + accessor_.GetLayer().IsResizeable()) + { + originalSpacingX_ = accessor_.GetLayer().GetPixelSpacingX(); + originalSpacingY_ = accessor_.GetLayer().GetPixelSpacingY(); + originalPanX_ = accessor_.GetLayer().GetPanX(); + originalPanY_ = accessor_.GetLayer().GetPanY(); + + switch (corner) + { + case Corner_TopLeft: + oppositeCorner_ = Corner_BottomRight; + break; + + case Corner_TopRight: + oppositeCorner_ = Corner_BottomLeft; + break; + + case Corner_BottomLeft: + oppositeCorner_ = Corner_TopRight; + break; + + case Corner_BottomRight: + oppositeCorner_ = Corner_TopLeft; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + accessor_.GetLayer().GetCorner(oppositeX_, oppositeY_, oppositeCorner_); + + double d = ComputeDistance(x, y, oppositeX_, oppositeY_); + if (d >= std::numeric_limits::epsilon()) + { + baseScaling_ = 1.0 / d; + } + else + { + // Avoid division by zero in extreme cases + accessor_.Invalidate(); + } + } + } + + + void RadiographyLayerResizeTracker::Render(CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void RadiographyLayerResizeTracker::MouseUp() + { + if (accessor_.IsValid() && + accessor_.GetLayer().IsResizeable()) + { + undoRedoStack_.Add(new UndoRedoCommand(*this)); + } + } + + + void RadiographyLayerResizeTracker::MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY) + { + static const double ROUND_SCALING = 0.1; + + if (accessor_.IsValid() && + accessor_.GetLayer().IsResizeable()) + { + double scaling = ComputeDistance(oppositeX_, oppositeY_, sceneX, sceneY) * baseScaling_; + + if (roundScaling_) + { + scaling = boost::math::round((scaling / ROUND_SCALING) * ROUND_SCALING); + } + + RadiographyLayer& layer = accessor_.GetLayer(); + layer.SetPixelSpacing(scaling * originalSpacingX_, + scaling * originalSpacingY_); + + // Keep the opposite corner at a fixed location + double ox, oy; + layer.GetCorner(ox, oy, oppositeCorner_); + layer.SetPan(layer.GetPanX() + oppositeX_ - ox, + layer.GetPanY() + oppositeY_ - oy); + } + } +} diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyLayerResizeTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyLayerResizeTracker.h Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,71 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../Toolbox/UndoRedoStack.h" +#include "../Widgets/IWorldSceneMouseTracker.h" +#include "RadiographyScene.h" + +namespace OrthancStone +{ + class RadiographyLayerResizeTracker : public IWorldSceneMouseTracker + { + private: + class UndoRedoCommand; + + UndoRedoStack& undoRedoStack_; + RadiographyScene::LayerAccessor accessor_; + bool roundScaling_; + double originalSpacingX_; + double originalSpacingY_; + double originalPanX_; + double originalPanY_; + Corner oppositeCorner_; + double oppositeX_; + double oppositeY_; + double baseScaling_; + + public: + RadiographyLayerResizeTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + size_t layer, + double x, + double y, + Corner corner, + bool roundScaling); + + virtual bool HasRender() const + { + return false; + } + + virtual void Render(CairoContext& context, + double zoom); + + virtual void MouseUp(); + + virtual void MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY); + }; +} diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyWindowingTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyWindowingTracker.cpp Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,195 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "RadiographyWindowingTracker.h" + +#include + + +namespace OrthancStone +{ + class RadiographyWindowingTracker::UndoRedoCommand : public UndoRedoStack::ICommand + { + private: + RadiographyScene& scene_; + float sourceCenter_; + float sourceWidth_; + float targetCenter_; + float targetWidth_; + + public: + UndoRedoCommand(const RadiographyWindowingTracker& tracker) : + scene_(tracker.scene_), + sourceCenter_(tracker.sourceCenter_), + sourceWidth_(tracker.sourceWidth_) + { + scene_.GetWindowingWithDefault(targetCenter_, targetWidth_); + } + + virtual void Undo() const + { + scene_.SetWindowing(sourceCenter_, sourceWidth_); + } + + virtual void Redo() const + { + scene_.SetWindowing(targetCenter_, targetWidth_); + } + }; + + + void RadiographyWindowingTracker::ComputeAxisEffect(int& deltaCenter, + int& deltaWidth, + int delta, + Action actionNegative, + Action actionPositive) + { + if (delta < 0) + { + switch (actionNegative) + { + case Action_IncreaseWidth: + deltaWidth = -delta; + break; + + case Action_DecreaseWidth: + deltaWidth = delta; + break; + + case Action_IncreaseCenter: + deltaCenter = -delta; + break; + + case Action_DecreaseCenter: + deltaCenter = delta; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + else if (delta > 0) + { + switch (actionPositive) + { + case Action_IncreaseWidth: + deltaWidth = delta; + break; + + case Action_DecreaseWidth: + deltaWidth = -delta; + break; + + case Action_IncreaseCenter: + deltaCenter = delta; + break; + + case Action_DecreaseCenter: + deltaCenter = -delta; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + } + + + RadiographyWindowingTracker::RadiographyWindowingTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + int x, + int y, + Action leftAction, + Action rightAction, + Action upAction, + Action downAction) : + undoRedoStack_(undoRedoStack), + scene_(scene), + clickX_(x), + clickY_(y), + leftAction_(leftAction), + rightAction_(rightAction), + upAction_(upAction), + downAction_(downAction) + { + scene_.GetWindowingWithDefault(sourceCenter_, sourceWidth_); + + float minValue, maxValue; + scene.GetRange(minValue, maxValue); + + assert(minValue <= maxValue); + + float tmp; + + float delta = (maxValue - minValue); + if (delta <= 1) + { + tmp = 0; + } + else + { + // NB: Visual Studio 2008 does not provide "log2f()", so we + // implement it by ourselves + tmp = logf(delta) / logf(2.0f); + } + + strength_ = tmp - 7; + if (strength_ < 1) + { + strength_ = 1; + } + } + + + void RadiographyWindowingTracker::Render(CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void RadiographyWindowingTracker::MouseUp() + { + undoRedoStack_.Add(new UndoRedoCommand(*this)); + } + + + void RadiographyWindowingTracker::MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY) + { + // This follows the behavior of the Osimis Web viewer: + // https://bitbucket.org/osimis/osimis-webviewer-plugin/src/master/frontend/src/app/viewport/image-plugins/windowing-viewport-tool.class.js + + static const float SCALE = 1.0; + + int deltaCenter = 0; + int deltaWidth = 0; + + ComputeAxisEffect(deltaCenter, deltaWidth, displayX - clickX_, leftAction_, rightAction_); + ComputeAxisEffect(deltaCenter, deltaWidth, displayY - clickY_, upAction_, downAction_); + + float newCenter = sourceCenter_ + (deltaCenter / SCALE * strength_); + float newWidth = sourceWidth_ + (deltaWidth / SCALE * strength_); + scene_.SetWindowing(newCenter, newWidth); + } +} diff -r f7616c010056 -r c0589c3173fd Framework/Radiography/RadiographyWindowingTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Radiography/RadiographyWindowingTracker.h Tue Nov 13 10:36:53 2018 +0100 @@ -0,0 +1,87 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../Toolbox/UndoRedoStack.h" +#include "../Widgets/IWorldSceneMouseTracker.h" +#include "RadiographyScene.h" + +namespace OrthancStone +{ + class RadiographyWindowingTracker : public IWorldSceneMouseTracker + { + public: + enum Action + { + Action_IncreaseWidth, + Action_DecreaseWidth, + Action_IncreaseCenter, + Action_DecreaseCenter + }; + + private: + class UndoRedoCommand; + + UndoRedoStack& undoRedoStack_; + RadiographyScene& scene_; + int clickX_; + int clickY_; + Action leftAction_; + Action rightAction_; + Action upAction_; + Action downAction_; + float strength_; + float sourceCenter_; + float sourceWidth_; + + static void ComputeAxisEffect(int& deltaCenter, + int& deltaWidth, + int delta, + Action actionNegative, + Action actionPositive); + + public: + RadiographyWindowingTracker(UndoRedoStack& undoRedoStack, + RadiographyScene& scene, + int x, + int y, + Action leftAction, + Action rightAction, + Action upAction, + Action downAction); + + virtual bool HasRender() const + { + return false; + } + + virtual void Render(CairoContext& context, + double zoom); + + virtual void MouseUp(); + + virtual void MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY); + }; +} diff -r f7616c010056 -r c0589c3173fd Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Mon Nov 12 18:00:48 2018 +0100 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue Nov 13 10:36:53 2018 +0100 @@ -246,12 +246,15 @@ ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayerCropTracker.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayerMoveTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayerResizeTracker.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayerRotateTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyLayer.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyScene.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographySceneCommand.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWindowingTracker.cpp ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneEnumerations.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneException.h