Mercurial > hg > orthanc-stone
changeset 2001:e943a84da9ac
creation of text annotations
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 02 Nov 2022 14:56:35 +0100 |
parents | 3e9ced39cd1b |
children | 1bb0a9716876 |
files | Applications/StoneWebViewer/NEWS Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h |
diffstat | 6 files changed, 182 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/NEWS Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/NEWS Wed Nov 02 14:56:35 2022 +0100 @@ -2,6 +2,7 @@ =============================== * New types of annotations: + - Text annotation - Pixel probe - Rectangle probe - Ellipse probe
--- a/Applications/StoneWebViewer/WebApplication/app.js Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebApplication/app.js Wed Nov 02 14:56:35 2022 +0100 @@ -1188,6 +1188,15 @@ window.addEventListener('StoneAnnotationRemoved', function() { // Ignore }); + + window.addEventListener('TextAnnotationRequired', function(args) { + var label = prompt('Enter your annotation:', ''); + if (label !== null) { + stone.AddTextAnnotation(args.detail.canvasId, label, + args.detail.pointedX, args.detail.pointedY, + args.detail.labelX, args.detail.labelY); + } + }); } });
--- a/Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/ParseWebAssemblyExports.py Wed Nov 02 14:56:35 2022 +0100 @@ -174,6 +174,8 @@ arg['type'] = "'int'" elif argType == 'const char *': arg['type'] = "'string'" + elif argType == 'double': + arg['type'] = "'double'" else: raise Exception('Unknown type for argument "%s" in function "%s()": %s' % (child.displayname, node.spelling, argType))
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Nov 02 13:52:14 2022 +0100 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Wed Nov 02 14:56:35 2022 +0100 @@ -1597,6 +1597,10 @@ virtual void SignalStoneAnnotationAdded(const ViewerViewport& viewport) = 0; virtual void SignalStoneAnnotationRemoved(const ViewerViewport& viewport) = 0; + + virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) = 0; }; private: @@ -2692,6 +2696,14 @@ } } + void Handle(const OrthancStone::AnnotationsSceneLayer::TextAnnotationRequiredMessage& message) + { + if (observer_.get() != NULL) + { + observer_->SignalStoneTextAnnotationRequired(*this, message.GetPointedPosition(), message.GetLabelPosition()); + } + } + public: virtual ~ViewerViewport() { @@ -2732,6 +2744,9 @@ viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage>( *viewport->stoneAnnotations_, &ViewerViewport::Handle); + + viewport->Register<OrthancStone::AnnotationsSceneLayer::TextAnnotationRequiredMessage>( + *viewport->stoneAnnotations_, &ViewerViewport::Handle); } { @@ -3435,6 +3450,14 @@ Redraw(); } } + + void AddTextAnnotation(const std::string& label, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) + { + stoneAnnotations_->AddTextAnnotation(label, pointedPosition, labelPosition); + Redraw(); + } }; @@ -3695,6 +3718,27 @@ }, viewport.GetCanvasId().c_str()); } + + virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, + const OrthancStone::ScenePoint2D& pointedPosition, + const OrthancStone::ScenePoint2D& labelPosition) ORTHANC_OVERRIDE + { + EM_ASM({ + const customEvent = document.createEvent("CustomEvent"); + customEvent.initCustomEvent("TextAnnotationRequired", false, false, + { "canvasId" : UTF8ToString($0), + "pointedX" : $1, + "pointedY" : $2, + "labelX" : $3, + "labelY" : $4 }); + window.dispatchEvent(customEvent); + }, + viewport.GetCanvasId().c_str(), + pointedPosition.GetX(), + pointedPosition.GetY(), + labelPosition.GetX(), + labelPosition.GetY() ); + } }; @@ -4497,4 +4541,21 @@ EXTERN_CATCH_EXCEPTIONS; return false; } + + + EMSCRIPTEN_KEEPALIVE + void AddTextAnnotation(const char* canvas, + const char* label, + double pointedX, + double pointedY, + double labelX, + double labelY) + { + try + { + GetViewport(canvas)->AddTextAnnotation(label, OrthancStone::ScenePoint2D(pointedX, pointedY), + OrthancStone::ScenePoint2D(labelX, labelY)); + } + EXTERN_CATCH_EXCEPTIONS; + } }
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Nov 02 13:52:14 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Wed Nov 02 14:56:35 2022 +0100 @@ -1272,14 +1272,25 @@ public: TextAnnotation(AnnotationsSceneLayer& that, const std::string& label, - const ScenePoint2D& p1, - const ScenePoint2D& p2) : - SegmentAnnotation(that, Handle::Shape_Invisible, p1, Handle::Shape_Square, p2) + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition) : + SegmentAnnotation(that, Handle::Shape_Invisible, pointedPosition /* p1 */, + Handle::Shape_Square, labelPosition /* p2 */) { SetStartArrow(true); UpdateLabel(label); } + ScenePoint2D GetPointedPosition() const + { + return GetHandle1().GetCenter(); + } + + ScenePoint2D GetLabelPosition() const + { + return GetHandle2().GetCenter(); + } + void UpdateLabel(const std::string& label) { TextSceneLayer content; @@ -2325,6 +2336,25 @@ AnnotationsSceneLayer& layer_; Annotation* annotation_; AffineTransform2D canvasToScene_; + + protected: + AnnotationsSceneLayer& GetLayer() const + { + return layer_; + } + + const Annotation& GetAnnotation() const + { + if (IsAlive()) + { + assert(annotation_ != NULL); + return *annotation_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } public: CreateTwoHandlesTracker(Annotation& annotation, @@ -2506,6 +2536,35 @@ }; + class AnnotationsSceneLayer::CreateTextAnnotationTracker : public CreateTwoHandlesTracker + { + public: + CreateTextAnnotationTracker(AnnotationsSceneLayer& that, + const std::string& label, + const ScenePoint2D& position, + const AffineTransform2D& canvasToScene) : + CreateTwoHandlesTracker(*new TextAnnotation(that, label, position, position), canvasToScene) + { + } + + virtual void PointerUp(const PointerEvent& event, + const Scene2D& scene) ORTHANC_OVERRIDE + { + std::unique_ptr<TextAnnotationRequiredMessage> request; + + { + const TextAnnotation& annotation = dynamic_cast<const TextAnnotation&>(GetAnnotation()); + request.reset(new TextAnnotationRequiredMessage(GetLayer(), annotation.GetPointedPosition(), annotation.GetLabelPosition())); + } + + Cancel(scene); // Warning: "annotation_" is now invalid! + + GetLayer().BroadcastMessage(AnnotationChangedMessage(GetLayer())); + GetLayer().BroadcastMessage(*request); + } + }; + + // Dummy tracker that is only used for deletion, in order to warn // the caller that the mouse action was taken into consideration class AnnotationsSceneLayer::RemoveTracker : public IFlexiblePointerTracker @@ -2616,6 +2675,7 @@ const ScenePoint2D& p2) { annotations_.insert(new LengthAnnotation(*this, units_, true /* show label */, p1, p2)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2623,6 +2683,7 @@ const ScenePoint2D& p2) { annotations_.insert(new CircleAnnotation(*this, units_, p1, p2)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2631,6 +2692,7 @@ const ScenePoint2D& p3) { annotations_.insert(new AngleAnnotation(*this, p1, p2, p3)); + BroadcastMessage(AnnotationChangedMessage(*this)); } @@ -2810,10 +2872,7 @@ } case Tool_TextAnnotation: - { - Annotation* annotation = new TextAnnotation(*this, "" /* empty label */, s, s); - return new CreateTwoHandlesTracker(*annotation, scene.GetCanvasToSceneTransform()); - } + return new CreateTextAnnotationTracker(*this, "" /* empty label */, s, scene.GetCanvasToSceneTransform()); default: return NULL; @@ -2930,4 +2989,13 @@ } } } + + + void AnnotationsSceneLayer::AddTextAnnotation(const std::string& label, + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition) + { + annotations_.insert(new TextAnnotation(*this, label, pointedPosition, labelPosition)); + BroadcastMessage(AnnotationChangedMessage(*this)); + } }
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Nov 02 13:52:14 2022 +0100 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h Wed Nov 02 14:56:35 2022 +0100 @@ -34,6 +34,35 @@ ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, AnnotationRemovedMessage, AnnotationsSceneLayer); ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, AnnotationChangedMessage, AnnotationsSceneLayer); + class TextAnnotationRequiredMessage : public OriginMessage<AnnotationsSceneLayer> + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + ScenePoint2D pointedPosition_; + ScenePoint2D labelPosition_; + + public: + TextAnnotationRequiredMessage(const AnnotationsSceneLayer& origin, + ScenePoint2D pointedPosition, + ScenePoint2D labelPosition) : + OriginMessage(origin), + pointedPosition_(pointedPosition), + labelPosition_(labelPosition) + { + } + + const ScenePoint2D& GetPointedPosition() const + { + return pointedPosition_; + } + + const ScenePoint2D& GetLabelPosition() const + { + return labelPosition_; + } + }; + enum Tool { Tool_Edit, @@ -73,6 +102,7 @@ class CreateAngleTracker; class CreatePixelProbeTracker; class RemoveTracker; + class CreateTextAnnotationTracker; typedef std::set<GeometricPrimitive*> GeometricPrimitives; typedef std::set<Annotation*> Annotations; @@ -155,5 +185,9 @@ { return probedLayer_; } + + void AddTextAnnotation(const std::string& label, + const ScenePoint2D& pointedPosition, + const ScenePoint2D& labelPosition); }; }