diff Framework/Scene2DViewport/MeasureToolsToolbox.cpp @ 698:8b6adfb62a2f refactor-viewport-controller

Code is broken -- stashing ongoing work in a branch
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 15 May 2019 16:56:17 +0200
parents
children c0fcb2757b0a 712ff6ff3c19
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2DViewport/MeasureToolsToolbox.cpp	Wed May 15 16:56:17 2019 +0200
@@ -0,0 +1,336 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 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 "MeasureToolsToolbox.h"
+
+#include <Framework/Scene2D/TextSceneLayer.h>
+
+#include <boost/math/constants/constants.hpp>
+
+namespace
+{
+  double g_pi = boost::math::constants::pi<double>();
+}
+
+namespace OrthancStone
+{
+  double RadiansToDegrees(double angleRad)
+  {
+    static const double factor = 180.0 / g_pi;
+    return angleRad * factor;
+  }
+
+  void AddSquare(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       sideLength)
+  {
+    chain.clear();
+    chain.reserve(4);
+    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account 
+    double handleLX = centerC.GetX() - sideLength / 2;
+    double handleTY = centerC.GetY() - sideLength / 2;
+    double handleRX = centerC.GetX() + sideLength / 2;
+    double handleBY = centerC.GetY() + sideLength / 2;
+    ScenePoint2D LTC(handleLX, handleTY);
+    ScenePoint2D RTC(handleRX, handleTY);
+    ScenePoint2D RBC(handleRX, handleBY);
+    ScenePoint2D LBC(handleLX, handleBY);
+
+    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
+
+    chain.push_back(startLT);
+    chain.push_back(startRT);
+    chain.push_back(startRB);
+    chain.push_back(startLB);
+  }
+#if 0
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&      scene
+    , const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2
+    , const double&       radiusS
+    , const bool          clockwise
+    , const int           subdivisionsCount)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    AddArc(
+      chain, scene, c, radiusS, p1cAngle, p2cAngle, 
+      clockwise, subdivisionsCount);
+  }
+#endif
+
+  void AddShortestArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&             scene
+    , const ScenePoint2D&        p1
+    , const ScenePoint2D&        c
+    , const ScenePoint2D&        p2
+    , const double&              radiusS
+    , const int                  subdivisionsCount)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    AddShortestArc(
+      chain, scene, c, radiusS, p1cAngle, p2cAngle, subdivisionsCount);
+  }
+
+  void GetPositionOnBisectingLine(
+    ScenePoint2D&       result
+    , const ScenePoint2D& p1
+    , const ScenePoint2D& c
+    , const ScenePoint2D& p2
+    , const double d)
+  {
+    // TODO: fix correct half-plane
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    double angle = 0.5*(p1cAngle + p2cAngle);
+    double unitVectorX = cos(angle);
+    double unitVectorY = sin(angle);
+    double posX = c.GetX() + d * unitVectorX;
+    double posY = c.GetX() + d * unitVectorY;
+    result = ScenePoint2D(posX, posY);
+  }
+   
+  void AddShortestArc(
+      PolylineSceneLayer::Chain&  chain
+    , const Scene2D&              scene
+    , const ScenePoint2D&         centerS
+    , const double&               radiusS
+    , const double                startAngleRad
+    , const double                endAngleRad
+    , const int                   subdivisionsCount)
+  {
+    // this gives a signed difference between angle which
+    // is the smallest difference (in magnitude) between 
+    // the angles
+    double delta = NormalizeAngle(endAngleRad-startAngleRad);
+
+    chain.clear();
+    chain.reserve(subdivisionsCount + 1);
+
+    double angleIncr = delta/static_cast<double>(subdivisionsCount);
+
+    double theta = startAngleRad;
+    for (int i = 0; i < subdivisionsCount + 1; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+
+#if 0
+  void AddArc(
+      PolylineSceneLayer::Chain& chain
+    , const Scene2D&      scene
+    , const ScenePoint2D& centerS
+    , const double&       radiusS
+    , const double        startAngleRad
+    , const double        endAngleRad
+    , const bool          clockwise
+    , const int           subdivisionsCount)
+  {
+    double startAngleRadN = NormalizeAngle(startAngleRad);
+    double endAngleRadN = NormalizeAngle(endAngleRad);
+
+    double angle1Rad = std::min(startAngleRadN, endAngleRadN);
+    double angle2Rad = std::max(startAngleRadN, endAngleRadN);
+
+    // now we are sure angle1Rad < angle2Rad
+    // this means that if we draw from 1 to 2, it will be clockwise (
+    // increasing angles).
+    // let's fix this:
+    if (!clockwise)
+    {
+      angle2Rad -= 2 * g_pi;
+      // now we are sure angle2Rad < angle1Rad (since they were normalized) 
+      // and, thus, going from 1 to 2 means the angle values will DECREASE,
+      // which is the definition of anticlockwise
+    }
+
+    chain.clear();
+    chain.reserve(subdivisionsCount + 1);
+
+    double angleIncr = (angle2Rad - angle1Rad)
+      / static_cast<double>(subdivisionsCount);
+
+    double theta = angle1Rad;
+    for (int i = 0; i < subdivisionsCount + 1; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+#endif
+
+  void AddCircle(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       radiusS,
+    const int           numSubdivisions)
+  {
+    //ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account
+
+    // TODO: automatically compute the number for segments for smooth 
+    // display based on the radius in pixels.
+
+    chain.clear();
+    chain.reserve(numSubdivisions);
+
+    double angleIncr = (2.0 * g_pi)
+      / static_cast<double>(numSubdivisions);
+
+    double theta = 0;
+    for (int i = 0; i < numSubdivisions; ++i)
+    {
+      double offsetX = radiusS * cos(theta);
+      double offsetY = radiusS * sin(theta);
+      double pointX = centerS.GetX() + offsetX;
+      double pointY = centerS.GetY() + offsetY;
+      chain.push_back(ScenePoint2D(pointX, pointY));
+      theta += angleIncr;
+    }
+  }
+
+  double NormalizeAngle(double angle)
+  {
+    double retAngle = angle;
+    while (retAngle < -1.0*g_pi)
+      retAngle += 2 * g_pi;
+    while (retAngle >= g_pi)
+      retAngle -= 2 * g_pi;
+    return retAngle;
+  }
+
+  double MeasureAngle(const ScenePoint2D& p1, const ScenePoint2D& c, const ScenePoint2D& p2)
+  {
+    double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
+    double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
+    double delta = p2cAngle - p1cAngle;
+    return NormalizeAngle(delta);
+  }
+
+
+#if 0
+  void AddEllipse(PolylineSceneLayer::Chain& chain,
+    const Scene2D&      scene,
+    const ScenePoint2D& centerS,
+    const double&       halfHAxis,
+    const double&       halfVAxis)
+  {
+    chain.clear();
+    chain.reserve(4);
+    ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
+    //TODO: take DPI into account
+    double handleLX = centerC.GetX() - sideLength / 2;
+    double handleTY = centerC.GetY() - sideLength / 2;
+    double handleRX = centerC.GetX() + sideLength / 2;
+    double handleBY = centerC.GetY() + sideLength / 2;
+    ScenePoint2D LTC(handleLX, handleTY);
+    ScenePoint2D RTC(handleRX, handleTY);
+    ScenePoint2D RBC(handleRX, handleBY);
+    ScenePoint2D LBC(handleLX, handleBY);
+
+    ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
+    ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
+
+    chain.push_back(startLT);
+    chain.push_back(startRT);
+    chain.push_back(startRB);
+    chain.push_back(startLB);
+}
+#endif
+
+
+  namespace
+  {
+    /**
+    Helper function for outlined text rendering
+    */
+    TextSceneLayer* GetOutlineTextLayer(
+      Scene2D& scene, int baseLayerIndex, int index)
+    {
+      assert(scene.HasLayer(baseLayerIndex));
+      assert(index >= 0);
+      assert(index < 5);
+
+      ISceneLayer * layer = &(scene.GetLayer(baseLayerIndex + index));
+      TextSceneLayer * concreteLayer = dynamic_cast<TextSceneLayer*>(layer);
+      assert(concreteLayer != NULL);
+      return concreteLayer;
+    }
+  }
+   
+  void SetTextLayerOutlineProperties(
+    Scene2D& scene, int baseLayerIndex, const char* text, ScenePoint2D p)
+  {
+    double xoffsets[5] = { 2, 0, -2, 0, 0 };
+    double yoffsets[5] = { 0, -2, 0, 2, 0 };
+
+    // get the scaling factor 
+    const double pixelToScene =
+      scene.GetCanvasToSceneTransform().ComputeZoom();
+
+    for (int i = 0; i < 5; ++i)
+    {
+      TextSceneLayer* textLayer = GetOutlineTextLayer(scene, baseLayerIndex, i);
+      textLayer->SetText(text);
+
+      if (i == 4)
+        textLayer->SetColor(0, 223, 81);
+      else
+        textLayer->SetColor(0, 56, 21);
+
+      ScenePoint2D textAnchor;
+      //GetPositionOnBisectingLine(
+      //  textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene);
+      textLayer->SetPosition(
+        p.GetX() + xoffsets[i] * pixelToScene,
+        p.GetY() + yoffsets[i] * pixelToScene);
+    }
+  }
+
+
+
+
+
+
+
+
+}