# HG changeset patch # User Sebastien Jodogne # Date 1542033491 -3600 # Node ID 99c9b32380080f8342e796dccc12603deb664097 # Parent 6834c236b36dcee37a7d9622290d37e8922cb9c4 AffineTransform2D diff -r 6834c236b36d -r 99c9b3238008 Framework/Radiography/RadiographyScene.cpp --- a/Framework/Radiography/RadiographyScene.cpp Mon Nov 12 14:52:10 2018 +0100 +++ b/Framework/Radiography/RadiographyScene.cpp Mon Nov 12 15:38:11 2018 +0100 @@ -43,73 +43,20 @@ } - static Matrix CreateOffsetMatrix(double dx, - double dy) - { - Matrix m = LinearAlgebra::IdentityMatrix(3); - m(0, 2) = dx; - m(1, 2) = dy; - return m; - } - - - static Matrix CreateScalingMatrix(double sx, - double sy) - { - Matrix m = LinearAlgebra::IdentityMatrix(3); - m(0, 0) = sx; - m(1, 1) = sy; - return m; - } - - - static Matrix CreateRotationMatrix(double angle) - { - Matrix m; - const double v[] = { cos(angle), -sin(angle), 0, - sin(angle), cos(angle), 0, - 0, 0, 1 }; - LinearAlgebra::FillMatrix(m, 3, 3, v); - return m; - } - - - static void ApplyTransform(double& x /* inout */, - double& y /* inout */, - const Matrix& transform) - { - Vector p; - LinearAlgebra::AssignVector(p, x, y, 1); - - Vector q = LinearAlgebra::Product(transform, p); - - if (!LinearAlgebra::IsNear(q[2], 1.0)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - else - { - x = q[0]; - y = q[1]; - } - } - - - void RadiographyScene::Layer::UpdateTransform() { - transform_ = CreateScalingMatrix(pixelSpacingX_, pixelSpacingY_); + transform_ = AffineTransform2D::CreateScaling(pixelSpacingX_, pixelSpacingY_); double centerX, centerY; GetCenter(centerX, centerY); - transform_ = LinearAlgebra::Product( - CreateOffsetMatrix(panX_ + centerX, panY_ + centerY), - CreateRotationMatrix(angle_), - CreateOffsetMatrix(-centerX, -centerY), + transform_ = AffineTransform2D::Combine( + AffineTransform2D::CreateOffset(panX_ + centerX, panY_ + centerY), + AffineTransform2D::CreateRotation(angle_), + AffineTransform2D::CreateOffset(-centerX, -centerY), transform_); - LinearAlgebra::InvertMatrix(transformInverse_, transform_); + transformInverse_ = AffineTransform2D::Invert(transform_); } @@ -117,7 +64,7 @@ double x, double y) const { - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); extent.AddPoint(x, y); } @@ -161,14 +108,14 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); } bool RadiographyScene::Layer::Contains(double x, double y) const { - ApplyTransform(x, y, transformInverse_); + transformInverse_.Apply(x, y); unsigned int cropX, cropY, cropWidth, cropHeight; GetCrop(cropX, cropY, cropWidth, cropHeight); @@ -195,27 +142,27 @@ double x, y; x = dx; y = dy; - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); cairo_move_to(cr, x, y); x = dx + dwidth; y = dy; - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); cairo_line_to(cr, x, y); x = dx + dwidth; y = dy + dheight; - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); cairo_line_to(cr, x, y); x = dx; y = dy + dheight; - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); cairo_line_to(cr, x, y); x = dx; y = dy; - ApplyTransform(x, y, transform_); + transform_.Apply(x, y); cairo_line_to(cr, x, y); cairo_stroke(cr); @@ -345,7 +292,7 @@ } else { - ApplyTransform(sceneX, sceneY, transformInverse_); + transformInverse_.Apply(sceneX, sceneY); int x = static_cast(std::floor(sceneX)); int y = static_cast(std::floor(sceneY)); @@ -404,7 +351,7 @@ { centerX = static_cast(width_) / 2.0; centerY = static_cast(height_) / 2.0; - ApplyTransform(centerX, centerY, transform_); + transform_.Apply(centerX, centerY); } @@ -598,7 +545,7 @@ virtual void Render(Orthanc::ImageAccessor& buffer, - const Matrix& viewTransform, + const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const { if (alpha_.get() == NULL) @@ -614,15 +561,16 @@ unsigned int cropX, cropY, cropWidth, cropHeight; GetCrop(cropX, cropY, cropWidth, cropHeight); - Matrix m = LinearAlgebra::Product(viewTransform, - GetTransform(), - CreateOffsetMatrix(cropX, cropY)); + const AffineTransform2D t = AffineTransform2D::Combine( + viewTransform, GetTransform(), + AffineTransform2D::CreateOffset(cropX, cropY)); Orthanc::ImageAccessor cropped; alpha_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); Orthanc::Image tmp(Orthanc::PixelFormat_Grayscale8, buffer.GetWidth(), buffer.GetHeight(), false); - ApplyProjectiveTransform(tmp, cropped, m, interpolation, true /* clear */); + + t.Apply(tmp, cropped, interpolation, true /* clear */); // Blit const unsigned int width = buffer.GetWidth(); @@ -756,7 +704,7 @@ virtual void Render(Orthanc::ImageAccessor& buffer, - const Matrix& viewTransform, + const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const { if (converted_.get() != NULL) @@ -769,14 +717,14 @@ unsigned int cropX, cropY, cropWidth, cropHeight; GetCrop(cropX, cropY, cropWidth, cropHeight); - Matrix m = LinearAlgebra::Product(viewTransform, - GetTransform(), - CreateOffsetMatrix(cropX, cropY)); + AffineTransform2D t = AffineTransform2D::Combine( + viewTransform, GetTransform(), + AffineTransform2D::CreateOffset(cropX, cropY)); Orthanc::ImageAccessor cropped; converted_->GetRegion(cropped, cropX, cropY, cropWidth, cropHeight); - ApplyProjectiveTransform(buffer, cropped, m, interpolation, false); + t.Apply(buffer, cropped, interpolation, false); } } @@ -1052,7 +1000,7 @@ void RadiographyScene::Render(Orthanc::ImageAccessor& buffer, - const Matrix& viewTransform, + const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const { Orthanc::ImageProcessing::Set(buffer, 0); @@ -1173,9 +1121,9 @@ static_cast(w), static_cast(h), false); - Matrix view = LinearAlgebra::Product( - CreateScalingMatrix(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), - CreateOffsetMatrix(-extent.GetX1(), -extent.GetY1())); + AffineTransform2D view = AffineTransform2D::Combine( + AffineTransform2D::CreateScaling(1.0 / pixelSpacingX, 1.0 / pixelSpacingY), + AffineTransform2D::CreateOffset(-extent.GetX1(), -extent.GetY1())); Render(layers, view, interpolation); diff -r 6834c236b36d -r 99c9b3238008 Framework/Radiography/RadiographyScene.h --- a/Framework/Radiography/RadiographyScene.h Mon Nov 12 14:52:10 2018 +0100 +++ b/Framework/Radiography/RadiographyScene.h Mon Nov 12 15:38:11 2018 +0100 @@ -21,8 +21,8 @@ #pragma once +#include "../Toolbox/AffineTransform2D.h" #include "../Toolbox/Extent2D.h" -#include "../Toolbox/LinearAlgebra.h" #include "../Toolbox/OrthancApiClient.h" #include "../Viewport/CairoContext.h" @@ -45,32 +45,33 @@ Corner_BottomRight }; + class Layer : public boost::noncopyable { friend class RadiographyScene; private: - size_t index_; - bool hasSize_; - unsigned int width_; - unsigned int height_; - bool hasCrop_; - unsigned int cropX_; - unsigned int cropY_; - unsigned int cropWidth_; - unsigned int cropHeight_; - Matrix transform_; - Matrix transformInverse_; - double pixelSpacingX_; - double pixelSpacingY_; - double panX_; - double panY_; - double angle_; - bool resizeable_; + size_t index_; + bool hasSize_; + unsigned int width_; + unsigned int height_; + bool hasCrop_; + unsigned int cropX_; + unsigned int cropY_; + unsigned int cropWidth_; + unsigned int cropHeight_; + AffineTransform2D transform_; + AffineTransform2D transformInverse_; + double pixelSpacingX_; + double pixelSpacingY_; + double panX_; + double panY_; + double angle_; + bool resizeable_; protected: - const Matrix& GetTransform() const + const AffineTransform2D& GetTransform() const { return transform_; } @@ -209,7 +210,7 @@ float& width) const = 0; virtual void Render(Orthanc::ImageAccessor& buffer, - const Matrix& viewTransform, + const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const = 0; virtual bool GetRange(float& minValue, @@ -299,7 +300,7 @@ Extent2D GetSceneExtent() const; void Render(Orthanc::ImageAccessor& buffer, - const Matrix& viewTransform, + const AffineTransform2D& viewTransform, ImageInterpolation interpolation) const; bool LookupLayer(size_t& index /* out */, diff -r 6834c236b36d -r 99c9b3238008 Framework/Toolbox/AffineTransform2D.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Toolbox/AffineTransform2D.cpp Mon Nov 12 15:38:11 2018 +0100 @@ -0,0 +1,166 @@ +/** + * 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 "AffineTransform2D.h" + +#include "ImageGeometry.h" + +#include +#include + +namespace OrthancStone +{ + AffineTransform2D::AffineTransform2D() : + matrix_(LinearAlgebra::IdentityMatrix(3)) + { + } + + + AffineTransform2D::AffineTransform2D(const Matrix& m) + { + if (m.size1() != 3 || + m.size2() != 3) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); + } + + if (!LinearAlgebra::IsCloseToZero(m(2, 0)) || + !LinearAlgebra::IsCloseToZero(m(2, 1)) || + LinearAlgebra::IsCloseToZero(m(2, 2))) + { + LOG(ERROR) << "Cannot setup an AffineTransform2D with perspective effects"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + matrix_ = m / m(2, 2); + } + + + void AffineTransform2D::Apply(double& x /* inout */, + double& y /* inout */) const + { + Vector p; + LinearAlgebra::AssignVector(p, x, y, 1); + + Vector q = LinearAlgebra::Product(matrix_, p); + + if (!LinearAlgebra::IsNear(q[2], 1.0)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + x = q[0]; + y = q[1]; + } + } + + + void AffineTransform2D::Apply(Orthanc::ImageAccessor& target, + const Orthanc::ImageAccessor& source, + ImageInterpolation interpolation, + bool clear) const + { + assert(LinearAlgebra::IsNear(matrix_(2, 0), 0) && + LinearAlgebra::IsNear(matrix_(2, 1), 0) && + LinearAlgebra::IsNear(matrix_(2, 2), 1)); + + ApplyAffineTransform(target, source, + matrix_(0, 0), matrix_(0, 1), matrix_(0, 2), + matrix_(1, 0), matrix_(1, 1), matrix_(1, 2), + interpolation, clear); + } + + + AffineTransform2D AffineTransform2D::Invert(const AffineTransform2D& a) + { + AffineTransform2D t; + LinearAlgebra::InvertMatrix(t.matrix_, a.matrix_); + return t; + } + + + AffineTransform2D AffineTransform2D::Combine(const AffineTransform2D& a, + const AffineTransform2D& b) + { + return AffineTransform2D(LinearAlgebra::Product(a.GetHomogeneousMatrix(), + b.GetHomogeneousMatrix())); + } + + + AffineTransform2D AffineTransform2D::Combine(const AffineTransform2D& a, + const AffineTransform2D& b, + const AffineTransform2D& c) + { + return AffineTransform2D(LinearAlgebra::Product(a.GetHomogeneousMatrix(), + b.GetHomogeneousMatrix(), + c.GetHomogeneousMatrix())); + } + + + AffineTransform2D AffineTransform2D::Combine(const AffineTransform2D& a, + const AffineTransform2D& b, + const AffineTransform2D& c, + const AffineTransform2D& d) + { + return AffineTransform2D(LinearAlgebra::Product(a.GetHomogeneousMatrix(), + b.GetHomogeneousMatrix(), + c.GetHomogeneousMatrix(), + d.GetHomogeneousMatrix())); + } + + + AffineTransform2D AffineTransform2D::CreateOffset(double dx, + double dy) + { + AffineTransform2D t; + t.matrix_(0, 2) = dx; + t.matrix_(1, 2) = dy; + + return t; + } + + + AffineTransform2D AffineTransform2D::CreateScaling(double sx, + double sy) + { + AffineTransform2D t; + t.matrix_(0, 0) = sx; + t.matrix_(1, 1) = sy; + + return t; + } + + + AffineTransform2D AffineTransform2D::CreateRotation(double angle) + { + double cosine = cos(angle); + double sine = sin(angle); + + AffineTransform2D t; + t.matrix_(0, 0) = cosine; + t.matrix_(0, 1) = -sine; + t.matrix_(1, 0) = sine; + t.matrix_(1, 1) = cosine; + + return t; + } +} diff -r 6834c236b36d -r 99c9b3238008 Framework/Toolbox/AffineTransform2D.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Toolbox/AffineTransform2D.h Mon Nov 12 15:38:11 2018 +0100 @@ -0,0 +1,82 @@ +/** + * 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 "../StoneEnumerations.h" +#include "LinearAlgebra.h" + +#include + +namespace OrthancStone +{ + class AffineTransform2D + { + private: + Matrix matrix_; + + public: + AffineTransform2D(); + + // The matrix must be 3x3, without perspective effects + AffineTransform2D(const Matrix& m); + + AffineTransform2D(const AffineTransform2D& other) : + matrix_(other.matrix_) + { + } + + const Matrix& GetHomogeneousMatrix() const + { + return matrix_; + } + + void Apply(double& x /* inout */, + double& y /* inout */) const; + + void Apply(Orthanc::ImageAccessor& target, + const Orthanc::ImageAccessor& source, + ImageInterpolation interpolation, + bool clear) const; + + static AffineTransform2D Invert(const AffineTransform2D& a); + + static AffineTransform2D Combine(const AffineTransform2D& a, + const AffineTransform2D& b); + + static AffineTransform2D Combine(const AffineTransform2D& a, + const AffineTransform2D& b, + const AffineTransform2D& c); + + static AffineTransform2D Combine(const AffineTransform2D& a, + const AffineTransform2D& b, + const AffineTransform2D& c, + const AffineTransform2D& d); + + static AffineTransform2D CreateOffset(double dx, + double dy); + + static AffineTransform2D CreateScaling(double sx, + double sy); + + static AffineTransform2D CreateRotation(double angle); + }; +} diff -r 6834c236b36d -r 99c9b3238008 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Mon Nov 12 14:52:10 2018 +0100 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Mon Nov 12 15:38:11 2018 +0100 @@ -251,8 +251,8 @@ ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneEnumerations.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneException.h - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.h + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/AffineTransform2D.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/AffineTransform2D.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/CoordinateSystem3D.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomFrameConverter.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomStructureSet.cpp @@ -273,6 +273,8 @@ ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Slice.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.h ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp