# HG changeset patch # User Benjamin Golinvaux # Date 1557753176 -7200 # Node ID 1e9ed656318e051a7c18d0c07634aa7962eab866 # Parent f939f449482ce59f70c71b86280283bca4b3935e# Parent 7ca8dc7ec17b23c32c7a68e6c679c21c25cc4e16 Merge + ongoing measure work diff -r f939f449482c -r 1e9ed656318e .hgignore --- a/.hgignore Fri May 10 16:15:55 2019 +0200 +++ b/.hgignore Mon May 13 15:12:56 2019 +0200 @@ -30,3 +30,5 @@ Resources/CommandTool/protoc-tests/generated_ts/ Resources/CommandTool/protoc-tests/node_modules/ Samples/Sdl/ThirdPartyDownloads/ +Samples/Sdl/CMakeLists.txt.orig + diff -r f939f449482c -r 1e9ed656318e Framework/StoneEnumerations.h --- a/Framework/StoneEnumerations.h Fri May 10 16:15:55 2019 +0200 +++ b/Framework/StoneEnumerations.h Mon May 13 15:12:56 2019 +0200 @@ -172,6 +172,13 @@ MessageType_Test1, MessageType_Test2, + + + MessageType_OrthancRestApiCommand, + MessageType_GetOrthancImageCommand, + MessageType_GetOrthancWebViewerJpegCommand, + MessageType_OracleCommandExceptionMessage, + MessageType_CustomMessage // Custom messages ids ust be greater than this (this one must remain in last position) }; diff -r f939f449482c -r 1e9ed656318e Samples/Common/AngleMeasureTool.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/AngleMeasureTool.cpp Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,199 @@ +/** + * 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 . + **/ + +#include "AngleMeasureTool.h" +#include "MeasureToolsToolbox.h" + +#include + +#include + +namespace OrthancStone +{ + AngleMeasureTool::~AngleMeasureTool() + { + // this measuring tool is a RABI for the corresponding visual layers + // stored in the 2D scene + Disable(); + RemoveFromScene(); + } + + void AngleMeasureTool::RemoveFromScene() + { + if (layersCreated) + { + assert(GetScene().HasLayer(polylineZIndex_)); + assert(GetScene().HasLayer(textZIndex_)); + GetScene().DeleteLayer(polylineZIndex_); + GetScene().DeleteLayer(textZIndex_); + } + } + + void AngleMeasureTool::SetSide1End(ScenePoint2D pt) + { + side1End_ = pt; + RefreshScene(); + } + + void AngleMeasureTool::SetSide2End(ScenePoint2D pt) + { + side2End_ = pt; + RefreshScene(); + } + + void AngleMeasureTool::SetCenter(ScenePoint2D pt) + { + center_ = pt; + RefreshScene(); + } + + PolylineSceneLayer* AngleMeasureTool::GetPolylineLayer() + { + assert(GetScene().HasLayer(polylineZIndex_)); + ISceneLayer* layer = &(GetScene().GetLayer(polylineZIndex_)); + PolylineSceneLayer* concreteLayer = dynamic_cast(layer); + assert(concreteLayer != NULL); + return concreteLayer; + } + + TextSceneLayer* AngleMeasureTool::GetTextLayer() + { + assert(GetScene().HasLayer(textZIndex_)); + ISceneLayer* layer = &(GetScene().GetLayer(textZIndex_)); + TextSceneLayer* concreteLayer = dynamic_cast(layer); + assert(concreteLayer != NULL); + return concreteLayer; + } + + + void AngleMeasureTool::RefreshScene() + { + if (IsEnabled()) + { + + // get the scaling factor + const double pixelToScene = + GetScene().GetCanvasToSceneTransform().ComputeZoom(); + + if (!layersCreated) + { + // Create the layers if need be + + assert(textZIndex_ == -1); + { + polylineZIndex_ = GetScene().GetMaxDepth() + 100; + //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_; + std::auto_ptr layer(new PolylineSceneLayer()); + GetScene().SetLayer(polylineZIndex_, layer.release()); + } + { + textZIndex_ = GetScene().GetMaxDepth() + 100; + //LOG(INFO) << "set textZIndex_ to: " << textZIndex_; + std::auto_ptr layer(new TextSceneLayer()); + GetScene().SetLayer(textZIndex_, layer.release()); + } + layersCreated = true; + } + else + { + assert(GetScene().HasLayer(polylineZIndex_)); + assert(GetScene().HasLayer(textZIndex_)); + } + { + // Fill the polyline layer with the measurement line + + PolylineSceneLayer* polylineLayer = GetPolylineLayer(); + polylineLayer->ClearAllChains(); + polylineLayer->SetColor(0, 223, 21); + + // sides + { + { + PolylineSceneLayer::Chain chain; + chain.push_back(side1End_); + chain.push_back(center_); + polylineLayer->AddChain(chain, false); + } + { + PolylineSceneLayer::Chain chain; + chain.push_back(side2End_); + chain.push_back(center_); + polylineLayer->AddChain(chain, false); + } + } + + // handles + { + //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength) + + { + PolylineSceneLayer::Chain chain; + AddSquare(chain, GetScene(), side1End_, 10.0); //TODO: take DPI into account + polylineLayer->AddChain(chain, true); + } + + { + PolylineSceneLayer::Chain chain; + AddSquare(chain, GetScene(), side2End_, 10.0); //TODO: take DPI into account + polylineLayer->AddChain(chain, true); + } + } + + // arc + { + PolylineSceneLayer::Chain chain; + + AddArc(chain, GetScene(), side1End_, center_, side2End_, + 20.0*pixelToScene, true); //TODO: true means always clockwise + polylineLayer->AddChain(chain, true); + } + } + { + // Set the text layer proporeties + + // the angle is measured in a clockwise way between the points + double angleRad = MeasureAngle(side1End_, center_, side2End_); + double angleDeg = RadiansToDegrees(angleRad); + + TextSceneLayer* textLayer = GetTextLayer(); + + char buf[64]; + sprintf(buf, "%0.02f deg", angleDeg); + textLayer->SetText(buf); + textLayer->SetColor(0, 223, 21); + + ScenePoint2D textAnchor; + GetPositionOnBisectingLine( + textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene); + textLayer->SetPosition(textAnchor.GetX(), textAnchor.GetY()); + } + } + else + { + if (layersCreated) + { + RemoveFromScene(); + layersCreated = false; + } + } + } + + +} diff -r f939f449482c -r 1e9ed656318e Samples/Common/AngleMeasureTool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/AngleMeasureTool.h Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,74 @@ +/** + * 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 . + **/ + +#pragma once + +#include "MeasureTools.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace OrthancStone +{ + class AngleMeasureTool : public MeasureTool + { + public: + AngleMeasureTool(Scene2D& scene) + : MeasureTool(scene) + , layersCreated(false) + , polylineZIndex_(-1) + , textZIndex_(-1) + { + + } + + ~AngleMeasureTool(); + + void SetSide1End(ScenePoint2D start); + void SetCenter(ScenePoint2D start); + void SetSide2End(ScenePoint2D start); + + private: + PolylineSceneLayer* GetPolylineLayer(); + TextSceneLayer* GetTextLayer(); + virtual void RefreshScene() ORTHANC_OVERRIDE; + void RemoveFromScene(); + + private: + ScenePoint2D side1End_; + ScenePoint2D side2End_; + ScenePoint2D center_; + bool layersCreated; + int polylineZIndex_; + int textZIndex_; + }; + + typedef boost::shared_ptr AngleMeasureToolPtr; +} + + diff -r f939f449482c -r 1e9ed656318e Samples/Common/CreateAngleMeasureTracker.cpp --- a/Samples/Common/CreateAngleMeasureTracker.cpp Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/CreateAngleMeasureTracker.cpp Mon May 13 15:12:56 2019 +0200 @@ -18,6 +18,109 @@ * along with this program. If not, see . **/ +#include "CreateAngleMeasureTracker.h" +#include + +using namespace Orthanc; + namespace OrthancStone { + CreateAngleMeasureTracker::CreateAngleMeasureTracker( + Scene2D& scene, + std::vector& undoStack, + std::vector& measureTools, + const PointerEvent& e) + : CreateMeasureTracker(scene, undoStack, measureTools) + , state_(CreatingSide1) + { + command_.reset( + new CreateAngleMeasureCommand( + scene, + measureTools, + e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform()))); + } + + CreateAngleMeasureTracker::~CreateAngleMeasureTracker() + { + } + + void CreateAngleMeasureTracker::PointerMove(const PointerEvent& event) + { + if (!active_) + { + throw OrthancException(ErrorCode_InternalError, + "Internal error: wrong state in CreateAngleMeasureTracker::" + "PointerMove: active_ == false"); + } + + ScenePoint2D scenePos = event.GetMainPosition().Apply( + scene_.GetCanvasToSceneTransform()); + + switch (state_) + { + case CreatingSide1: + GetCommand()->SetCenter(scenePos); + break; + case CreatingSide2: + GetCommand()->SetSide2End(scenePos); + break; + default: + throw OrthancException(ErrorCode_InternalError, + "Wrong state in CreateAngleMeasureTracker::" + "PointerMove: state_ invalid"); + } + //LOG(TRACE) << "scenePos.GetX() = " << scenePos.GetX() << " " << + // "scenePos.GetY() = " << scenePos.GetY(); + } + + void CreateAngleMeasureTracker::PointerUp(const PointerEvent& e) + { + // TODO: the current app does not prevent multiple PointerDown AND + // PointerUp to be sent to the tracker. + // Unless we augment the PointerEvent structure with the button index, + // we cannot really tell if this pointer up event matches the initial + // pointer down event. Let's make it simple for now. + + switch (state_) + { + case CreatingSide1: + state_ = CreatingSide2; + break; + case CreatingSide2: + throw OrthancException(ErrorCode_InternalError, + "Wrong state in CreateAngleMeasureTracker::" + "PointerUp: state_ == CreatingSide2 ; this should not happen"); + break; + default: + throw OrthancException(ErrorCode_InternalError, + "Wrong state in CreateAngleMeasureTracker::" + "PointerMove: state_ invalid"); + } + } + + void CreateAngleMeasureTracker::PointerDown(const PointerEvent& e) + { + switch (state_) + { + case CreatingSide1: + throw OrthancException(ErrorCode_InternalError, + "Wrong state in CreateAngleMeasureTracker::" + "PointerDown: state_ == CreatingSide1 ; this should not happen"); + break; + case CreatingSide2: + // we are done + active_ = false; + break; + default: + throw OrthancException(ErrorCode_InternalError, + "Wrong state in CreateAngleMeasureTracker::" + "PointerMove: state_ invalid"); + } + } + + CreateAngleMeasureCommandPtr CreateAngleMeasureTracker::GetCommand() + { + return boost::dynamic_pointer_cast(command_); + } + } diff -r f939f449482c -r 1e9ed656318e Samples/Common/CreateAngleMeasureTracker.h --- a/Samples/Common/CreateAngleMeasureTracker.h Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/CreateAngleMeasureTracker.h Mon May 13 15:12:56 2019 +0200 @@ -20,6 +20,45 @@ #pragma once +#include "MeasureTrackers.h" +#include "MeasureCommands.h" + +#include + namespace OrthancStone { + class CreateAngleMeasureTracker : public CreateMeasureTracker + { + public: + /** + When you create this tracker, you need to supply it with the undo stack + where it will store the commands that perform the actual measure tool + creation and modification. + In turn, a container for these commands to store the actual measuring + must be supplied, too + */ + CreateAngleMeasureTracker( + Scene2D& scene, + std::vector& undoStack, + std::vector& measureTools, + const PointerEvent& e); + + ~CreateAngleMeasureTracker(); + + virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE; + virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE; + + private: + CreateAngleMeasureCommandPtr GetCommand(); + + enum State + { + CreatingSide1, + CreatingSide2, + Finished // just for debug + }; + State state_; + + }; } diff -r f939f449482c -r 1e9ed656318e Samples/Common/CreateLineMeasureTracker.cpp --- a/Samples/Common/CreateLineMeasureTracker.cpp Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/CreateLineMeasureTracker.cpp Mon May 13 15:12:56 2019 +0200 @@ -62,7 +62,7 @@ CreateLineMeasureTracker* concreteThis = dynamic_cast(this); assert(concreteThis != NULL); - command_->Update(scenePos); + GetCommand()->SetEnd(scenePos); } void CreateLineMeasureTracker::PointerUp(const PointerEvent& e) @@ -80,4 +80,10 @@ LOG(WARNING) << "Additional touches (fingers, pen, mouse buttons...) " "are ignored when the line measure creation tracker is active"; } + + CreateLineMeasureCommandPtr CreateLineMeasureTracker::GetCommand() + { + return boost::dynamic_pointer_cast(command_); + } + } diff -r f939f449482c -r 1e9ed656318e Samples/Common/CreateLineMeasureTracker.h --- a/Samples/Common/CreateLineMeasureTracker.h Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/CreateLineMeasureTracker.h Mon May 13 15:12:56 2019 +0200 @@ -45,5 +45,8 @@ virtual void PointerMove(const PointerEvent& e) ORTHANC_OVERRIDE; virtual void PointerUp(const PointerEvent& e) ORTHANC_OVERRIDE; virtual void PointerDown(const PointerEvent& e) ORTHANC_OVERRIDE; + + private: + CreateLineMeasureCommandPtr GetCommand(); }; } diff -r f939f449482c -r 1e9ed656318e Samples/Common/LineMeasureTool.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/LineMeasureTool.cpp Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,200 @@ +/** + * 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 . + **/ + +#include "LineMeasureTool.h" +#include "MeasureToolsToolbox.h" + +#include + + +namespace OrthancStone +{ + LineMeasureTool::~LineMeasureTool() + { + // this measuring tool is a RABI for the corresponding visual layers + // stored in the 2D scene + Disable(); + RemoveFromScene(); + } + + void LineMeasureTool::RemoveFromScene() + { + if (layersCreated) + { + assert(GetScene().HasLayer(polylineZIndex_)); + assert(GetScene().HasLayer(textZIndex_)); + GetScene().DeleteLayer(polylineZIndex_); + GetScene().DeleteLayer(textZIndex_); + } + } + + + void LineMeasureTool::SetStart(ScenePoint2D start) + { + start_ = start; + RefreshScene(); + } + + void LineMeasureTool::SetEnd(ScenePoint2D end) + { + end_ = end; + RefreshScene(); + } + + void LineMeasureTool::Set(ScenePoint2D start, ScenePoint2D end) + { + start_ = start; + end_ = end; + RefreshScene(); + } + + PolylineSceneLayer* LineMeasureTool::GetPolylineLayer() + { + assert(GetScene().HasLayer(polylineZIndex_)); + ISceneLayer* layer = &(GetScene().GetLayer(polylineZIndex_)); + PolylineSceneLayer* concreteLayer = dynamic_cast(layer); + assert(concreteLayer != NULL); + return concreteLayer; + } + + TextSceneLayer* LineMeasureTool::GetTextLayer() + { + assert(GetScene().HasLayer(textZIndex_)); + ISceneLayer* layer = &(GetScene().GetLayer(textZIndex_)); + TextSceneLayer* concreteLayer = dynamic_cast(layer); + assert(concreteLayer != NULL); + return concreteLayer; + } + + void LineMeasureTool::RefreshScene() + { + if (IsEnabled()) + { + if (!layersCreated) + { + // Create the layers if need be + + assert(textZIndex_ == -1); + { + polylineZIndex_ = GetScene().GetMaxDepth() + 100; + //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_; + std::auto_ptr layer(new PolylineSceneLayer()); + GetScene().SetLayer(polylineZIndex_, layer.release()); + } + { + textZIndex_ = GetScene().GetMaxDepth() + 100; + //LOG(INFO) << "set textZIndex_ to: " << textZIndex_; + std::auto_ptr layer(new TextSceneLayer()); + GetScene().SetLayer(textZIndex_, layer.release()); + } + layersCreated = true; + } + else + { + assert(GetScene().HasLayer(polylineZIndex_)); + assert(GetScene().HasLayer(textZIndex_)); + } + { + // Fill the polyline layer with the measurement line + + PolylineSceneLayer* polylineLayer = GetPolylineLayer(); + polylineLayer->ClearAllChains(); + polylineLayer->SetColor(0, 223, 21); + + { + PolylineSceneLayer::Chain chain; + chain.push_back(start_); + chain.push_back(end_); + polylineLayer->AddChain(chain, false); + } + + // handles + { + //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength) + + { + PolylineSceneLayer::Chain chain; + AddSquare(chain, GetScene(), start_, 10.0); //TODO: take DPI into account + polylineLayer->AddChain(chain, true); + } + + { + PolylineSceneLayer::Chain chain; + AddSquare(chain, GetScene(), end_, 10.0); //TODO: take DPI into account + polylineLayer->AddChain(chain, true); + } + + //ScenePoint2D startC = start_.Apply(GetScene().GetSceneToCanvasTransform()); + //double squareSize = 10.0; + //double startHandleLX = startC.GetX() - squareSize/2; + //double startHandleTY = startC.GetY() - squareSize / 2; + //double startHandleRX = startC.GetX() + squareSize / 2; + //double startHandleBY = startC.GetY() + squareSize / 2; + //ScenePoint2D startLTC(startHandleLX, startHandleTY); + //ScenePoint2D startRTC(startHandleRX, startHandleTY); + //ScenePoint2D startRBC(startHandleRX, startHandleBY); + //ScenePoint2D startLBC(startHandleLX, startHandleBY); + + //ScenePoint2D startLT = startLTC.Apply(GetScene().GetCanvasToSceneTransform()); + //ScenePoint2D startRT = startRTC.Apply(GetScene().GetCanvasToSceneTransform()); + //ScenePoint2D startRB = startRBC.Apply(GetScene().GetCanvasToSceneTransform()); + //ScenePoint2D startLB = startLBC.Apply(GetScene().GetCanvasToSceneTransform()); + + //PolylineSceneLayer::Chain chain; + //chain.push_back(startLT); + //chain.push_back(startRT); + //chain.push_back(startRB); + //chain.push_back(startLB); + //polylineLayer->AddChain(chain, true); + } + + } + { + // Set the text layer proporeties + + TextSceneLayer* textLayer = GetTextLayer(); + double deltaX = end_.GetX() - start_.GetX(); + double deltaY = end_.GetY() - start_.GetY(); + double squareDist = deltaX * deltaX + deltaY * deltaY; + double dist = sqrt(squareDist); + char buf[64]; + sprintf(buf, "%0.02f units", dist); + textLayer->SetText(buf); + textLayer->SetColor(0, 223, 21); + + // TODO: for now we simply position the text overlay at the middle + // of the measuring segment + double midX = 0.5*(end_.GetX() + start_.GetX()); + double midY = 0.5*(end_.GetY() + start_.GetY()); + textLayer->SetPosition(midX, midY); + } + } + else + { + if (layersCreated) + { + RemoveFromScene(); + layersCreated = false; + } + } + } + + +} \ No newline at end of file diff -r f939f449482c -r 1e9ed656318e Samples/Common/LineMeasureTool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/LineMeasureTool.h Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,72 @@ +/** + * 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 . + **/ + +#pragma once + +#include "MeasureTools.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace OrthancStone +{ + class LineMeasureTool : public MeasureTool + { + public: + LineMeasureTool(Scene2D& scene) + : MeasureTool(scene) + , layersCreated(false) + , polylineZIndex_(-1) + , textZIndex_(-1) + { + + } + + ~LineMeasureTool(); + + void SetStart(ScenePoint2D start); + void SetEnd(ScenePoint2D end); + void Set(ScenePoint2D start, ScenePoint2D end); + + private: + PolylineSceneLayer* GetPolylineLayer(); + TextSceneLayer* GetTextLayer(); + virtual void RefreshScene() ORTHANC_OVERRIDE; + void RemoveFromScene(); + + private: + ScenePoint2D start_; + ScenePoint2D end_; + bool layersCreated; + int polylineZIndex_; + int textZIndex_; + }; + + typedef boost::shared_ptr LineMeasureToolPtr; +} + diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureCommands.cpp --- a/Samples/Common/MeasureCommands.cpp Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureCommands.cpp Mon May 13 15:12:56 2019 +0200 @@ -52,15 +52,36 @@ : CreateMeasureCommand(scene, measureTools) , measureTool_(new LineMeasureTool(scene)) { - measureTool_ = LineMeasureToolPtr(new LineMeasureTool(scene)); measureTools_.push_back(measureTool_); measureTool_->Set(point, point); } - void CreateLineMeasureCommand::Update(ScenePoint2D scenePos) + void CreateLineMeasureCommand::SetEnd(ScenePoint2D scenePos) { measureTool_->SetEnd(scenePos); } + CreateAngleMeasureCommand::CreateAngleMeasureCommand( + Scene2D& scene, MeasureToolList& measureTools, ScenePoint2D point) + : CreateMeasureCommand(scene, measureTools) + , measureTool_(new AngleMeasureTool(scene)) + { + measureTools_.push_back(measureTool_); + measureTool_->SetSide1End(point); + measureTool_->SetCenter(point); + measureTool_->SetSide2End(point); + } + + /** This method sets center*/ + void CreateAngleMeasureCommand::SetCenter(ScenePoint2D scenePos) + { + measureTool_->SetCenter(scenePos); + } + + /** This method sets end of side 2*/ + void CreateAngleMeasureCommand::SetSide2End(ScenePoint2D scenePos) + { + measureTool_->SetSide2End(scenePos); + } } diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureCommands.h --- a/Samples/Common/MeasureCommands.h Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureCommands.h Mon May 13 15:12:56 2019 +0200 @@ -24,9 +24,16 @@ // to be moved into Stone #include "MeasureTools.h" +#include "LineMeasureTool.h" +#include "AngleMeasureTool.h" namespace OrthancStone { + //class LineMeasureTool; + //typedef boost::shared_ptr LineMeasureToolPtr; + //class AngleMeasureTool; + //typedef boost::shared_ptr AngleMeasureToolPtr; + class TrackerCommand { public: @@ -36,8 +43,6 @@ } virtual void Undo() = 0; virtual void Redo() = 0; - virtual void Update(ScenePoint2D scenePos) = 0; - Scene2D& GetScene() { return scene_; @@ -74,7 +79,8 @@ CreateLineMeasureCommand( Scene2D& scene, MeasureToolList& measureTools, ScenePoint2D point); - void Update(ScenePoint2D scenePos) ORTHANC_OVERRIDE; + // the starting position is set in the ctor + void SetEnd(ScenePoint2D scenePos); private: virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE @@ -82,10 +88,31 @@ return measureTool_; } LineMeasureToolPtr measureTool_; - ScenePoint2D start_; - ScenePoint2D end_; }; typedef boost::shared_ptr CreateLineMeasureCommandPtr; + + class CreateAngleMeasureCommand : public CreateMeasureCommand + { + public: + /** Ctor sets end of side 1*/ + CreateAngleMeasureCommand( + Scene2D& scene, MeasureToolList& measureTools, ScenePoint2D point); + + /** This method sets center*/ + void SetCenter(ScenePoint2D scenePos); + + /** This method sets end of side 2*/ + void SetSide2End(ScenePoint2D scenePos); + + private: + virtual MeasureToolPtr GetMeasureTool() ORTHANC_OVERRIDE + { + return measureTool_; + } + AngleMeasureToolPtr measureTool_; + }; + + typedef boost::shared_ptr CreateAngleMeasureCommandPtr; } diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureTools.cpp --- a/Samples/Common/MeasureTools.cpp Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureTools.cpp Mon May 13 15:12:56 2019 +0200 @@ -18,8 +18,10 @@ * along with this program. If not, see . **/ +#include "MeasureTools.h" + #include -#include "MeasureTools.h" + #include namespace OrthancStone @@ -35,276 +37,5 @@ enabled_ = false; RefreshScene(); } - - LineMeasureTool::~LineMeasureTool() - { - // this measuring tool is a RABI for the corresponding visual layers - // stored in the 2D scene - Disable(); - RemoveFromScene(); - } - - void LineMeasureTool::RemoveFromScene() - { - if (layersCreated) - { - assert(GetScene().HasLayer(polylineZIndex_)); - assert(GetScene().HasLayer(textZIndex_)); - GetScene().DeleteLayer(polylineZIndex_); - GetScene().DeleteLayer(textZIndex_); - } - } - - - void LineMeasureTool::SetStart(ScenePoint2D start) - { - start_ = start; - RefreshScene(); - } - - void LineMeasureTool::SetEnd(ScenePoint2D end) - { - end_ = end; - RefreshScene(); - } - - void LineMeasureTool::Set(ScenePoint2D start, ScenePoint2D end) - { - start_ = start; - end_ = end; - RefreshScene(); - } - - PolylineSceneLayer* LineMeasureTool::GetPolylineLayer() - { - assert(GetScene().HasLayer(polylineZIndex_)); - ISceneLayer* layer = &(GetScene().GetLayer(polylineZIndex_)); - PolylineSceneLayer* concreteLayer = dynamic_cast(layer); - assert(concreteLayer != NULL); - return concreteLayer; - } - - TextSceneLayer* LineMeasureTool::GetTextLayer() - { - assert(GetScene().HasLayer(textZIndex_)); - ISceneLayer* layer = &(GetScene().GetLayer(textZIndex_)); - TextSceneLayer* concreteLayer = dynamic_cast(layer); - assert(concreteLayer != NULL); - return concreteLayer; - } - - namespace - { - /** - This function will create a square around the center point supplied in - scene coordinates, with a side length given in canvas coordinates. The - square sides are parallel to the canvas boundaries. - */ - 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); - } - - void AddCircle(PolylineSceneLayer::Chain& chain, - const Scene2D& scene, - const ScenePoint2D& centerS, - const double& radiusS) - { - chain.clear(); - chain.reserve(4); - //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. - int lineCount = 50; - - double angleIncr = (2.0 * boost::math::constants::pi()) - / static_cast(lineCount); - - double theta = 0; - for (int i = 0; i < lineCount; ++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 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 - - - } - - - void LineMeasureTool::RefreshScene() - { - if (IsEnabled()) - { - if (!layersCreated) - { - // Create the layers if need be - - assert(textZIndex_ == -1); - { - polylineZIndex_ = GetScene().GetMaxDepth() + 100; - //LOG(INFO) << "set polylineZIndex_ to: " << polylineZIndex_; - std::auto_ptr layer(new PolylineSceneLayer()); - GetScene().SetLayer(polylineZIndex_, layer.release()); - } - { - textZIndex_ = GetScene().GetMaxDepth() + 100; - //LOG(INFO) << "set textZIndex_ to: " << textZIndex_; - std::auto_ptr layer(new TextSceneLayer()); - GetScene().SetLayer(textZIndex_, layer.release()); - } - layersCreated = true; - } - else - { - assert(GetScene().HasLayer(polylineZIndex_)); - assert(GetScene().HasLayer(textZIndex_)); - } - { - // Fill the polyline layer with the measurement line - - PolylineSceneLayer* polylineLayer = GetPolylineLayer(); - polylineLayer->ClearAllChains(); - polylineLayer->SetColor(0, 223, 21); - - { - PolylineSceneLayer::Chain chain; - chain.push_back(start_); - chain.push_back(end_); - polylineLayer->AddChain(chain, false); - } - - // handles - { - //void AddSquare(PolylineSceneLayer::Chain& chain,const Scene2D& scene,const ScenePoint2D& centerS,const double& sideLength) - - { - PolylineSceneLayer::Chain chain; - AddSquare(chain, GetScene(), start_, 10.0); //TODO: take DPI into account - polylineLayer->AddChain(chain, true); - } - - { - PolylineSceneLayer::Chain chain; - AddSquare(chain, GetScene(), end_, 10.0); //TODO: take DPI into account - polylineLayer->AddChain(chain, true); - } - - //ScenePoint2D startC = start_.Apply(GetScene().GetSceneToCanvasTransform()); - //double squareSize = 10.0; - //double startHandleLX = startC.GetX() - squareSize/2; - //double startHandleTY = startC.GetY() - squareSize / 2; - //double startHandleRX = startC.GetX() + squareSize / 2; - //double startHandleBY = startC.GetY() + squareSize / 2; - //ScenePoint2D startLTC(startHandleLX, startHandleTY); - //ScenePoint2D startRTC(startHandleRX, startHandleTY); - //ScenePoint2D startRBC(startHandleRX, startHandleBY); - //ScenePoint2D startLBC(startHandleLX, startHandleBY); - - //ScenePoint2D startLT = startLTC.Apply(GetScene().GetCanvasToSceneTransform()); - //ScenePoint2D startRT = startRTC.Apply(GetScene().GetCanvasToSceneTransform()); - //ScenePoint2D startRB = startRBC.Apply(GetScene().GetCanvasToSceneTransform()); - //ScenePoint2D startLB = startLBC.Apply(GetScene().GetCanvasToSceneTransform()); - - //PolylineSceneLayer::Chain chain; - //chain.push_back(startLT); - //chain.push_back(startRT); - //chain.push_back(startRB); - //chain.push_back(startLB); - //polylineLayer->AddChain(chain, true); - } - - } - { - // Set the text layer proporeties - - TextSceneLayer* textLayer = GetTextLayer(); - double deltaX = end_.GetX() - start_.GetX(); - double deltaY = end_.GetY() - start_.GetY(); - double squareDist = deltaX * deltaX + deltaY * deltaY; - double dist = sqrt(squareDist); - char buf[64]; - sprintf(buf, "%0.02f units", dist); - textLayer->SetText(buf); - textLayer->SetColor(0, 223, 21); - - // TODO: for now we simply position the text overlay at the middle - // of the measuring segment - double midX = 0.5*(end_.GetX() + start_.GetX()); - double midY = 0.5*(end_.GetY() + start_.GetY()); - textLayer->SetPosition(midX, midY); - } - } - else - { - if (layersCreated) - { - RemoveFromScene(); - layersCreated = false; - } - } - } } diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureTools.h --- a/Samples/Common/MeasureTools.h Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureTools.h Mon May 13 15:12:56 2019 +0200 @@ -17,6 +17,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ + #pragma once #include @@ -86,40 +87,6 @@ }; typedef boost::shared_ptr MeasureToolPtr; - - class LineMeasureTool : public MeasureTool - { - public: - LineMeasureTool(Scene2D& scene) - : MeasureTool(scene) - , layersCreated(false) - , polylineZIndex_(-1) - , textZIndex_(-1) - { - - } - - ~LineMeasureTool(); - - void SetStart(ScenePoint2D start); - void SetEnd(ScenePoint2D end); - void Set(ScenePoint2D start, ScenePoint2D end); - - private: - PolylineSceneLayer* GetPolylineLayer(); - TextSceneLayer* GetTextLayer(); - virtual void RefreshScene() ORTHANC_OVERRIDE; - void RemoveFromScene(); - - private: - ScenePoint2D start_; - ScenePoint2D end_; - bool layersCreated; - int polylineZIndex_; - int textZIndex_; - }; - - typedef boost::shared_ptr LineMeasureToolPtr; typedef std::vector MeasureToolList; } diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureToolsToolbox.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/MeasureToolsToolbox.cpp Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,229 @@ +/** + * 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 . + **/ + +#include "MeasureToolsToolbox.h" + +#include + +namespace +{ + double g_pi = boost::math::constants::pi(); +} + +namespace OrthancStone +{ + + 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); + } + + 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); + } + + double RadiansToDegrees(double angleRad) + { + static const double factor = 180.0 / g_pi; + return angleRad * factor; + } + + 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 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(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; + } + } + + 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(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 < 0) + retAngle += 2 * g_pi; + while (retAngle >= 2 * 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 +} diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureToolsToolbox.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Samples/Common/MeasureToolsToolbox.h Mon May 13 15:12:56 2019 +0200 @@ -0,0 +1,135 @@ +/** + * 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 . + **/ + +#include +#include + +namespace OrthancStone +{ + + /** + This function will create a square around the center point supplied in + scene coordinates, with a side length given in canvas coordinates. The + square sides are parallel to the canvas boundaries. + */ + void AddSquare(PolylineSceneLayer::Chain& chain, + const Scene2D& scene, + const ScenePoint2D& centerS, + const double& sideLength); + + /** + Creates an arc centered pm c that goes + - from a point r1: + - so that r1 belongs to the p1,c line + - so that the distance from c to r1 equals radius + - to a point r2: + - so that r2 belongs to the p2,c line + - so that the distance from c to r2 equals radius + + if clockwise is true, the arc is drawn from r1 to r2 with increasing + angle values. Otherwise, the angle values decrease. + + Warning: the existing chain content will be wiped out. + */ + + 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 = 63); + + /** + Creates an arc (open curve) with "numSubdivisions" + (N + 1 points) from start angle to end angle. + + if clockwise is true, the arc is drawn from start to end + by increasing the angle values. + + otherwise, the angle value decreases from start to end. + + Warning: the existing chain content will be wiped out. + */ + 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 = 63); + + /** + Creates a circle (closed curve) with "numSubdivisions" + (N points) + + Warning: the existing chain content will be wiped out. + */ + void AddCircle(PolylineSceneLayer::Chain& chain, + const Scene2D& scene, + const ScenePoint2D& centerS, + const double& radiusS, + const int numSubdivisions = 63); + + /** + Adds or subtracts 2*pi as many times as need to shift the specified + angle to a value such as: 0 <= value < 2*pi + */ + double NormalizeAngle(double angle); + + /** + Returns the angle magnitude between the p1,c and p2,c lines. + The returned angle is between 0 and 2*pi + + If the angle is between 0 and pi, this means that the shortest arc + from p1 to p2 is clockwise. + + If the angle is between pi and 2*pi, this means that the shortest arc + from p1 to p2 is COUNTERclockwise. + + */ + double MeasureAngle( + const ScenePoint2D& p1 + , const ScenePoint2D& c + , const ScenePoint2D& p2); + + /** + RadiansToDegrees + */ + double RadiansToDegrees(double angleRad); + + /** + This function will return the coordinates of a point that: + - belongs to the two bisecting lines of the p1 c p2 angle. + - is a distance d from c. + Among the four possible points, the one returned will be the one belonging + to the *smallest* half-plane defined by the [c,p1[ and [c,p2[ half-lines. + */ + void GetPositionOnBisectingLine( + ScenePoint2D& result + , const ScenePoint2D& p1 + , const ScenePoint2D& c + , const ScenePoint2D& p2 + , const double d); +} diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureTrackers.cpp --- a/Samples/Common/MeasureTrackers.cpp Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureTrackers.cpp Mon May 13 15:12:56 2019 +0200 @@ -17,15 +17,15 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **/ - -#include "MeasureTrackers.h" + +#include "MeasureTrackers.h" #include - -using namespace Orthanc; - -namespace OrthancStone -{ - + +using namespace Orthanc; + +namespace OrthancStone +{ + CreateMeasureTracker::CreateMeasureTracker( Scene2D& scene, std::vector& undoStack, @@ -35,20 +35,20 @@ , undoStack_(undoStack) , measureTools_(measureTools) , commitResult_(true) - { - } - - void CreateMeasureTracker::Cancel() - { - commitResult_ = false; - active_ = false; - } + { + } + + void CreateMeasureTracker::Cancel() + { + commitResult_ = false; + active_ = false; + } bool CreateMeasureTracker::IsActive() const { return active_; } - + CreateMeasureTracker::~CreateMeasureTracker() { // if the tracker completes successfully, we add the command @@ -60,8 +60,6 @@ else command_->Undo(); } - +} -} - - + diff -r f939f449482c -r 1e9ed656318e Samples/Common/MeasureTrackers.h --- a/Samples/Common/MeasureTrackers.h Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Common/MeasureTrackers.h Mon May 13 15:12:56 2019 +0200 @@ -45,13 +45,13 @@ ~CreateMeasureTracker(); protected: + CreateMeasureCommandPtr command_; Scene2D& scene_; - CreateMeasureCommandPtr command_; bool active_; private: std::vector& undoStack_; std::vector& measureTools_; bool commitResult_; }; +} -} diff -r f939f449482c -r 1e9ed656318e Samples/Sdl/CMakeLists.txt --- a/Samples/Sdl/CMakeLists.txt Fri May 10 16:15:55 2019 +0200 +++ b/Samples/Sdl/CMakeLists.txt Mon May 13 15:12:56 2019 +0200 @@ -69,6 +69,9 @@ LIST(APPEND TRACKERSAMPLE_SOURCE "../../../SDL-Console/SDL_Console.h") endif() +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/AngleMeasureTool.cpp") +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/AngleMeasureTool.h") + LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateAngleMeasureTracker.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateAngleMeasureTracker.h") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/CreateCircleMeasureTracker.cpp") @@ -90,14 +93,20 @@ LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/IFlexiblePointerTracker.h") +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/LineMeasureTool.cpp") +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/LineMeasureTool.h") + LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureCommands.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureCommands.h") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTools.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTools.h") + +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureToolsToolbox.cpp") +LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureToolsToolbox.h") + LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTrackers.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "../Common/MeasureTrackers.h") - LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSample.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSampleApp.cpp") LIST(APPEND TRACKERSAMPLE_SOURCE "TrackerSampleApp.h") diff -r f939f449482c -r 1e9ed656318e Samples/Sdl/Loader.cpp diff -r f939f449482c -r 1e9ed656318e Samples/Sdl/TrackerSample.cpp