# HG changeset patch # User Sebastien Jodogne # Date 1667390930 -3600 # Node ID 1fa3f484008e574ea1e30086ec4635c5051acd19 # Parent c622219a3388eb3106e03f1196c8f4ad31543bd7 added arrows to AnnotationsSceneLayer::Segment diff -r c622219a3388 -r 1fa3f484008e Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp --- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Tue Nov 01 19:42:27 2022 +0100 +++ b/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Wed Nov 02 13:08:50 2022 +0100 @@ -81,7 +81,7 @@ << " c\tCreate circle annotations" << std::endl << " d\tDelete mode for annotations" << std::endl << " e\tCreate ellipse probe" << std::endl - << " l\tCreate line annotations" << std::endl + << " l\tCreate length annotations" << std::endl << " m\tModification/edit mode, don't create annotation (default)" << std::endl << " p\tCreate pixel probe" << std::endl << " r\tCreate rectangle probe" << std::endl @@ -317,7 +317,7 @@ case SDLK_l: #if SAMPLE_USE_ANNOTATIONS_LAYER == 1 - annotations.SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Segment); + annotations.SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Length); #else if (activeTool == ActiveTool_Line) { diff -r c622219a3388 -r 1fa3f484008e Applications/StoneWebViewer/WebApplication/app.js --- a/Applications/StoneWebViewer/WebApplication/app.js Tue Nov 01 19:42:27 2022 +0100 +++ b/Applications/StoneWebViewer/WebApplication/app.js Wed Nov 02 13:08:50 2022 +0100 @@ -42,7 +42,7 @@ var MOUSE_TOOL_ZOOM = 2; var MOUSE_TOOL_PAN = 3; var MOUSE_TOOL_CROSSHAIR = 4; -var MOUSE_TOOL_CREATE_SEGMENT = 5; +var MOUSE_TOOL_CREATE_LENGTH = 5; var MOUSE_TOOL_CREATE_ANGLE = 6; var MOUSE_TOOL_CREATE_CIRCLE = 7; var MOUSE_TOOL_REMOVE_MEASURE = 8; diff -r c622219a3388 -r 1fa3f484008e Applications/StoneWebViewer/WebApplication/index.html --- a/Applications/StoneWebViewer/WebApplication/index.html Tue Nov 01 19:42:27 2022 +0100 +++ b/Applications/StoneWebViewer/WebApplication/index.html Wed Nov 02 13:08:50 2022 +0100 @@ -530,8 +530,8 @@
diff -r c622219a3388 -r 1fa3f484008e Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp --- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Tue Nov 01 19:42:27 2022 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Nov 02 13:08:50 2022 +0100 @@ -145,7 +145,7 @@ WebViewerAction_CreateAngle, WebViewerAction_CreateCircle, - WebViewerAction_CreateSegment, + WebViewerAction_CreateLength, WebViewerAction_RemoveMeasure, WebViewerAction_CreatePixelProbe, // New in 2.4 WebViewerAction_CreateEllipseProbe, // New in 2.4 @@ -178,7 +178,7 @@ case WebViewerAction_Crosshair: case WebViewerAction_CreateAngle: case WebViewerAction_CreateCircle: - case WebViewerAction_CreateSegment: + case WebViewerAction_CreateLength: case WebViewerAction_RemoveMeasure: case WebViewerAction_CreatePixelProbe: case WebViewerAction_CreateEllipseProbe: @@ -3231,8 +3231,8 @@ viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Circle); break; - case WebViewerAction_CreateSegment: - viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Segment); + case WebViewerAction_CreateLength: + viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Length); break; case WebViewerAction_RemoveMeasure: diff -r c622219a3388 -r 1fa3f484008e OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp --- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Tue Nov 01 19:42:27 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Nov 02 13:08:50 2022 +0100 @@ -34,11 +34,15 @@ #include #include +static const double PI = boost::math::constants::pi(); + static const double HANDLE_SIZE = 10.0; -static const double PI = boost::math::constants::pi(); +static const double ARROW_LENGTH = 1.5 * HANDLE_SIZE; +static const double ARROW_ANGLE = 20.0 * PI / 180.0; static const char* const KEY_ANNOTATIONS = "annotations"; static const char* const KEY_TYPE = "type"; +static const char* const KEY_TEXT = "text"; static const char* const KEY_X = "x"; static const char* const KEY_Y = "y"; static const char* const KEY_X1 = "x1"; @@ -51,12 +55,13 @@ static const char* const VALUE_ANGLE = "angle"; static const char* const VALUE_CIRCLE = "circle"; -static const char* const VALUE_SEGMENT = "segment"; +static const char* const VALUE_LENGTH = "length"; static const char* const VALUE_MILLIMETERS = "millimeters"; static const char* const VALUE_PIXELS = "pixels"; static const char* const VALUE_PIXEL_PROBE = "pixel-probe"; static const char* const VALUE_RECTANGLE_PROBE = "rectangle-probe"; static const char* const VALUE_ELLIPSE_PROBE = "ellipse-probe"; +static const char* const VALUE_TEXT_ANNOTATION = "text"; #if 0 static OrthancStone::Color COLOR_PRIMITIVES(192, 192, 192); @@ -301,9 +306,7 @@ void SetCenter(double x, double y) { - SetModified(true); - center_ = ScenePoint2D(x, y); - delta_ = ScenePoint2D(0, 0); + SetCenter(ScenePoint2D(x, y)); } ScenePoint2D GetCenter() const @@ -394,6 +397,8 @@ ScenePoint2D p1_; ScenePoint2D p2_; ScenePoint2D delta_; + bool hasStartArrow_; + bool hasEndArrow_; public: Segment(Annotation& parentAnnotation, @@ -402,7 +407,9 @@ GeometricPrimitive(parentAnnotation, 1), // Can only be selected if no handle matches p1_(p1), p2_(p2), - delta_(0, 0) + delta_(0, 0), + hasStartArrow_(false), + hasEndArrow_(false) { } @@ -414,7 +421,9 @@ GeometricPrimitive(parentAnnotation, 1), // Can only be selected if no handle matches p1_(x1, y1), p2_(x2, y2), - delta_(0, 0) + delta_(0, 0), + hasStartArrow_(false), + hasEndArrow_(false) { } @@ -448,6 +457,28 @@ return p2_ + delta_; } + void SetStartArrow(bool enabled) + { + SetModified(true); + hasStartArrow_ = enabled; + } + + bool HasStartArrow() const + { + return hasStartArrow_; + } + + void SetEndArrow(bool enabled) + { + SetModified(true); + hasEndArrow_ = enabled; + } + + bool HasEndArrow() const + { + return hasEndArrow_; + } + virtual bool IsHit(const ScenePoint2D& p, const Scene2D& scene) const ORTHANC_OVERRIDE { @@ -459,7 +490,38 @@ virtual void RenderPolylineLayer(PolylineSceneLayer& polyline, const Scene2D& scene) ORTHANC_OVERRIDE { - polyline.AddSegment(p1_ + delta_, p2_ + delta_, GetActiveColor()); + const Color color = GetActiveColor(); + const ScenePoint2D a(p1_ + delta_); + const ScenePoint2D b(p2_ + delta_); + + polyline.AddSegment(a, b, color); + + if (hasStartArrow_ || + hasEndArrow_) + { + const double length = ARROW_LENGTH / scene.GetSceneToCanvasTransform().ComputeZoom(); + const double angle = atan2(b.GetY() - a.GetY(), b.GetX() - a.GetX()); + + if (hasStartArrow_) + { + polyline.AddSegment(a, a + ScenePoint2D( + length * cos(angle + ARROW_ANGLE), + length * sin(angle + ARROW_ANGLE)), color); + polyline.AddSegment(a, a + ScenePoint2D( + length * cos(angle - ARROW_ANGLE), + length * sin(angle - ARROW_ANGLE)), color); + } + + if (hasEndArrow_) + { + polyline.AddSegment(b, b + ScenePoint2D( + length * cos(angle + ARROW_ANGLE + PI), + length * sin(angle + ARROW_ANGLE + PI)), color); + polyline.AddSegment(b, b + ScenePoint2D( + length * cos(angle - ARROW_ANGLE + PI), + length * sin(angle - ARROW_ANGLE + PI)), color); + } + } } virtual void RenderOtherLayers(MacroSceneLayer& macro, @@ -996,7 +1058,7 @@ }; - class AnnotationsSceneLayer::SegmentAnnotation : public Annotation + class AnnotationsSceneLayer::LengthAnnotation : public Annotation { private: bool showLabel_; @@ -1054,11 +1116,11 @@ } public: - SegmentAnnotation(AnnotationsSceneLayer& that, - Units units, - bool showLabel, - const ScenePoint2D& p1, - const ScenePoint2D& p2) : + LengthAnnotation(AnnotationsSceneLayer& that, + Units units, + bool showLabel, + const ScenePoint2D& p1, + const ScenePoint2D& p2) : Annotation(that, units), showLabel_(showLabel), handle1_(AddTypedPrimitive(new Handle(*this, Handle::Shape_Square, p1))), @@ -1118,7 +1180,7 @@ virtual void Serialize(Json::Value& target) ORTHANC_OVERRIDE { target = Json::objectValue; - target[KEY_TYPE] = VALUE_SEGMENT; + target[KEY_TYPE] = VALUE_LENGTH; target[KEY_X1] = handle1_.GetCenter().GetX(); target[KEY_Y1] = handle1_.GetCenter().GetY(); target[KEY_X2] = handle2_.GetCenter().GetX(); @@ -1138,13 +1200,13 @@ source[KEY_X2].isNumeric() && source[KEY_Y2].isNumeric()) { - new SegmentAnnotation(target, units, true, - ScenePoint2D(source[KEY_X1].asDouble(), source[KEY_Y1].asDouble()), - ScenePoint2D(source[KEY_X2].asDouble(), source[KEY_Y2].asDouble())); + new LengthAnnotation(target, units, true, + ScenePoint2D(source[KEY_X1].asDouble(), source[KEY_Y1].asDouble()), + ScenePoint2D(source[KEY_X2].asDouble(), source[KEY_Y2].asDouble())); } else { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot unserialize an segment annotation"); + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot unserialize a length annotation"); } } }; @@ -2179,7 +2241,7 @@ { private: AnnotationsSceneLayer& that_; - SegmentAnnotation* segment_; + LengthAnnotation* length_; AngleAnnotation* angle_; AffineTransform2D canvasToScene_; @@ -2189,20 +2251,20 @@ const ScenePoint2D& sceneClick, const AffineTransform2D& canvasToScene) : that_(that), - segment_(NULL), + length_(NULL), angle_(NULL), canvasToScene_(canvasToScene) { - segment_ = new SegmentAnnotation(that, units, false /* no length label */, sceneClick, sceneClick); + length_ = new LengthAnnotation(that, units, false /* no length label */, sceneClick, sceneClick); } virtual void PointerMove(const PointerEvent& event, const Scene2D& scene) ORTHANC_OVERRIDE { - if (segment_ != NULL) + if (length_ != NULL) { - segment_->GetHandle(1).SetCenter(event.GetMainPosition().Apply(canvasToScene_)); - segment_->SignalMove(segment_->GetHandle(1), scene); + length_->GetHandle(1).SetCenter(event.GetMainPosition().Apply(canvasToScene_)); + length_->SignalMove(length_->GetHandle(1), scene); that_.BroadcastMessage(AnnotationChangedMessage(that_)); } @@ -2217,16 +2279,16 @@ virtual void PointerUp(const PointerEvent& event, const Scene2D& scene) ORTHANC_OVERRIDE { - if (segment_ != NULL) + if (length_ != NULL) { // End of first step: The first segment is available, now create the angle - angle_ = new AngleAnnotation(that_, segment_->GetUnits(), segment_->GetHandle(0).GetCenter(), - segment_->GetHandle(1).GetCenter(), - segment_->GetHandle(1).GetCenter()); + angle_ = new AngleAnnotation(that_, length_->GetUnits(), length_->GetHandle(0).GetCenter(), + length_->GetHandle(1).GetCenter(), + length_->GetHandle(1).GetCenter()); - that_.DeleteAnnotation(segment_); - segment_ = NULL; + that_.DeleteAnnotation(length_); + length_ = NULL; that_.BroadcastMessage(AnnotationChangedMessage(that_)); } @@ -2245,16 +2307,16 @@ virtual bool IsAlive() const ORTHANC_OVERRIDE { - return (segment_ != NULL || + return (length_ != NULL || angle_ != NULL); } virtual void Cancel(const Scene2D& scene) ORTHANC_OVERRIDE { - if (segment_ != NULL) + if (length_ != NULL) { - that_.DeleteAnnotation(segment_); - segment_ = NULL; + that_.DeleteAnnotation(length_); + length_ = NULL; } if (angle_ != NULL) @@ -2411,10 +2473,10 @@ } - void AnnotationsSceneLayer::AddSegmentAnnotation(const ScenePoint2D& p1, - const ScenePoint2D& p2) + void AnnotationsSceneLayer::AddLengthAnnotation(const ScenePoint2D& p1, + const ScenePoint2D& p2) { - annotations_.insert(new SegmentAnnotation(*this, units_, true /* show label */, p1, p2)); + annotations_.insert(new LengthAnnotation(*this, units_, true /* show label */, p1, p2)); } @@ -2578,9 +2640,9 @@ { switch (activeTool_) { - case Tool_Segment: + case Tool_Length: { - Annotation* annotation = new SegmentAnnotation(*this, units_, true /* show label */, s, s); + Annotation* annotation = new LengthAnnotation(*this, units_, true /* show label */, s, s); return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); } @@ -2608,6 +2670,12 @@ return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); } + /*case Tool_TextAnnotation: + { + Annotation* annotation = new TextAnnotation(*this, units_, true show label, s, s); + return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); + }*/ + default: return NULL; } @@ -2697,9 +2765,9 @@ { CircleAnnotation::Unserialize(*this, units_, annotations[i]); } - else if (type == VALUE_SEGMENT) + else if (type == VALUE_LENGTH) { - SegmentAnnotation::Unserialize(*this, units_, annotations[i]); + LengthAnnotation::Unserialize(*this, units_, annotations[i]); } else if (type == VALUE_PIXEL_PROBE) { @@ -2713,6 +2781,10 @@ { EllipseProbeAnnotation::Unserialize(*this, units_, annotations[i]); } + /*else if (type == VALUE_TEXT_ANNOTATION) + { + TextAnnotation::Unserialize(*this, units_, annotations[i]); + }*/ else { LOG(ERROR) << "Cannot unserialize unknown type of annotation: " << type; diff -r c622219a3388 -r 1fa3f484008e OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h --- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Tue Nov 01 19:42:27 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Nov 02 13:08:50 2022 +0100 @@ -38,7 +38,7 @@ { Tool_Edit, Tool_None, - Tool_Segment, + Tool_Length, Tool_Angle, Tool_Circle, Tool_Remove, @@ -61,10 +61,12 @@ class ProbingAnnotation; class PixelProbeAnnotation; class SegmentAnnotation; + class LengthAnnotation; class AngleAnnotation; class CircleAnnotation; class RectangleProbeAnnotation; class EllipseProbeAnnotation; + class TextAnnotation; class EditPrimitiveTracker; class CreateTwoHandlesTracker; @@ -120,8 +122,8 @@ return units_; } - void AddSegmentAnnotation(const ScenePoint2D& p1, - const ScenePoint2D& p2); + void AddLengthAnnotation(const ScenePoint2D& p1, + const ScenePoint2D& p2); void AddCircleAnnotation(const ScenePoint2D& p1, const ScenePoint2D& p2);