Mercurial > hg > orthanc-stone
view Framework/Scene2DViewport/MeasureToolsToolbox.cpp @ 710:3046a603eebf
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 20 May 2019 13:13:04 +0200 |
parents | 8b6adfb62a2f |
children | c0fcb2757b0a 712ff6ff3c19 |
line wrap: on
line source
/** * 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); } } }