Mercurial > hg > orthanc-stone
changeset 1980:0aac8f552d89
added pixel probe to the Stone Web viewer toolbar
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sun, 30 Oct 2022 10:26:32 +0100 |
parents | b31e494e34c5 |
children | c074c75cf416 |
files | Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp |
diffstat | 4 files changed, 110 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js Sat Oct 29 17:10:21 2022 +0200 +++ b/Applications/StoneWebViewer/WebApplication/app.js Sun Oct 30 10:26:32 2022 +0100 @@ -46,6 +46,7 @@ var MOUSE_TOOL_CREATE_ANGLE = 6; var MOUSE_TOOL_CREATE_CIRCLE = 7; var MOUSE_TOOL_REMOVE_MEASURE = 8; +var MOUSE_TOOL_CREATE_PIXEL_PROBE = 9; function getParameterFromUrl(key) {
--- a/Applications/StoneWebViewer/WebApplication/index.html Sat Oct 29 17:10:21 2022 +0200 +++ b/Applications/StoneWebViewer/WebApplication/index.html Sun Oct 30 10:26:32 2022 +0100 @@ -528,6 +528,15 @@ <div class="ng-scope inline-object"> <button class="wvButton--underline text-center" + v-bind:class="{ 'active' : mouseTool == MOUSE_TOOL_CREATE_PIXEL_PROBE }" + v-on:click="SetLeftMouseButtonAction(MOUSE_TOOL_CREATE_PIXEL_PROBE, stone.WebViewerAction.CREATE_PIXEL_PROBE)" + data-toggle="tooltip" data-title="Pixel probe"> + <i class="far fa-dot-circle"></i> + </button> + </div> + + <div class="ng-scope inline-object"> + <button class="wvButton--underline text-center" v-bind:class="{ 'active' : mouseTool == MOUSE_TOOL_REMOVE_MEASURE }" v-on:click="SetLeftMouseButtonAction(MOUSE_TOOL_REMOVE_MEASURE, stone.WebViewerAction.REMOVE_MEASURE)" data-toggle="tooltip" data-title="Delete measurement">
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sat Oct 29 17:10:21 2022 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sun Oct 30 10:26:32 2022 +0100 @@ -170,6 +170,7 @@ case WebViewerAction_CreateCircle: case WebViewerAction_CreateSegment: case WebViewerAction_RemoveMeasure: + case WebViewerAction_CreatePixelProbe: return OrthancStone::MouseAction_None; default:
--- a/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Sat Oct 29 17:10:21 2022 +0200 +++ b/OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.cpp Sun Oct 30 10:26:32 2022 +0100 @@ -234,14 +234,72 @@ class AnnotationsSceneLayer::Handle : public GeometricPrimitive { + public: + enum Shape { + Shape_Square, + Shape_CrossedSquare + }; + private: + Shape shape_; ScenePoint2D center_; ScenePoint2D delta_; + void AddChain(PolylineSceneLayer& polyline, + const PolylineSceneLayer::Chain& chain) const + { + if (IsHover()) + { + polyline.AddChain(chain, true /* closed */, GetHoverColor()); + } + else + { + polyline.AddChain(chain, true /* closed */, GetColor()); + } + } + + void AddRectangle(PolylineSceneLayer& polyline, + double x1, + double y1, + double x2, + double y2) + { + PolylineSceneLayer::Chain chain; + chain.resize(4); + chain[0] = ScenePoint2D(x1, y1); + chain[1] = ScenePoint2D(x2, y1); + chain[2] = ScenePoint2D(x2, y2); + chain[3] = ScenePoint2D(x1, y2); + AddChain(polyline, chain); + } + + void AddCross(PolylineSceneLayer& polyline, + double x1, + double y1, + double x2, + double y2) + { + const double halfX = (x1 + x2) / 2.0; + const double halfY = (y1 + y2) / 2.0; + + PolylineSceneLayer::Chain chain; + chain.resize(2); + + chain[0] = ScenePoint2D(x1, halfY); + chain[1] = ScenePoint2D(x2, halfY); + AddChain(polyline, chain); + + chain[0] = ScenePoint2D(halfX, y1); + chain[1] = ScenePoint2D(halfX, y2); + AddChain(polyline, chain); + } + public: explicit Handle(Annotation& parentAnnotation, + Shape shape, const ScenePoint2D& center) : GeometricPrimitive(parentAnnotation, 0), // Highest priority + shape_(shape), center_(center), delta_(0, 0) { @@ -272,8 +330,16 @@ double dx = (center_.GetX() + delta_.GetX() - p.GetX()) * zoom; double dy = (center_.GetY() + delta_.GetY() - p.GetY()) * zoom; - return (std::abs(dx) <= HANDLE_SIZE / 2.0 && - std::abs(dy) <= HANDLE_SIZE / 2.0); + switch (shape_) + { + case Shape_Square: + case Shape_CrossedSquare: + return (std::abs(dx) <= HANDLE_SIZE / 2.0 && + std::abs(dy) <= HANDLE_SIZE / 2.0); + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } } virtual void RenderPolylineLayer(PolylineSceneLayer& polyline, @@ -287,20 +353,19 @@ double x2 = center_.GetX() + delta_.GetX() + (HANDLE_SIZE / 2.0) / zoom; double y2 = center_.GetY() + delta_.GetY() + (HANDLE_SIZE / 2.0) / zoom; - PolylineSceneLayer::Chain chain; - chain.reserve(4); - chain.push_back(ScenePoint2D(x1, y1)); - chain.push_back(ScenePoint2D(x2, y1)); - chain.push_back(ScenePoint2D(x2, y2)); - chain.push_back(ScenePoint2D(x1, y2)); + switch (shape_) + { + case Shape_Square: + AddRectangle(polyline, x1, y1, x2, y2); + break; + + case Shape_CrossedSquare: + AddRectangle(polyline, x1, y1, x2, y2); + AddCross(polyline, x1, y1, x2, y2); + break; - if (IsHover()) - { - polyline.AddChain(chain, true /* closed */, GetHoverColor()); - } - else - { - polyline.AddChain(chain, true /* closed */, GetColor()); + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } } @@ -377,9 +442,9 @@ const Scene2D& scene) ORTHANC_OVERRIDE { PolylineSceneLayer::Chain chain; - chain.reserve(2); - chain.push_back(p1_ + delta_); - chain.push_back(p2_ + delta_); + chain.resize(2); + chain[0] = p1_ + delta_; + chain[1] = p2_ + delta_; if (IsHover()) { @@ -480,13 +545,13 @@ double increment = 2.0 * PI / static_cast<double>(NUM_SEGMENTS - 1); PolylineSceneLayer::Chain chain; - chain.reserve(NUM_SEGMENTS); + chain.resize(NUM_SEGMENTS); double theta = 0; for (unsigned int i = 0; i < NUM_SEGMENTS; i++) { - chain.push_back(ScenePoint2D(delta_.GetX() + middle.GetX() + radius * cos(theta), - delta_.GetY() + middle.GetY() + radius * sin(theta))); + chain[i] = ScenePoint2D(delta_.GetX() + middle.GetX() + radius * cos(theta), + delta_.GetY() + middle.GetY() + radius * sin(theta)); theta += increment; } @@ -617,13 +682,13 @@ double increment = fullAngle / static_cast<double>(NUM_SEGMENTS - 1); PolylineSceneLayer::Chain chain; - chain.reserve(NUM_SEGMENTS); + chain.resize(NUM_SEGMENTS); double theta = startAngle; for (unsigned int i = 0; i < NUM_SEGMENTS; i++) { - chain.push_back(ScenePoint2D(middle_.GetX() + radius * cos(theta), - middle_.GetY() + radius * sin(theta))); + chain[i] = ScenePoint2D(middle_.GetX() + radius * cos(theta), + middle_.GetY() + radius * sin(theta)); theta += increment; } @@ -881,8 +946,8 @@ const ScenePoint2D& p2) : Annotation(that, units), showLabel_(showLabel), - handle1_(AddTypedPrimitive<Handle>(new Handle(*this, p1))), - handle2_(AddTypedPrimitive<Handle>(new Handle(*this, p2))), + handle1_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p1))), + handle2_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p2))), segment_(AddTypedPrimitive<Segment>(new Segment(*this, p1, p2))), label_(AddTypedPrimitive<Text>(new Text(that, *this))) { @@ -1035,7 +1100,7 @@ switch (image.GetFormat()) { case Orthanc::PixelFormat_Float32: - sprintf(buf, "%.01f\n", Orthanc::ImageTraits<Orthanc::PixelFormat_Float32>::GetFloatPixel( + sprintf(buf, "(%d,%d): %.01f", x, y, Orthanc::ImageTraits<Orthanc::PixelFormat_Float32>::GetFloatPixel( image, static_cast<unsigned int>(x), static_cast<unsigned int>(y))); break; @@ -1044,7 +1109,7 @@ Orthanc::PixelTraits<Orthanc::PixelFormat_RGB24>::PixelType pixel; Orthanc::ImageTraits<Orthanc::PixelFormat_RGB24>::GetPixel( pixel, image, static_cast<unsigned int>(x), static_cast<unsigned int>(y)); - sprintf(buf, "(%d,%d,%d)\n", pixel.red_, pixel.green_, pixel.blue_); + sprintf(buf, "(%d,%d): (%d,%d,%d)", x, y, pixel.red_, pixel.green_, pixel.blue_); break; } @@ -1067,7 +1132,7 @@ const ScenePoint2D& p, int probedLayer) : ProbingAnnotation(that, units, probedLayer), - handle_(AddTypedPrimitive<Handle>(new Handle(*this, p))), + handle_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_CrossedSquare, p))), label_(AddTypedPrimitive<Text>(new Text(that, *this))) { TextSceneLayer content; @@ -1170,9 +1235,9 @@ const ScenePoint2D& middle, const ScenePoint2D& end) : Annotation(that, units), - startHandle_(AddTypedPrimitive<Handle>(new Handle(*this, start))), - middleHandle_(AddTypedPrimitive<Handle>(new Handle(*this, middle))), - endHandle_(AddTypedPrimitive<Handle>(new Handle(*this, end))), + startHandle_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, start))), + middleHandle_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, middle))), + endHandle_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, end))), segment1_(AddTypedPrimitive<Segment>(new Segment(*this, start, middle))), segment2_(AddTypedPrimitive<Segment>(new Segment(*this, middle, end))), arc_(AddTypedPrimitive<Arc>(new Arc(*this, start, middle, end))), @@ -1340,8 +1405,8 @@ const ScenePoint2D& p1, const ScenePoint2D& p2) : Annotation(that, units), - handle1_(AddTypedPrimitive<Handle>(new Handle(*this, p1))), - handle2_(AddTypedPrimitive<Handle>(new Handle(*this, p2))), + handle1_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p1))), + handle2_(AddTypedPrimitive<Handle>(new Handle(*this, Handle::Shape_Square, p2))), segment_(AddTypedPrimitive<Segment>(new Segment(*this, p1, p2))), circle_(AddTypedPrimitive<Circle>(new Circle(*this, p1, p2))), label_(AddTypedPrimitive<Text>(new Text(that, *this)))