Mercurial > hg > orthanc-stone
diff Framework/Deprecated/Radiography/RadiographyLayer.cpp @ 1398:c5403d52078c
moved Radiography into Deprecated
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Wed, 29 Apr 2020 20:43:09 +0200 |
parents | Framework/Radiography/RadiographyLayer.cpp@379c00958553 |
children | 30deba7bc8e2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Radiography/RadiographyLayer.cpp Wed Apr 29 20:43:09 2020 +0200 @@ -0,0 +1,402 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 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 <http://www.gnu.org/licenses/>. + **/ + + +#include "RadiographyLayer.h" + +#include <Core/OrthancException.h> + + +namespace OrthancStone +{ + static double Square(double x) + { + return x * x; + } + + + RadiographyLayer::Geometry::Geometry() : + hasCrop_(false), + flipVertical_(false), + flipHorizontal_(false), + panX_(0), + panY_(0), + angle_(0), + resizeable_(false), + pixelSpacingX_(1), + pixelSpacingY_(1) + { + + } + + void RadiographyLayer::Geometry::GetCrop(unsigned int &x, unsigned int &y, unsigned int &width, unsigned int &height) const + { + if (!hasCrop_) + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); // you should probably use RadiographyLayer::GetCrop() or at least call HasCrop() before + + x = cropX_; + y = cropY_; + width = cropWidth_; + height = cropHeight_; + } + + void RadiographyLayer::UpdateTransform() + { + // important to update transform_ before getting the center to use the right scaling !!! + transform_ = AffineTransform2D::CreateScaling(geometry_.GetScalingX(), geometry_.GetScalingY()); + + double centerX, centerY; + GetCenter(centerX, centerY); + + transform_ = AffineTransform2D::Combine( + AffineTransform2D::CreateOffset(geometry_.GetPanX(), geometry_.GetPanY()), + AffineTransform2D::CreateRotation(geometry_.GetAngle(), centerX, centerY), + transform_); + + transformInverse_ = AffineTransform2D::Invert(transform_); + } + + + void RadiographyLayer::AddToExtent(Extent2D& extent, + double x, + double y) const + { + GetTransform().Apply(x, y); + extent.AddPoint(x, y); + } + + bool RadiographyLayer::Contains(double x, + double y) const + { + GetTransformInverse().Apply(x, y); + + unsigned int cropX, cropY, cropWidth, cropHeight; + GetCrop(cropX, cropY, cropWidth, cropHeight); + + return (x >= cropX && x <= cropX + cropWidth && + y >= cropY && y <= cropY + cropHeight); + } + + + void RadiographyLayer::DrawBorders(CairoContext& context, + double zoom) + { + if (GetControlPointCount() < 3 ) + return; + + cairo_t* cr = context.GetObject(); + cairo_set_line_width(cr, 2.0 / zoom); + + ControlPoint cp; + GetControlPoint(cp, 0); + cairo_move_to(cr, cp.x, cp.y); + + for (size_t i = 0; i < GetControlPointCount(); i++) + { + GetControlPoint(cp, i); + cairo_line_to(cr, cp.x, cp.y); + } + + cairo_close_path(cr); + cairo_stroke(cr); + } + + + RadiographyLayer::RadiographyLayer(const RadiographyScene& scene) : + index_(0), + hasSize_(false), + width_(0), + height_(0), + prefferedPhotometricDisplayMode_(RadiographyPhotometricDisplayMode_Default), + scene_(scene) + { + UpdateTransform(); + } + + void RadiographyLayer::ResetCrop() + { + geometry_.ResetCrop(); + UpdateTransform(); + } + + void RadiographyLayer::SetPreferredPhotomotricDisplayMode(RadiographyPhotometricDisplayMode prefferedPhotometricDisplayMode) + { + prefferedPhotometricDisplayMode_ = prefferedPhotometricDisplayMode; + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + void RadiographyLayer::SetCrop(unsigned int x, + unsigned int y, + unsigned int width, + unsigned int height) + { + if (!hasSize_) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + if (x + width > width_ || + y + height > height_) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + geometry_.SetCrop(x, y, width, height); + UpdateTransform(); + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + void RadiographyLayer::SetGeometry(const Geometry& geometry) + { + geometry_ = geometry; + + if (hasSize_) + { + UpdateTransform(); + } + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + + void RadiographyLayer::GetCrop(unsigned int& x, + unsigned int& y, + unsigned int& width, + unsigned int& height) const + { + if (GetGeometry().HasCrop()) + { + GetGeometry().GetCrop(x, y, width, height); + } + else + { + x = 0; + y = 0; + width = width_; + height = height_; + } + } + + + void RadiographyLayer::SetAngle(double angle) + { + geometry_.SetAngle(angle); + UpdateTransform(); + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + void RadiographyLayer::SetFlipVertical(bool flip) + { + geometry_.SetFlipVertical(flip); + UpdateTransform(); + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + void RadiographyLayer::SetFlipHorizontal(bool flip) + { + geometry_.SetFlipHorizontal(flip); + UpdateTransform(); + + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + void RadiographyLayer::SetSize(unsigned int width, + unsigned int height, + bool emitLayerEditedEvent) + { + hasSize_ = true; + width_ = width; + height_ = height; + + UpdateTransform(); + + if (emitLayerEditedEvent) + { + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + } + + Extent2D RadiographyLayer::GetSceneExtent(bool /*minimal*/) const + { + Extent2D extent; + + unsigned int x, y, width, height; + GetCrop(x, y, width, height); + + double dx = static_cast<double>(x); + double dy = static_cast<double>(y); + double dwidth = static_cast<double>(width); + double dheight = static_cast<double>(height); + + // AddToExtent transforms the coordinates from image to scene + AddToExtent(extent, dx, dy); + AddToExtent(extent, dx + dwidth, dy); + AddToExtent(extent, dx, dy + dheight); + AddToExtent(extent, dx + dwidth, dy + dheight); + + return extent; + } + + + bool RadiographyLayer::GetPixel(unsigned int& imageX, + unsigned int& imageY, + double sceneX, + double sceneY) const + { + if (width_ == 0 || + height_ == 0) + { + return false; + } + else + { + GetTransformInverse().Apply(sceneX, sceneY); + + int x = static_cast<int>(std::floor(sceneX)); + int y = static_cast<int>(std::floor(sceneY)); + + if (x < 0) + { + imageX = 0; + } + else if (x >= static_cast<int>(width_)) + { + imageX = width_; + } + else + { + imageX = static_cast<unsigned int>(x); + } + + if (y < 0) + { + imageY = 0; + } + else if (y >= static_cast<int>(height_)) + { + imageY = height_; + } + else + { + imageY = static_cast<unsigned int>(y); + } + + return true; + } + } + + + void RadiographyLayer::SetPan(double x, + double y) + { + geometry_.SetPan(x, y); + UpdateTransform(); + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + + + void RadiographyLayer::SetPixelSpacing(double x, + double y, + bool emitLayerEditedEvent) + { + geometry_.SetPixelSpacing(x, y); + UpdateTransform(); + if (emitLayerEditedEvent) + { + BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); + } + } + + + void RadiographyLayer::GetCenter(double& centerX, + double& centerY) const + { + centerX = static_cast<double>(width_) / 2.0; + centerY = static_cast<double>(height_) / 2.0; + GetTransform().Apply(centerX, centerY); + } + + + + size_t RadiographyLayer::GetControlPointCount() const {return 4;} + + void RadiographyLayer::GetControlPoint(ControlPoint& cpScene /* out in scene coordinates */, + size_t index) const + { + unsigned int cropX, cropY, cropWidth, cropHeight; + GetCrop(cropX, cropY, cropWidth, cropHeight); + + ControlPoint cp; + switch (index) + { + case RadiographyControlPointType_TopLeftCorner: + cp = ControlPoint(cropX, cropY, RadiographyControlPointType_TopLeftCorner); + break; + + case RadiographyControlPointType_TopRightCorner: + cp = ControlPoint(cropX + cropWidth, cropY, RadiographyControlPointType_TopRightCorner); + break; + + case RadiographyControlPointType_BottomLeftCorner: + cp = ControlPoint(cropX, cropY + cropHeight, RadiographyControlPointType_BottomLeftCorner); + break; + + case RadiographyControlPointType_BottomRightCorner: + cp = ControlPoint(cropX + cropWidth, cropY + cropHeight, RadiographyControlPointType_BottomRightCorner); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + // transforms image coordinates into scene coordinates + GetTransform().Apply(cp.x, cp.y); + cpScene = cp; + } + + bool RadiographyLayer::LookupControlPoint(ControlPoint& cpScene /* out */, + double x, + double y, + double zoom, + double viewportDistance) const + { + double threshold = Square(viewportDistance / zoom); + + for (size_t i = 0; i < GetControlPointCount(); i++) + { + ControlPoint cp; + GetControlPoint(cp, i); + + double d = Square(cp.x - x) + Square(cp.y - y); + + if (d <= threshold) + { + cpScene = cp; + return true; + } + } + + return false; + } +}