diff Framework/Radiography/RadiographyLayer.cpp @ 410:6decc0ba9da5

rename RadiographyScene::Layer as RadiographyLayer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 12 Nov 2018 15:52:03 +0100
parents
children b85f635f1eb5 b70e9be013e4
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Radiography/RadiographyLayer.cpp	Mon Nov 12 15:52:03 2018 +0100
@@ -0,0 +1,391 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "RadiographyLayer.h"
+
+#include <Core/OrthancException.h>
+
+
+namespace OrthancStone
+{
+  static double Square(double x)
+  {
+    return x * x;
+  }
+
+
+  void RadiographyLayer::UpdateTransform()
+  {
+    transform_ = AffineTransform2D::CreateScaling(pixelSpacingX_, pixelSpacingY_);
+
+    double centerX, centerY;
+    GetCenter(centerX, centerY);
+
+    transform_ = AffineTransform2D::Combine(
+      AffineTransform2D::CreateOffset(panX_ + centerX, panY_ + centerY),
+      AffineTransform2D::CreateRotation(angle_),
+      AffineTransform2D::CreateOffset(-centerX, -centerY),
+      transform_);
+
+    transformInverse_ = AffineTransform2D::Invert(transform_);
+  }
+
+
+  void RadiographyLayer::AddToExtent(Extent2D& extent,
+                                     double x,
+                                     double y) const
+  {
+    transform_.Apply(x, y);
+    extent.AddPoint(x, y);
+  }
+
+
+  void RadiographyLayer::GetCornerInternal(double& x,
+                                           double& y,
+                                           Corner corner,
+                                           unsigned int cropX,
+                                           unsigned int cropY,
+                                           unsigned int cropWidth,
+                                           unsigned int cropHeight) const
+  {
+    double dx = static_cast<double>(cropX);
+    double dy = static_cast<double>(cropY);
+    double dwidth = static_cast<double>(cropWidth);
+    double dheight = static_cast<double>(cropHeight);
+
+    switch (corner)
+    {
+      case Corner_TopLeft:
+        x = dx;
+        y = dy;
+        break;
+
+      case Corner_TopRight:
+        x = dx + dwidth;
+        y = dy;
+        break;
+
+      case Corner_BottomLeft:
+        x = dx;
+        y = dy + dheight;
+        break;
+
+      case Corner_BottomRight:
+        x = dx + dwidth;
+        y = dy + dheight;
+        break;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
+    transform_.Apply(x, y);
+  }
+
+
+  bool RadiographyLayer::Contains(double x,
+                                  double y) const
+  {
+    transformInverse_.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)
+  {
+    unsigned int cx, cy, width, height;
+    GetCrop(cx, cy, width, height);
+
+    double dx = static_cast<double>(cx);
+    double dy = static_cast<double>(cy);
+    double dwidth = static_cast<double>(width);
+    double dheight = static_cast<double>(height);
+
+    cairo_t* cr = context.GetObject();
+    cairo_set_line_width(cr, 2.0 / zoom);
+        
+    double x, y;
+    x = dx;
+    y = dy;
+    transform_.Apply(x, y);
+    cairo_move_to(cr, x, y);
+
+    x = dx + dwidth;
+    y = dy;
+    transform_.Apply(x, y);
+    cairo_line_to(cr, x, y);
+
+    x = dx + dwidth;
+    y = dy + dheight;
+    transform_.Apply(x, y);
+    cairo_line_to(cr, x, y);
+
+    x = dx;
+    y = dy + dheight;
+    transform_.Apply(x, y);
+    cairo_line_to(cr, x, y);
+
+    x = dx;
+    y = dy;
+    transform_.Apply(x, y);
+    cairo_line_to(cr, x, y);
+
+    cairo_stroke(cr);
+  }
+
+
+  RadiographyLayer::RadiographyLayer() :
+    index_(0),
+    hasSize_(false),
+    width_(0),
+    height_(0),
+    hasCrop_(false),
+    pixelSpacingX_(1),
+    pixelSpacingY_(1),
+    panX_(0),
+    panY_(0),
+    angle_(0),
+    resizeable_(false)
+  {
+    UpdateTransform();
+  }
+
+
+  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);
+    }
+        
+    hasCrop_ = true;
+    cropX_ = x;
+    cropY_ = y;
+    cropWidth_ = width;
+    cropHeight_ = height;
+
+    UpdateTransform();
+  }
+
+      
+  void RadiographyLayer::GetCrop(unsigned int& x,
+                                 unsigned int& y,
+                                 unsigned int& width,
+                                 unsigned int& height) const
+  {
+    if (hasCrop_)
+    {
+      x = cropX_;
+      y = cropY_;
+      width = cropWidth_;
+      height = cropHeight_;
+    }
+    else 
+    {
+      x = 0;
+      y = 0;
+      width = width_;
+      height = height_;
+    }
+  }
+
+      
+  void RadiographyLayer::SetAngle(double angle)
+  {
+    angle_ = angle;
+    UpdateTransform();
+  }
+
+
+  void RadiographyLayer::SetSize(unsigned int width,
+                                 unsigned int height)
+  {
+    if (hasSize_ &&
+        (width != width_ ||
+         height != height_))
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize);
+    }
+        
+    hasSize_ = true;
+    width_ = width;
+    height_ = height;
+
+    UpdateTransform();
+  }
+
+
+  Extent2D RadiographyLayer::GetExtent() 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(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
+    {
+      transformInverse_.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)
+  {
+    panX_ = x;
+    panY_ = y;
+    UpdateTransform();
+  }
+
+
+  void RadiographyLayer::SetPixelSpacing(double x,
+                                         double y)
+  {
+    pixelSpacingX_ = x;
+    pixelSpacingY_ = y;
+    UpdateTransform();
+  }
+
+
+  void RadiographyLayer::GetCenter(double& centerX,
+                                   double& centerY) const
+  {
+    centerX = static_cast<double>(width_) / 2.0;
+    centerY = static_cast<double>(height_) / 2.0;
+    transform_.Apply(centerX, centerY);
+  }
+
+
+  void RadiographyLayer::GetCorner(double& x /* out */,
+                                   double& y /* out */,
+                                   Corner corner) const
+  {
+    unsigned int cropX, cropY, cropWidth, cropHeight;
+    GetCrop(cropX, cropY, cropWidth, cropHeight);
+    GetCornerInternal(x, y, corner, cropX, cropY, cropWidth, cropHeight);
+  }
+      
+      
+  bool RadiographyLayer::LookupCorner(Corner& corner /* out */,
+                                      double x,
+                                      double y,
+                                      double zoom,
+                                      double viewportDistance) const
+  {
+    static const Corner CORNERS[] = {
+      Corner_TopLeft,
+      Corner_TopRight,
+      Corner_BottomLeft,
+      Corner_BottomRight
+    };
+        
+    unsigned int cropX, cropY, cropWidth, cropHeight;
+    GetCrop(cropX, cropY, cropWidth, cropHeight);
+
+    double threshold = Square(viewportDistance / zoom);
+        
+    for (size_t i = 0; i < 4; i++)
+    {
+      double cx, cy;
+      GetCornerInternal(cx, cy, CORNERS[i], cropX, cropY, cropWidth, cropHeight);
+
+      double d = Square(cx - x) + Square(cy - y);
+        
+      if (d <= threshold)
+      {
+        corner = CORNERS[i];
+        return true;
+      }
+    }
+        
+    return false;
+  }
+}