comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1693:eafb10992e73

synchronized browsing
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 26 Nov 2020 13:46:50 +0100
parents 84fe7089ccaa
children 7226b68e2742
comparison
equal deleted inserted replaced
1692:e787b52d025f 1693:eafb10992e73
1031 virtual void SignalFrameUpdated(const ViewerViewport& viewport, 1031 virtual void SignalFrameUpdated(const ViewerViewport& viewport,
1032 size_t currentFrame, 1032 size_t currentFrame,
1033 size_t countFrames, 1033 size_t countFrames,
1034 DisplayedFrameQuality quality) = 0; 1034 DisplayedFrameQuality quality) = 0;
1035 1035
1036 virtual void SignalCrosshair(const OrthancStone::Vector& click) = 0; 1036 virtual void SignalCrosshair(const ViewerViewport& viewport,
1037 const OrthancStone::Vector& click) = 0;
1037 }; 1038 };
1038 1039
1039 private: 1040 private:
1040 static const int LAYER_TEXTURE = 0; 1041 static const int LAYER_TEXTURE = 0;
1041 static const int LAYER_REFERENCE_LINES = 1; 1042 static const int LAYER_REFERENCE_LINES = 1;
1395 unsigned int cineRate_; 1396 unsigned int cineRate_;
1396 bool inverted_; 1397 bool inverted_;
1397 bool flipX_; 1398 bool flipX_;
1398 bool flipY_; 1399 bool flipY_;
1399 bool fitNextContent_; 1400 bool fitNextContent_;
1400 bool isCtrlDown_;
1401 std::list<PrefetchItem> prefetchQueue_; 1401 std::list<PrefetchItem> prefetchQueue_;
1402 bool serverSideTranscoding_; 1402 bool serverSideTranscoding_;
1403 OrthancStone::Vector synchronizationOffset_;
1404 bool synchronizationEnabled_;
1403 1405
1404 1406
1405 bool hasFocusOnInstance_; 1407 bool hasFocusOnInstance_;
1406 std::string focusSopInstanceUid_; 1408 std::string focusSopInstanceUid_;
1407 size_t focusFrameNumber_; 1409 size_t focusFrameNumber_;
1780 bool softwareRendering) : 1782 bool softwareRendering) :
1781 context_(context), 1783 context_(context),
1782 source_(source), 1784 source_(source),
1783 framesCache_(cache), 1785 framesCache_(cache),
1784 fitNextContent_(true), 1786 fitNextContent_(true),
1785 isCtrlDown_(false),
1786 flipX_(false), 1787 flipX_(false),
1787 flipY_(false), 1788 flipY_(false),
1788 hasFocusOnInstance_(false), 1789 hasFocusOnInstance_(false),
1789 focusFrameNumber_(0) 1790 focusFrameNumber_(0),
1791 synchronizationOffset_(OrthancStone::LinearAlgebra::CreateVector(0, 0, 0)),
1792 synchronizationEnabled_(false)
1790 { 1793 {
1791 if (!framesCache_) 1794 if (!framesCache_)
1792 { 1795 {
1793 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); 1796 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
1794 } 1797 }
1810 Orthanc::EmbeddedResources::GetFileResource(ttf, Orthanc::EmbeddedResources::UBUNTU_FONT); 1813 Orthanc::EmbeddedResources::GetFileResource(ttf, Orthanc::EmbeddedResources::UBUNTU_FONT);
1811 lock->GetCompositor().SetFont(0, ttf, 24 /* font size */, Orthanc::Encoding_Latin1); 1814 lock->GetCompositor().SetFont(0, ttf, 24 /* font size */, Orthanc::Encoding_Latin1);
1812 } 1815 }
1813 1816
1814 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel); 1817 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, OnWheel);
1815 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey);
1816 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, OnKey);
1817 1818
1818 SetWindowingPreset(); 1819 SetWindowingPreset();
1819 }
1820
1821 static EM_BOOL OnKey(int eventType,
1822 const EmscriptenKeyboardEvent *event,
1823 void *userData)
1824 {
1825 /**
1826 * WARNING: There is a problem with Firefox 71 that seems to mess
1827 * the "ctrlKey" value.
1828 **/
1829
1830 ViewerViewport& that = *reinterpret_cast<ViewerViewport*>(userData);
1831 that.isCtrlDown_ = event->ctrlKey;
1832 return false;
1833 } 1820 }
1834 1821
1835 1822
1836 static EM_BOOL OnWheel(int eventType, 1823 static EM_BOOL OnWheel(int eventType,
1837 const EmscriptenWheelEvent *wheelEvent, 1824 const EmscriptenWheelEvent *wheelEvent,
1838 void *userData) 1825 void *userData)
1839 { 1826 {
1840 ViewerViewport& that = *reinterpret_cast<ViewerViewport*>(userData); 1827 ViewerViewport& that = *reinterpret_cast<ViewerViewport*>(userData);
1841 1828
1842 if (that.cursor_.get() != NULL) 1829 if (that.frames_.get() != NULL &&
1843 { 1830 that.cursor_.get() != NULL)
1831 {
1832 const bool isCtrl = wheelEvent->mouse.ctrlKey;
1833 const bool isShift = wheelEvent->mouse.shiftKey;
1834
1835 const size_t previousCursorIndex = that.cursor_->GetCurrentIndex();
1836
1844 if (wheelEvent->deltaY < 0) 1837 if (wheelEvent->deltaY < 0)
1845 { 1838 {
1846 that.ChangeFrame(that.isCtrlDown_ ? SeriesCursor::Action_FastMinus : SeriesCursor::Action_Minus, false /* not circular */); 1839 that.ChangeFrame(isCtrl ? SeriesCursor::Action_FastMinus :
1840 SeriesCursor::Action_Minus, false /* not circular */);
1847 } 1841 }
1848 else if (wheelEvent->deltaY > 0) 1842 else if (wheelEvent->deltaY > 0)
1849 { 1843 {
1850 that.ChangeFrame(that.isCtrlDown_ ? SeriesCursor::Action_FastPlus : SeriesCursor::Action_Plus, false /* not circular */); 1844 that.ChangeFrame(isCtrl ? SeriesCursor::Action_FastPlus :
1845 SeriesCursor::Action_Plus, false /* not circular */);
1846 }
1847
1848 if (that.synchronizationEnabled_)
1849 {
1850 const size_t currentCursorIndex = that.cursor_->GetCurrentIndex();
1851
1852 const OrthancStone::CoordinateSystem3D current =
1853 that.frames_->GetFrameGeometry(currentCursorIndex);
1854
1855 if (isShift &&
1856 previousCursorIndex != currentCursorIndex)
1857 {
1858 const OrthancStone::CoordinateSystem3D previous =
1859 that.frames_->GetFrameGeometry(previousCursorIndex);
1860 that.synchronizationOffset_ += previous.GetOrigin() - current.GetOrigin();
1861 }
1862
1863 that.observer_->SignalCrosshair(that, current.GetOrigin() + that.synchronizationOffset_);
1851 } 1864 }
1852 } 1865 }
1853 1866
1854 return true; 1867 return true;
1855 } 1868 }
1874 { 1887 {
1875 // Unregister the callbacks to avoid any call with a "void*" that 1888 // Unregister the callbacks to avoid any call with a "void*" that
1876 // has been destroyed. "WebAssemblyViewport::CreateObjectCookie()" 1889 // has been destroyed. "WebAssemblyViewport::CreateObjectCookie()"
1877 // provides a more advanced alternative. 1890 // provides a more advanced alternative.
1878 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, NULL); 1891 emscripten_set_wheel_callback(viewport_->GetCanvasCssSelector().c_str(), this, true, NULL);
1879 emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, NULL);
1880 emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, this, false, NULL);
1881 } 1892 }
1882 1893
1883 static boost::shared_ptr<ViewerViewport> Create(OrthancStone::WebAssemblyLoadersContext& context, 1894 static boost::shared_ptr<ViewerViewport> Create(OrthancStone::WebAssemblyLoadersContext& context,
1884 const OrthancStone::DicomSource& source, 1895 const OrthancStone::DicomSource& source,
1885 const std::string& canvas, 1896 const std::string& canvas,
1917 flipY_ = false; 1928 flipY_ = false;
1918 fitNextContent_ = true; 1929 fitNextContent_ = true;
1919 cineRate_ = DEFAULT_CINE_RATE; 1930 cineRate_ = DEFAULT_CINE_RATE;
1920 inverted_ = false; 1931 inverted_ = false;
1921 serverSideTranscoding_ = false; 1932 serverSideTranscoding_ = false;
1933 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0);
1922 1934
1923 frames_.reset(frames); 1935 frames_.reset(frames);
1924 cursor_.reset(new SeriesCursor(frames_->GetFramesCount())); 1936 cursor_.reset(new SeriesCursor(frames_->GetFramesCount()));
1925 1937
1926 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); 1938 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount();
2279 lock2->GetController().GetCanvasToSceneTransform().Apply(x, y); 2291 lock2->GetController().GetCanvasToSceneTransform().Apply(x, y);
2280 2292
2281 OrthancStone::Vector click = plane.MapSliceToWorldCoordinates(x, y); 2293 OrthancStone::Vector click = plane.MapSliceToWorldCoordinates(x, y);
2282 if (viewer_.observer_.get() != NULL) 2294 if (viewer_.observer_.get() != NULL)
2283 { 2295 {
2284 viewer_.observer_->SignalCrosshair(click); 2296 viewer_.observer_->SignalCrosshair(viewer_, click);
2285 } 2297 }
2286 } 2298 }
2287 2299
2288 return NULL; // No need for a tracker, this is just a click 2300 return NULL; // No need for a tracker, this is just a click
2289 } 2301 }
2382 name += " " + boost::lexical_cast<std::string>(i + 1); 2394 name += " " + boost::lexical_cast<std::string>(i + 1);
2383 } 2395 }
2384 2396
2385 Json::Value preset = Json::objectValue; 2397 Json::Value preset = Json::objectValue;
2386 preset["name"] = name; 2398 preset["name"] = name;
2387 preset["info"] = ("C " + boost::lexical_cast<std::string>(boost::math::iround(c)) +
2388 ", W " + boost::lexical_cast<std::string>(boost::math::iround(w)));
2389 preset["center"] = c; 2399 preset["center"] = c;
2390 preset["width"] = w; 2400 preset["width"] = w;
2391 2401 preset["info"] =
2402 ("C " + boost::lexical_cast<std::string>(static_cast<int>(boost::math::iround<double>(c))) +
2403 ", W " + boost::lexical_cast<std::string>(static_cast<int>(boost::math::iround<double>(w))));
2404
2392 target.append(preset); 2405 target.append(preset);
2393 } 2406 }
2407 }
2408
2409
2410 void SetSynchronizedBrowsingEnabled(int enabled)
2411 {
2412 OrthancStone::LinearAlgebra::AssignVector(synchronizationOffset_, 0, 0, 0);
2413 synchronizationEnabled_ = enabled;
2394 } 2414 }
2395 }; 2415 };
2396 2416
2397 2417
2398 2418
2508 quality); 2528 quality);
2509 2529
2510 UpdateReferenceLines(); 2530 UpdateReferenceLines();
2511 } 2531 }
2512 2532
2513 virtual void SignalCrosshair(const OrthancStone::Vector& click) ORTHANC_OVERRIDE 2533 virtual void SignalCrosshair(const ViewerViewport& viewport,
2534 const OrthancStone::Vector& click) ORTHANC_OVERRIDE
2514 { 2535 {
2515 for (Viewports::const_iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) 2536 for (Viewports::const_iterator it = allViewports_.begin(); it != allViewports_.end(); ++it)
2516 { 2537 {
2517 assert(it->second != NULL); 2538 assert(it->second.get() != NULL);
2518 it->second->FocusOnPoint(click); 2539 if (it->second.get() != &viewport)
2540 {
2541 it->second->FocusOnPoint(click);
2542 }
2519 } 2543 }
2520 } 2544 }
2521 2545
2522 virtual void SignalSeriesPdfLoaded(const std::string& studyInstanceUid, 2546 virtual void SignalSeriesPdfLoaded(const std::string& studyInstanceUid,
2523 const std::string& seriesInstanceUid, 2547 const std::string& seriesInstanceUid,
3082 GetViewport(canvas)->FormatWindowingPresets(v); 3106 GetViewport(canvas)->FormatWindowingPresets(v);
3083 stringBuffer_ = v.toStyledString(); 3107 stringBuffer_ = v.toStyledString();
3084 } 3108 }
3085 EXTERN_CATCH_EXCEPTIONS; 3109 EXTERN_CATCH_EXCEPTIONS;
3086 } 3110 }
3111
3112
3113 EMSCRIPTEN_KEEPALIVE
3114 void SetSynchronizedBrowsingEnabled(int enabled)
3115 {
3116 try
3117 {
3118 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it)
3119 {
3120 assert(it->second != NULL);
3121 it->second->SetSynchronizedBrowsingEnabled(enabled);
3122 }
3123 }
3124 EXTERN_CATCH_EXCEPTIONS;
3125 }
3087 } 3126 }