Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 2003:963f28eb40cb deep-learning
integration default->deep-learning
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 02 Nov 2022 15:14:56 +0100 |
parents | 2034ae383cfd e943a84da9ac |
children | 37d6805b80ee |
comparison
equal
deleted
inserted
replaced
1964:2034ae383cfd | 2003:963f28eb40cb |
---|---|
94 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyCairoViewport.h" | 94 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyCairoViewport.h" |
95 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyLoadersContext.h" | 95 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebAssemblyLoadersContext.h" |
96 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebGLViewport.h" | 96 #include "../../../OrthancStone/Sources/Platforms/WebAssembly/WebGLViewport.h" |
97 | 97 |
98 | 98 |
99 #include <algorithm> | |
100 #include <boost/make_shared.hpp> | |
101 #include <boost/math/constants/constants.hpp> | |
99 #include <boost/math/special_functions/round.hpp> | 102 #include <boost/math/special_functions/round.hpp> |
100 #include <boost/make_shared.hpp> | |
101 #include <stdio.h> | 103 #include <stdio.h> |
102 #include <algorithm> | 104 |
105 static const double PI = boost::math::constants::pi<double>(); | |
103 | 106 |
104 #if !defined(STONE_WEB_VIEWER_EXPORT) | 107 #if !defined(STONE_WEB_VIEWER_EXPORT) |
105 // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm | 108 // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm |
106 # define STONE_WEB_VIEWER_EXPORT | 109 # define STONE_WEB_VIEWER_EXPORT |
107 #endif | 110 #endif |
136 WebViewerAction_Windowing, | 139 WebViewerAction_Windowing, |
137 WebViewerAction_Zoom, | 140 WebViewerAction_Zoom, |
138 WebViewerAction_Pan, | 141 WebViewerAction_Pan, |
139 WebViewerAction_Rotate, | 142 WebViewerAction_Rotate, |
140 WebViewerAction_Crosshair, | 143 WebViewerAction_Crosshair, |
144 WebViewerAction_MagnifyingGlass, // New in 2.4 | |
141 | 145 |
142 WebViewerAction_CreateAngle, | 146 WebViewerAction_CreateAngle, |
143 WebViewerAction_CreateCircle, | 147 WebViewerAction_CreateCircle, |
144 WebViewerAction_CreateSegment, | 148 WebViewerAction_CreateLength, |
145 WebViewerAction_RemoveMeasure | 149 WebViewerAction_RemoveMeasure, |
150 WebViewerAction_CreatePixelProbe, // New in 2.4 | |
151 WebViewerAction_CreateEllipseProbe, // New in 2.4 | |
152 WebViewerAction_CreateRectangleProbe, // New in 2.4 | |
153 WebViewerAction_CreateTextAnnotation // New in 2.4 | |
146 }; | 154 }; |
147 | 155 |
148 | 156 |
149 | 157 |
150 static OrthancStone::MouseAction ConvertWebViewerAction(int action) | 158 static OrthancStone::MouseAction ConvertWebViewerAction(int action) |
161 return OrthancStone::MouseAction_Pan; | 169 return OrthancStone::MouseAction_Pan; |
162 | 170 |
163 case WebViewerAction_Rotate: | 171 case WebViewerAction_Rotate: |
164 return OrthancStone::MouseAction_Rotate; | 172 return OrthancStone::MouseAction_Rotate; |
165 | 173 |
174 case WebViewerAction_MagnifyingGlass: | |
175 return OrthancStone::MouseAction_MagnifyingGlass; | |
176 | |
166 case WebViewerAction_None: | 177 case WebViewerAction_None: |
167 case WebViewerAction_Crosshair: | 178 case WebViewerAction_Crosshair: |
168 case WebViewerAction_CreateAngle: | 179 case WebViewerAction_CreateAngle: |
169 case WebViewerAction_CreateCircle: | 180 case WebViewerAction_CreateCircle: |
170 case WebViewerAction_CreateSegment: | 181 case WebViewerAction_CreateLength: |
171 case WebViewerAction_RemoveMeasure: | 182 case WebViewerAction_RemoveMeasure: |
183 case WebViewerAction_CreatePixelProbe: | |
184 case WebViewerAction_CreateEllipseProbe: | |
185 case WebViewerAction_CreateRectangleProbe: | |
186 case WebViewerAction_CreateTextAnnotation: | |
172 return OrthancStone::MouseAction_None; | 187 return OrthancStone::MouseAction_None; |
173 | 188 |
174 default: | 189 default: |
175 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | 190 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); |
176 } | 191 } |
1196 return ((framesCount_ == 0 && frame == 0) || | 1211 return ((framesCount_ == 0 && frame == 0) || |
1197 (framesCount_ > 0 && frame >= 0 && frame < framesCount_)); | 1212 (framesCount_ > 0 && frame >= 0 && frame < framesCount_)); |
1198 } | 1213 } |
1199 | 1214 |
1200 public: | 1215 public: |
1201 explicit SeriesCursor(size_t framesCount) : | 1216 explicit SeriesCursor(size_t framesCount, |
1217 bool startAtMiddle /* Whether to start at the middle frame */) : | |
1202 framesCount_(framesCount), | 1218 framesCount_(framesCount), |
1203 currentFrame_(framesCount / 2), // Start at the middle frame | 1219 currentFrame_(startAtMiddle ? framesCount / 2 : 0), |
1204 isCircularPrefetch_(false), | 1220 isCircularPrefetch_(false), |
1205 lastAction_(Action_None) | 1221 lastAction_(Action_None) |
1206 { | 1222 { |
1207 SetFastDelta(framesCount / 20); | 1223 SetFastDelta(framesCount / 20); |
1208 UpdatePrefetch(); | 1224 UpdatePrefetch(); |
1579 size_t frame) = 0; | 1595 size_t frame) = 0; |
1580 | 1596 |
1581 virtual void SignalStoneAnnotationAdded(const ViewerViewport& viewport) = 0; | 1597 virtual void SignalStoneAnnotationAdded(const ViewerViewport& viewport) = 0; |
1582 | 1598 |
1583 virtual void SignalStoneAnnotationRemoved(const ViewerViewport& viewport) = 0; | 1599 virtual void SignalStoneAnnotationRemoved(const ViewerViewport& viewport) = 0; |
1600 | |
1601 virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, | |
1602 const OrthancStone::ScenePoint2D& pointedPosition, | |
1603 const OrthancStone::ScenePoint2D& labelPosition) = 0; | |
1584 }; | 1604 }; |
1585 | 1605 |
1586 private: | 1606 private: |
1587 static const int LAYER_TEXTURE = 0; | 1607 static const int LAYER_TEXTURE = 0; |
1588 static const int LAYER_OVERLAY = 1; | 1608 static const int LAYER_OVERLAY = 1; |
1589 static const int LAYER_ORIENTATION_MARKERS = 2; | 1609 static const int LAYER_DEEP_LEARNING = 2; |
1590 static const int LAYER_REFERENCE_LINES = 3; | 1610 static const int LAYER_ORIENTATION_MARKERS = 3; |
1591 static const int LAYER_ANNOTATIONS_OSIRIX = 4; | 1611 static const int LAYER_REFERENCE_LINES = 4; |
1592 static const int LAYER_ANNOTATIONS_STONE = 5; | 1612 static const int LAYER_ANNOTATIONS_OSIRIX = 5; |
1593 static const int LAYER_DEEP_LEARNING = 6; | 1613 static const int LAYER_ANNOTATIONS_STONE = 6; |
1594 | 1614 |
1595 | 1615 |
1596 class ICommand : public Orthanc::IDynamicObject | 1616 class ICommand : public Orthanc::IDynamicObject |
1597 { | 1617 { |
1598 private: | 1618 private: |
1983 float windowingWidth_; | 2003 float windowingWidth_; |
1984 std::vector<float> windowingPresetCenters_; | 2004 std::vector<float> windowingPresetCenters_; |
1985 std::vector<float> windowingPresetWidths_; | 2005 std::vector<float> windowingPresetWidths_; |
1986 unsigned int cineRate_; | 2006 unsigned int cineRate_; |
1987 bool inverted_; | 2007 bool inverted_; |
1988 bool flipX_; | |
1989 bool flipY_; | |
1990 bool fitNextContent_; | 2008 bool fitNextContent_; |
1991 std::list<PrefetchItem> prefetchQueue_; | 2009 std::list<PrefetchItem> prefetchQueue_; |
1992 bool serverSideTranscoding_; | 2010 bool serverSideTranscoding_; |
1993 OrthancStone::Vector synchronizationOffset_; | 2011 OrthancStone::Vector synchronizationOffset_; |
1994 bool synchronizationEnabled_; | 2012 bool synchronizationEnabled_; |
2006 | 2024 |
2007 // The coordinates of Stone annotations are expressed in 2D | 2025 // The coordinates of Stone annotations are expressed in 2D |
2008 // coordinates of the current texture, with (0,0) corresponding to | 2026 // coordinates of the current texture, with (0,0) corresponding to |
2009 // the center of the top-left pixel | 2027 // the center of the top-left pixel |
2010 boost::shared_ptr<OrthancStone::AnnotationsSceneLayer> stoneAnnotations_; | 2028 boost::shared_ptr<OrthancStone::AnnotationsSceneLayer> stoneAnnotations_; |
2029 | |
2030 bool linearInterpolation_; | |
2011 | 2031 |
2012 boost::shared_ptr<Orthanc::ImageAccessor> deepLearningMask_; | 2032 boost::shared_ptr<Orthanc::ImageAccessor> deepLearningMask_; |
2013 std::string deepLearningSopInstanceUid_; | 2033 std::string deepLearningSopInstanceUid_; |
2014 unsigned int deepLearningFrameNumber_; | 2034 unsigned int deepLearningFrameNumber_; |
2015 | |
2016 | 2035 |
2017 void ScheduleNextPrefetch() | 2036 void ScheduleNextPrefetch() |
2018 { | 2037 { |
2019 while (!prefetchQueue_.empty()) | 2038 while (!prefetchQueue_.empty()) |
2020 { | 2039 { |
2148 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); | 2167 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); |
2149 } | 2168 } |
2150 | 2169 |
2151 assert(layer.get() != NULL); | 2170 assert(layer.get() != NULL); |
2152 | 2171 |
2153 layer->SetLinearInterpolation(true); | 2172 layer->SetLinearInterpolation(linearInterpolation_); |
2154 layer->SetFlipX(flipX_); | |
2155 layer->SetFlipY(flipY_); | |
2156 | 2173 |
2157 double pixelSpacingX, pixelSpacingY; | 2174 double pixelSpacingX, pixelSpacingY; |
2158 | 2175 |
2159 if (instance.HasPixelSpacing()) | 2176 if (instance.HasPixelSpacing()) |
2160 { | 2177 { |
2204 { | 2221 { |
2205 OverlaysRegistry::Accessor accessor(OverlaysRegistry::GetInstance(), instance.GetSopInstanceUid()); | 2222 OverlaysRegistry::Accessor accessor(OverlaysRegistry::GetInstance(), instance.GetSopInstanceUid()); |
2206 if (accessor.IsValid()) | 2223 if (accessor.IsValid()) |
2207 { | 2224 { |
2208 overlay.reset(accessor.CreateTexture()); | 2225 overlay.reset(accessor.CreateTexture()); |
2209 overlay->SetFlipX(flipX_); | 2226 overlay->SetLinearInterpolation(false); |
2210 overlay->SetFlipY(flipY_); | |
2211 } | 2227 } |
2212 } | 2228 } |
2213 | 2229 |
2214 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsOsiriX; | 2230 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsOsiriX; |
2215 | 2231 |
2250 } | 2266 } |
2251 | 2267 |
2252 deepLearningLayer.reset(new OrthancStone::LookupTableTextureSceneLayer(*deepLearningMask_)); | 2268 deepLearningLayer.reset(new OrthancStone::LookupTableTextureSceneLayer(*deepLearningMask_)); |
2253 deepLearningLayer->SetLookupTable(lut); | 2269 deepLearningLayer->SetLookupTable(lut); |
2254 deepLearningLayer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); | 2270 deepLearningLayer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); |
2255 deepLearningLayer->SetFlipX(flipX_); | |
2256 deepLearningLayer->SetFlipY(flipY_); | |
2257 } | 2271 } |
2258 | 2272 |
2259 StoneAnnotationsRegistry::GetInstance().Load(*stoneAnnotations_, instance.GetSopInstanceUid(), frameIndex); | 2273 StoneAnnotationsRegistry::GetInstance().Load(*stoneAnnotations_, instance.GetSopInstanceUid(), frameIndex); |
2260 | 2274 |
2261 // Orientation markers, new in Stone Web viewer 2.4 | 2275 // Orientation markers, new in Stone Web viewer 2.4 |
2521 { | 2535 { |
2522 dynamic_cast<OrthancStone::FloatTextureSceneLayer&>( | 2536 dynamic_cast<OrthancStone::FloatTextureSceneLayer&>( |
2523 lock->GetController().GetScene().GetLayer(LAYER_TEXTURE)). | 2537 lock->GetController().GetScene().GetLayer(LAYER_TEXTURE)). |
2524 SetCustomWindowing(windowingCenter_, windowingWidth_); | 2538 SetCustomWindowing(windowingCenter_, windowingWidth_); |
2525 } | 2539 } |
2526 | |
2527 { | |
2528 OrthancStone::TextureBaseSceneLayer& layer = | |
2529 dynamic_cast<OrthancStone::TextureBaseSceneLayer&>( | |
2530 lock->GetController().GetScene().GetLayer(LAYER_TEXTURE)); | |
2531 | |
2532 layer.SetFlipX(flipX_); | |
2533 layer.SetFlipY(flipY_); | |
2534 } | |
2535 | |
2536 if (lock->GetController().GetScene().HasLayer(LAYER_OVERLAY)) | |
2537 { | |
2538 OrthancStone::TextureBaseSceneLayer& layer = | |
2539 dynamic_cast<OrthancStone::TextureBaseSceneLayer&>( | |
2540 lock->GetController().GetScene().GetLayer(LAYER_OVERLAY)); | |
2541 | |
2542 layer.SetFlipX(flipX_); | |
2543 layer.SetFlipY(flipY_); | |
2544 } | |
2545 | 2540 |
2546 lock->Invalidate(); | 2541 lock->Invalidate(); |
2547 } | 2542 } |
2548 } | 2543 } |
2549 | 2544 |
2550 | 2545 |
2551 ViewerViewport(OrthancStone::WebAssemblyLoadersContext& context, | 2546 ViewerViewport(OrthancStone::WebAssemblyLoadersContext& context, |
2552 const OrthancStone::DicomSource& source, | 2547 const OrthancStone::DicomSource& source, |
2553 const std::string& canvas, | 2548 const std::string& canvas, |
2554 boost::shared_ptr<FramesCache> cache, | 2549 boost::shared_ptr<FramesCache> cache, |
2555 bool softwareRendering) : | 2550 bool softwareRendering, |
2551 bool linearInterpolation) : | |
2556 context_(context), | 2552 context_(context), |
2557 source_(source), | 2553 source_(source), |
2558 framesCache_(cache), | 2554 framesCache_(cache), |
2559 fitNextContent_(true), | 2555 fitNextContent_(true), |
2560 flipX_(false), | |
2561 flipY_(false), | |
2562 hasFocusOnInstance_(false), | 2556 hasFocusOnInstance_(false), |
2563 focusFrameNumber_(0), | 2557 focusFrameNumber_(0), |
2564 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)), | 2558 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)), |
2565 synchronizationEnabled_(false), | 2559 synchronizationEnabled_(false), |
2566 centralPhysicalWidth_(1), | 2560 centralPhysicalWidth_(1), |
2567 centralPhysicalHeight_(1), | 2561 centralPhysicalHeight_(1), |
2568 centralPixelSpacingX_(1), | 2562 centralPixelSpacingX_(1), |
2569 centralPixelSpacingY_(1) | 2563 centralPixelSpacingY_(1), |
2564 linearInterpolation_(linearInterpolation) | |
2570 { | 2565 { |
2571 if (!framesCache_) | 2566 if (!framesCache_) |
2572 { | 2567 { |
2573 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 2568 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
2574 } | 2569 } |
2594 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel); | 2589 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel); |
2595 | 2590 |
2596 SetWindowingPreset(); | 2591 SetWindowingPreset(); |
2597 | 2592 |
2598 stoneAnnotations_.reset(new OrthancStone::AnnotationsSceneLayer(LAYER_ANNOTATIONS_STONE)); | 2593 stoneAnnotations_.reset(new OrthancStone::AnnotationsSceneLayer(LAYER_ANNOTATIONS_STONE)); |
2594 stoneAnnotations_->SetProbedLayer(LAYER_TEXTURE); | |
2599 } | 2595 } |
2600 | 2596 |
2601 | 2597 |
2602 void Handle(const OrthancStone::ViewportController::GrayscaleWindowingChanged& message) | 2598 void Handle(const OrthancStone::ViewportController::GrayscaleWindowingChanged& message) |
2603 { | 2599 { |
2731 { | 2727 { |
2732 observer_->SignalStoneAnnotationRemoved(*this); | 2728 observer_->SignalStoneAnnotationRemoved(*this); |
2733 } | 2729 } |
2734 } | 2730 } |
2735 | 2731 |
2732 void Handle(const OrthancStone::AnnotationsSceneLayer::TextAnnotationRequiredMessage& message) | |
2733 { | |
2734 if (observer_.get() != NULL) | |
2735 { | |
2736 observer_->SignalStoneTextAnnotationRequired(*this, message.GetPointedPosition(), message.GetLabelPosition()); | |
2737 } | |
2738 } | |
2739 | |
2736 public: | 2740 public: |
2737 virtual ~ViewerViewport() | 2741 virtual ~ViewerViewport() |
2738 { | 2742 { |
2739 // Unregister the callbacks to avoid any call with a "void*" that | 2743 // Unregister the callbacks to avoid any call with a "void*" that |
2740 // has been destroyed. "WebAssemblyViewport::CreateObjectCookie()" | 2744 // has been destroyed. "WebAssemblyViewport::CreateObjectCookie()" |
2744 | 2748 |
2745 static boost::shared_ptr<ViewerViewport> Create(OrthancStone::WebAssemblyLoadersContext& context, | 2749 static boost::shared_ptr<ViewerViewport> Create(OrthancStone::WebAssemblyLoadersContext& context, |
2746 const OrthancStone::DicomSource& source, | 2750 const OrthancStone::DicomSource& source, |
2747 const std::string& canvas, | 2751 const std::string& canvas, |
2748 boost::shared_ptr<FramesCache> cache, | 2752 boost::shared_ptr<FramesCache> cache, |
2749 bool softwareRendering) | 2753 bool softwareRendering, |
2754 bool linearInterpolation) | |
2750 { | 2755 { |
2751 boost::shared_ptr<ViewerViewport> viewport( | 2756 boost::shared_ptr<ViewerViewport> viewport( |
2752 new ViewerViewport(context, source, canvas, cache, softwareRendering)); | 2757 new ViewerViewport(context, source, canvas, cache, softwareRendering, linearInterpolation)); |
2753 | 2758 |
2754 { | 2759 { |
2755 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context.Lock()); | 2760 std::unique_ptr<OrthancStone::ILoadersContext::ILock> lock(context.Lock()); |
2756 | 2761 |
2757 viewport->loader_ = OrthancStone::DicomResourcesLoader::Create(*lock); | 2762 viewport->loader_ = OrthancStone::DicomResourcesLoader::Create(*lock); |
2770 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage>( | 2775 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationAddedMessage>( |
2771 *viewport->stoneAnnotations_, &ViewerViewport::Handle); | 2776 *viewport->stoneAnnotations_, &ViewerViewport::Handle); |
2772 | 2777 |
2773 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage>( | 2778 viewport->Register<OrthancStone::AnnotationsSceneLayer::AnnotationRemovedMessage>( |
2774 *viewport->stoneAnnotations_, &ViewerViewport::Handle); | 2779 *viewport->stoneAnnotations_, &ViewerViewport::Handle); |
2780 | |
2781 viewport->Register<OrthancStone::AnnotationsSceneLayer::TextAnnotationRequiredMessage>( | |
2782 *viewport->stoneAnnotations_, &ViewerViewport::Handle); | |
2775 } | 2783 } |
2776 | 2784 |
2777 { | 2785 { |
2778 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->viewport_->Lock()); | 2786 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->viewport_->Lock()); |
2779 viewport->Register<OrthancStone::ViewportController::GrayscaleWindowingChanged>(lock->GetController(), &ViewerViewport::Handle); | 2787 viewport->Register<OrthancStone::ViewportController::GrayscaleWindowingChanged>(lock->GetController(), &ViewerViewport::Handle); |
2788 if (frames == NULL) | 2796 if (frames == NULL) |
2789 { | 2797 { |
2790 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 2798 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
2791 } | 2799 } |
2792 | 2800 |
2793 flipX_ = false; | |
2794 flipY_ = false; | |
2795 fitNextContent_ = true; | 2801 fitNextContent_ = true; |
2796 cineRate_ = DEFAULT_CINE_RATE; | 2802 cineRate_ = DEFAULT_CINE_RATE; |
2797 inverted_ = false; | 2803 inverted_ = false; |
2798 serverSideTranscoding_ = false; | 2804 serverSideTranscoding_ = false; |
2799 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0); | 2805 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0); |
2800 | 2806 |
2801 frames_.reset(frames); | 2807 frames_.reset(frames); |
2802 cursor_.reset(new SeriesCursor(frames_->GetFramesCount())); | 2808 cursor_.reset(new SeriesCursor(frames_->GetFramesCount(), false)); |
2809 | |
2810 if (frames_->GetFramesCount() != 0) | |
2811 { | |
2812 const OrthancStone::DicomInstanceParameters& firstInstance = frames_->GetInstanceOfFrame(0); | |
2813 std::string modality; | |
2814 if (firstInstance.GetTags().LookupStringValue(modality, Orthanc::DICOM_TAG_MODALITY, false)) | |
2815 { | |
2816 if (modality == "MR" || | |
2817 modality == "CT" || | |
2818 modality == "NM" || | |
2819 modality == "OPT" || | |
2820 modality == "PT" || | |
2821 modality == "RTDOSE" || | |
2822 modality == "XA") | |
2823 { | |
2824 // For series that might correspond to 3D images, use their | |
2825 // central frame as the first frame to be displayed | |
2826 cursor_.reset(new SeriesCursor(frames_->GetFramesCount(), true)); | |
2827 } | |
2828 } | |
2829 } | |
2803 | 2830 |
2804 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); | 2831 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); |
2805 | 2832 |
2806 SetWindowingPreset(); | 2833 SetWindowingPreset(); |
2807 ClearViewport(); | 2834 ClearViewport(); |
3100 } | 3127 } |
3101 } | 3128 } |
3102 | 3129 |
3103 void FlipX() | 3130 void FlipX() |
3104 { | 3131 { |
3105 flipX_ = !flipX_; | 3132 { |
3106 UpdateCurrentTextureParameters(); | 3133 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); |
3134 lock->GetController().GetScene().FlipViewportX( | |
3135 lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight()); | |
3136 lock->Invalidate(); | |
3137 } | |
3107 } | 3138 } |
3108 | 3139 |
3109 void FlipY() | 3140 void FlipY() |
3110 { | 3141 { |
3111 flipY_ = !flipY_; | 3142 { |
3112 UpdateCurrentTextureParameters(); | 3143 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); |
3144 lock->GetController().GetScene().FlipViewportY( | |
3145 lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight()); | |
3146 lock->Invalidate(); | |
3147 } | |
3148 } | |
3149 | |
3150 void RotateLeft() | |
3151 { | |
3152 { | |
3153 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); | |
3154 lock->GetController().GetScene().RotateViewport( | |
3155 -PI / 2.0, lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight()); | |
3156 lock->Invalidate(); | |
3157 } | |
3158 } | |
3159 | |
3160 void RotateRight() | |
3161 { | |
3162 { | |
3163 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); | |
3164 lock->GetController().GetScene().RotateViewport( | |
3165 PI / 2.0, lock->GetCompositor().GetCanvasWidth(), lock->GetCompositor().GetCanvasHeight()); | |
3166 lock->Invalidate(); | |
3167 } | |
3113 } | 3168 } |
3114 | 3169 |
3115 void Invert() | 3170 void Invert() |
3116 { | 3171 { |
3117 inverted_ = !inverted_; | 3172 inverted_ = !inverted_; |
3222 | 3277 |
3223 case WebViewerAction_CreateCircle: | 3278 case WebViewerAction_CreateCircle: |
3224 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Circle); | 3279 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Circle); |
3225 break; | 3280 break; |
3226 | 3281 |
3227 case WebViewerAction_CreateSegment: | 3282 case WebViewerAction_CreateLength: |
3228 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Segment); | 3283 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Length); |
3229 break; | 3284 break; |
3230 | 3285 |
3231 case WebViewerAction_RemoveMeasure: | 3286 case WebViewerAction_RemoveMeasure: |
3232 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Remove); | 3287 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Remove); |
3288 break; | |
3289 | |
3290 case WebViewerAction_CreatePixelProbe: | |
3291 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_PixelProbe); | |
3292 break; | |
3293 | |
3294 case WebViewerAction_CreateEllipseProbe: | |
3295 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_EllipseProbe); | |
3296 break; | |
3297 | |
3298 case WebViewerAction_CreateRectangleProbe: | |
3299 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_RectangleProbe); | |
3300 break; | |
3301 | |
3302 case WebViewerAction_CreateTextAnnotation: | |
3303 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_TextAnnotation); | |
3233 break; | 3304 break; |
3234 | 3305 |
3235 default: | 3306 default: |
3236 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Edit); | 3307 viewer_.stoneAnnotations_->SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Edit); |
3237 break; | 3308 break; |
3400 stoneAnnotations_->Render(lock->GetController().GetScene()); | 3471 stoneAnnotations_->Render(lock->GetController().GetScene()); |
3401 lock->Invalidate(); | 3472 lock->Invalidate(); |
3402 } | 3473 } |
3403 } | 3474 } |
3404 } | 3475 } |
3476 } | |
3477 | |
3478 | |
3479 void SetLinearInterpolation(bool linearInterpolation) | |
3480 { | |
3481 if (linearInterpolation_ != linearInterpolation) | |
3482 { | |
3483 linearInterpolation_ = linearInterpolation; | |
3484 Redraw(); | |
3485 } | |
3486 } | |
3487 | |
3488 | |
3489 void AddTextAnnotation(const std::string& label, | |
3490 const OrthancStone::ScenePoint2D& pointedPosition, | |
3491 const OrthancStone::ScenePoint2D& labelPosition) | |
3492 { | |
3493 stoneAnnotations_->AddTextAnnotation(label, pointedPosition, labelPosition); | |
3494 Redraw(); | |
3405 } | 3495 } |
3406 | 3496 |
3407 | 3497 |
3408 bool GetCurrentFrame(std::string& sopInstanceUid /* out */, | 3498 bool GetCurrentFrame(std::string& sopInstanceUid /* out */, |
3409 unsigned int& frameNumber /* out */) const | 3499 unsigned int& frameNumber /* out */) const |
3698 { "canvasId" : UTF8ToString($0) }); | 3788 { "canvasId" : UTF8ToString($0) }); |
3699 window.dispatchEvent(customEvent); | 3789 window.dispatchEvent(customEvent); |
3700 }, | 3790 }, |
3701 viewport.GetCanvasId().c_str()); | 3791 viewport.GetCanvasId().c_str()); |
3702 } | 3792 } |
3793 | |
3794 virtual void SignalStoneTextAnnotationRequired(const ViewerViewport& viewport, | |
3795 const OrthancStone::ScenePoint2D& pointedPosition, | |
3796 const OrthancStone::ScenePoint2D& labelPosition) ORTHANC_OVERRIDE | |
3797 { | |
3798 EM_ASM({ | |
3799 const customEvent = document.createEvent("CustomEvent"); | |
3800 customEvent.initCustomEvent("TextAnnotationRequired", false, false, | |
3801 { "canvasId" : UTF8ToString($0), | |
3802 "pointedX" : $1, | |
3803 "pointedY" : $2, | |
3804 "labelX" : $3, | |
3805 "labelY" : $4 }); | |
3806 window.dispatchEvent(customEvent); | |
3807 }, | |
3808 viewport.GetCanvasId().c_str(), | |
3809 pointedPosition.GetX(), | |
3810 pointedPosition.GetY(), | |
3811 labelPosition.GetX(), | |
3812 labelPosition.GetY() ); | |
3813 } | |
3703 }; | 3814 }; |
3704 | 3815 |
3705 | 3816 |
3706 | 3817 |
3707 static OrthancStone::DicomSource source_; | 3818 static OrthancStone::DicomSource source_; |
3708 static boost::shared_ptr<FramesCache> framesCache_; | 3819 static boost::shared_ptr<FramesCache> framesCache_; |
3709 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_; | 3820 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_; |
3710 static std::string stringBuffer_; | 3821 static std::string stringBuffer_; |
3711 static bool softwareRendering_ = false; | 3822 static bool softwareRendering_ = false; |
3823 static bool linearInterpolation_ = true; | |
3712 static WebViewerAction leftButtonAction_ = WebViewerAction_Windowing; | 3824 static WebViewerAction leftButtonAction_ = WebViewerAction_Windowing; |
3713 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan; | 3825 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan; |
3714 static WebViewerAction rightButtonAction_ = WebViewerAction_Zoom; | 3826 static WebViewerAction rightButtonAction_ = WebViewerAction_Zoom; |
3715 | 3827 |
3716 | 3828 |
3753 { | 3865 { |
3754 Viewports::iterator found = allViewports_.find(canvas); | 3866 Viewports::iterator found = allViewports_.find(canvas); |
3755 if (found == allViewports_.end()) | 3867 if (found == allViewports_.end()) |
3756 { | 3868 { |
3757 boost::shared_ptr<ViewerViewport> viewport( | 3869 boost::shared_ptr<ViewerViewport> viewport( |
3758 ViewerViewport::Create(*context_, source_, canvas, framesCache_, softwareRendering_)); | 3870 ViewerViewport::Create(*context_, source_, canvas, framesCache_, softwareRendering_, linearInterpolation_)); |
3759 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); | 3871 viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); |
3760 viewport->AcquireObserver(new WebAssemblyObserver); | 3872 viewport->AcquireObserver(new WebAssemblyObserver); |
3761 viewport->SetOsiriXAnnotations(osiriXAnnotations_); | 3873 viewport->SetOsiriXAnnotations(osiriXAnnotations_); |
3762 allViewports_[canvas] = viewport; | 3874 allViewports_[canvas] = viewport; |
3763 return viewport; | 3875 return viewport; |
4492 EXTERN_CATCH_EXCEPTIONS; | 4604 EXTERN_CATCH_EXCEPTIONS; |
4493 } | 4605 } |
4494 | 4606 |
4495 | 4607 |
4496 EMSCRIPTEN_KEEPALIVE | 4608 EMSCRIPTEN_KEEPALIVE |
4609 void RotateLeft(const char* canvas) | |
4610 { | |
4611 try | |
4612 { | |
4613 GetViewport(canvas)->RotateLeft(); | |
4614 } | |
4615 EXTERN_CATCH_EXCEPTIONS; | |
4616 } | |
4617 | |
4618 | |
4619 EMSCRIPTEN_KEEPALIVE | |
4620 void RotateRight(const char* canvas) | |
4621 { | |
4622 try | |
4623 { | |
4624 GetViewport(canvas)->RotateRight(); | |
4625 } | |
4626 EXTERN_CATCH_EXCEPTIONS; | |
4627 } | |
4628 | |
4629 | |
4630 EMSCRIPTEN_KEEPALIVE | |
4497 void SetSoftwareRendering(int softwareRendering) | 4631 void SetSoftwareRendering(int softwareRendering) |
4498 { | 4632 { |
4499 softwareRendering_ = softwareRendering; | 4633 softwareRendering_ = softwareRendering; |
4500 } | 4634 } |
4501 | 4635 |
4502 | 4636 |
4503 EMSCRIPTEN_KEEPALIVE | 4637 EMSCRIPTEN_KEEPALIVE |
4504 int IsSoftwareRendering() | 4638 int IsSoftwareRendering() |
4505 { | 4639 { |
4506 return softwareRendering_; | 4640 return softwareRendering_; |
4641 } | |
4642 | |
4643 | |
4644 EMSCRIPTEN_KEEPALIVE | |
4645 void SetLinearInterpolation(int linearInterpolation) | |
4646 { | |
4647 linearInterpolation_ = linearInterpolation; | |
4648 | |
4649 try | |
4650 { | |
4651 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) | |
4652 { | |
4653 assert(it->second != NULL); | |
4654 it->second->SetLinearInterpolation(linearInterpolation); | |
4655 } | |
4656 } | |
4657 EXTERN_CATCH_EXCEPTIONS; | |
4507 } | 4658 } |
4508 | 4659 |
4509 | 4660 |
4510 EMSCRIPTEN_KEEPALIVE | 4661 EMSCRIPTEN_KEEPALIVE |
4511 void SetMouseButtonActions(int leftAction, | 4662 void SetMouseButtonActions(int leftAction, |
4716 } | 4867 } |
4717 } | 4868 } |
4718 EXTERN_CATCH_EXCEPTIONS; | 4869 EXTERN_CATCH_EXCEPTIONS; |
4719 return false; | 4870 return false; |
4720 } | 4871 } |
4872 | |
4873 | |
4874 EMSCRIPTEN_KEEPALIVE | |
4875 void AddTextAnnotation(const char* canvas, | |
4876 const char* label, | |
4877 double pointedX, | |
4878 double pointedY, | |
4879 double labelX, | |
4880 double labelY) | |
4881 { | |
4882 try | |
4883 { | |
4884 GetViewport(canvas)->AddTextAnnotation(label, OrthancStone::ScenePoint2D(pointedX, pointedY), | |
4885 OrthancStone::ScenePoint2D(labelX, labelY)); | |
4886 } | |
4887 EXTERN_CATCH_EXCEPTIONS; | |
4888 } | |
4721 } | 4889 } |