comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1668:ab1bc8de1798

refactoring
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 19 Nov 2020 18:39:31 +0100
parents 9584df157a9e
children d82a141e08d7
comparison
equal deleted inserted replaced
1667:9584df157a9e 1668:ab1bc8de1798
110 ThumbnailType_NoPreview, 110 ThumbnailType_NoPreview,
111 ThumbnailType_Pdf, 111 ThumbnailType_Pdf,
112 ThumbnailType_Video, 112 ThumbnailType_Video,
113 ThumbnailType_Loading, 113 ThumbnailType_Loading,
114 ThumbnailType_Unknown 114 ThumbnailType_Unknown
115 }; 115 };
116 116
117 117
118 enum STONE_WEB_VIEWER_EXPORT DisplayedFrameQuality 118 enum STONE_WEB_VIEWER_EXPORT DisplayedFrameQuality
119 { 119 {
120 DisplayedFrameQuality_None, 120 DisplayedFrameQuality_None,
1080 LOG(INFO) << "No default windowing"; 1080 LOG(INFO) << "No default windowing";
1081 GetViewport().ResetDefaultWindowing(); 1081 GetViewport().ResetDefaultWindowing();
1082 } 1082 }
1083 } 1083 }
1084 1084
1085 GetViewport().DisplayCurrentFrame(); 1085 GetViewport().Redraw();
1086 } 1086 }
1087 }; 1087 };
1088 1088
1089 1089
1090 class SetLowQualityFrame : public ICommand 1090 class SetLowQualityFrame : public ICommand
1373 size_t cursorIndex = cursor_->GetCurrentIndex(); 1373 size_t cursorIndex = cursor_->GetCurrentIndex();
1374 1374
1375 if (frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid() == sopInstanceUid && 1375 if (frames_->GetInstanceOfFrame(cursorIndex).GetSopInstanceUid() == sopInstanceUid &&
1376 frames_->GetFrameNumberInInstance(cursorIndex) == frameNumber) 1376 frames_->GetFrameNumberInInstance(cursorIndex) == frameNumber)
1377 { 1377 {
1378 DisplayCurrentFrame(); 1378 Redraw();
1379 }
1380 }
1381 }
1382
1383
1384 void DisplayCurrentFrame()
1385 {
1386 DisplayedFrameQuality quality = DisplayedFrameQuality_None;
1387
1388 if (cursor_.get() != NULL &&
1389 frames_.get() != NULL)
1390 {
1391 const size_t cursorIndex = cursor_->GetCurrentIndex();
1392
1393 unsigned int cachedQuality;
1394 if (!DisplayFrame(cachedQuality, cursorIndex))
1395 {
1396 // This frame is not cached yet: Load it
1397 if (source_.HasDicomWebRendered())
1398 {
1399 ScheduleLoadRenderedFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1400 }
1401 else
1402 {
1403 ScheduleLoadFullDicomFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1404 }
1405 }
1406 else if (cachedQuality < QUALITY_FULL)
1407 {
1408 // This frame is only available in low-res: Download the full DICOM
1409 ScheduleLoadFullDicomFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1410 quality = DisplayedFrameQuality_Low;
1411 }
1412 else
1413 {
1414 quality = DisplayedFrameQuality_High;
1415 }
1416
1417 {
1418 // Prepare prefetching
1419 prefetchQueue_.clear();
1420 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16; i++)
1421 {
1422 size_t a = cursor_->GetPrefetchIndex(i);
1423 if (a != cursorIndex)
1424 {
1425 prefetchQueue_.push_back(PrefetchItem(a, i < 2));
1426 }
1427 }
1428
1429 ScheduleNextPrefetch();
1430 }
1431
1432 if (observer_.get() != NULL)
1433 {
1434 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(),
1435 frames_->GetFramesCount(), quality);
1436 } 1379 }
1437 } 1380 }
1438 } 1381 }
1439 1382
1440 1383
1467 layer.GetWindowing(windowingCenter_, windowingWidth_); 1410 layer.GetWindowing(windowingCenter_, windowingWidth_);
1468 } 1411 }
1469 } 1412 }
1470 1413
1471 1414
1472 bool DisplayFrame(unsigned int& quality, 1415 void RenderCurrentScene(const Orthanc::ImageAccessor& frame,
1473 size_t cursorIndex) 1416 const OrthancStone::DicomInstanceParameters& instance,
1474 { 1417 const OrthancStone::CoordinateSystem3D& plane)
1475 if (frames_.get() == NULL) 1418 {
1476 { 1419 SaveCurrentWindowing();
1477 return false; 1420
1478 } 1421 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() ==
1479 1422 Orthanc::PhotometricInterpretation_Monochrome1);
1423
1424 std::unique_ptr<OrthancStone::TextureBaseSceneLayer> layer;
1425
1426 switch (frame.GetFormat())
1427 {
1428 case Orthanc::PixelFormat_RGB24:
1429 layer.reset(new OrthancStone::ColorTextureSceneLayer(frame));
1430 break;
1431
1432 case Orthanc::PixelFormat_Float32:
1433 {
1434 std::unique_ptr<OrthancStone::FloatTextureSceneLayer> tmp(
1435 new OrthancStone::FloatTextureSceneLayer(frame));
1436 tmp->SetCustomWindowing(windowingCenter_, windowingWidth_);
1437 tmp->SetInverted(inverted_ ^ isMonochrome1);
1438 layer.reset(tmp.release());
1439 break;
1440 }
1441
1442 default:
1443 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
1444 }
1445
1446 assert(layer.get() != NULL);
1447
1448 layer->SetLinearInterpolation(true);
1449 layer->SetFlipX(flipX_);
1450 layer->SetFlipY(flipY_);
1451
1452 double pixelSpacingX, pixelSpacingY;
1453 OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX, pixelSpacingY, instance.GetTags());
1454 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY);
1455
1456 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer;
1457
1458 if (annotations_)
1459 {
1460 std::set<size_t> a;
1461 annotations_->LookupSopInstanceUid(a, instance.GetSopInstanceUid());
1462 if (plane.IsValid() &&
1463 !a.empty())
1464 {
1465 annotationsLayer.reset(new OrthancStone::MacroSceneLayer);
1466 annotationsLayer->Reserve(a.size());
1467
1468 OrthancStone::OsiriXLayerFactory factory;
1469 factory.SetColor(0, 255, 0);
1470
1471 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it)
1472 {
1473 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(*it);
1474 annotationsLayer->AddLayer(factory.Create(annotation, plane));
1475 }
1476 }
1477 }
1478
1479 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
1480
1481 OrthancStone::Scene2D& scene = lock->GetController().GetScene();
1482
1483 scene.SetLayer(LAYER_TEXTURE, layer.release());
1484
1485 if (annotationsLayer.get() != NULL)
1486 {
1487 scene.SetLayer(LAYER_ANNOTATIONS, annotationsLayer.release());
1488 }
1489 else
1490 {
1491 scene.DeleteLayer(LAYER_ANNOTATIONS);
1492 }
1493
1494 if (fitNextContent_)
1495 {
1496 lock->RefreshCanvasSize();
1497 lock->GetCompositor().FitContent(scene);
1498 fitNextContent_ = false;
1499 }
1500
1501 //lock->GetCompositor().Refresh(scene);
1502 lock->Invalidate();
1503 }
1504
1505
1506 bool RenderCurrentSceneUsingCache(unsigned int& quality)
1507 {
1508 assert(cursor_.get() != NULL);
1509 assert(frames_.get() != NULL);
1510
1511 const size_t cursorIndex = cursor_->GetCurrentIndex();
1480 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex); 1512 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(cursorIndex);
1481 const std::string sopInstanceUid = instance.GetSopInstanceUid(); 1513 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursorIndex);
1482 size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex); 1514
1483 1515 const size_t frameNumber = frames_->GetFrameNumberInInstance(cursorIndex);
1484 FramesCache::Accessor accessor(*cache_, sopInstanceUid, frameNumber); 1516
1517 FramesCache::Accessor accessor(*cache_, instance.GetSopInstanceUid(), frameNumber);
1485 if (accessor.IsValid()) 1518 if (accessor.IsValid())
1486 { 1519 {
1487 SaveCurrentWindowing();
1488
1489 quality = accessor.GetQuality(); 1520 quality = accessor.GetQuality();
1490 1521 RenderCurrentScene(accessor.GetImage(), instance, plane);
1491 bool isMonochrome1 = (instance.GetImageInformation().GetPhotometricInterpretation() == 1522 return true;
1492 Orthanc::PhotometricInterpretation_Monochrome1);
1493
1494 std::unique_ptr<OrthancStone::TextureBaseSceneLayer> layer;
1495
1496 switch (accessor.GetImage().GetFormat())
1497 {
1498 case Orthanc::PixelFormat_RGB24:
1499 layer.reset(new OrthancStone::ColorTextureSceneLayer(accessor.GetImage()));
1500 break;
1501
1502 case Orthanc::PixelFormat_Float32:
1503 {
1504 std::unique_ptr<OrthancStone::FloatTextureSceneLayer> tmp(
1505 new OrthancStone::FloatTextureSceneLayer(accessor.GetImage()));
1506 tmp->SetCustomWindowing(windowingCenter_, windowingWidth_);
1507 tmp->SetInverted(inverted_ ^ isMonochrome1);
1508 layer.reset(tmp.release());
1509 break;
1510 }
1511
1512 default:
1513 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
1514 }
1515
1516 layer->SetLinearInterpolation(true);
1517 layer->SetFlipX(flipX_);
1518 layer->SetFlipY(flipY_);
1519
1520 double pixelSpacingX, pixelSpacingY;
1521 OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX, pixelSpacingY, instance.GetTags());
1522 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY);
1523
1524 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer;
1525
1526 if (annotations_ &&
1527 cursor_.get() != NULL)
1528 {
1529 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursor_->GetCurrentIndex());
1530
1531 std::set<size_t> a;
1532 annotations_->LookupSopInstanceUid(a, sopInstanceUid);
1533 if (plane.IsValid() &&
1534 !a.empty())
1535 {
1536 annotationsLayer.reset(new OrthancStone::MacroSceneLayer);
1537 annotationsLayer->Reserve(a.size());
1538
1539 OrthancStone::OsiriXLayerFactory factory;
1540 factory.SetColor(0, 255, 0);
1541
1542 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it)
1543 {
1544 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(*it);
1545 annotationsLayer->AddLayer(factory.Create(annotation, plane));
1546 }
1547 }
1548 }
1549
1550
1551 if (layer.get() == NULL)
1552 {
1553 return false;
1554 }
1555 else
1556 {
1557 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
1558
1559 OrthancStone::Scene2D& scene = lock->GetController().GetScene();
1560
1561 scene.SetLayer(LAYER_TEXTURE, layer.release());
1562
1563 if (annotationsLayer.get() != NULL)
1564 {
1565 scene.SetLayer(LAYER_ANNOTATIONS, annotationsLayer.release());
1566 }
1567 else
1568 {
1569 scene.DeleteLayer(LAYER_ANNOTATIONS);
1570 }
1571
1572 if (fitNextContent_)
1573 {
1574 lock->RefreshCanvasSize();
1575 lock->GetCompositor().FitContent(scene);
1576 fitNextContent_ = false;
1577 }
1578
1579 //lock->GetCompositor().Refresh(scene);
1580 lock->Invalidate();
1581 return true;
1582 }
1583 } 1523 }
1584 else 1524 else
1585 { 1525 {
1586 return false; 1526 return false;
1587 } 1527 }
1860 1800
1861 ApplyScheduledFocus(); 1801 ApplyScheduledFocus();
1862 } 1802 }
1863 1803
1864 1804
1865 void Redraw()
1866 {
1867 if (cursor_.get() != NULL)
1868 {
1869 unsigned int quality;
1870 DisplayFrame(quality, cursor_->GetCurrentIndex());
1871 }
1872 }
1873
1874
1875 // This method is used when the layout of the HTML page changes, 1805 // This method is used when the layout of the HTML page changes,
1876 // which does not trigger the "emscripten_set_resize_callback()" 1806 // which does not trigger the "emscripten_set_resize_callback()"
1877 void UpdateSize(bool fitContent) 1807 void UpdateSize(bool fitContent)
1878 { 1808 {
1879 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); 1809 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock());
1895 const std::string& GetCanvasId() const 1825 const std::string& GetCanvasId() const
1896 { 1826 {
1897 assert(viewport_); 1827 assert(viewport_);
1898 return viewport_->GetCanvasId(); 1828 return viewport_->GetCanvasId();
1899 } 1829 }
1830
1831
1832 void Redraw()
1833 {
1834 DisplayedFrameQuality quality = DisplayedFrameQuality_None;
1835
1836 if (cursor_.get() != NULL &&
1837 frames_.get() != NULL)
1838 {
1839 const size_t cursorIndex = cursor_->GetCurrentIndex();
1840
1841 unsigned int cachedQuality;
1842 if (!RenderCurrentSceneUsingCache(cachedQuality))
1843 {
1844 // This frame is not cached yet: Load it
1845 if (source_.HasDicomWebRendered())
1846 {
1847 ScheduleLoadRenderedFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1848 }
1849 else
1850 {
1851 ScheduleLoadFullDicomFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1852 }
1853 }
1854 else if (cachedQuality < QUALITY_FULL)
1855 {
1856 // This frame is only available in low-res: Download the full DICOM
1857 ScheduleLoadFullDicomFrame(cursorIndex, PRIORITY_HIGH, false /* not a prefetch */);
1858 quality = DisplayedFrameQuality_Low;
1859 }
1860 else
1861 {
1862 quality = DisplayedFrameQuality_High;
1863 }
1864
1865 {
1866 // Prepare prefetching
1867 prefetchQueue_.clear();
1868 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16; i++)
1869 {
1870 size_t a = cursor_->GetPrefetchIndex(i);
1871 if (a != cursorIndex)
1872 {
1873 prefetchQueue_.push_back(PrefetchItem(a, i < 2));
1874 }
1875 }
1876
1877 ScheduleNextPrefetch();
1878 }
1879
1880 if (observer_.get() != NULL)
1881 {
1882 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(),
1883 frames_->GetFramesCount(), quality);
1884 }
1885 }
1886 }
1887
1900 1888
1901 void ChangeFrame(SeriesCursor::Action action) 1889 void ChangeFrame(SeriesCursor::Action action)
1902 { 1890 {
1903 if (cursor_.get() != NULL) 1891 if (cursor_.get() != NULL)
1904 { 1892 {
1907 cursor_->Apply(action); 1895 cursor_->Apply(action);
1908 1896
1909 size_t current = cursor_->GetCurrentIndex(); 1897 size_t current = cursor_->GetCurrentIndex();
1910 if (previous != current) 1898 if (previous != current)
1911 { 1899 {
1912 DisplayCurrentFrame(); 1900 Redraw();
1913 } 1901 }
1914 } 1902 }
1915 } 1903 }
1916 1904
1917 bool GetCurrentFrameOfReferenceUid(std::string& frameOfReferenceUid) const 1905 bool GetCurrentFrameOfReferenceUid(std::string& frameOfReferenceUid) const
2177 size_t current = cursor_->GetCurrentIndex(); 2165 size_t current = cursor_->GetCurrentIndex();
2178 2166
2179 if (current != cursorIndex) 2167 if (current != cursorIndex)
2180 { 2168 {
2181 cursor_->SetCurrentIndex(cursorIndex); 2169 cursor_->SetCurrentIndex(cursorIndex);
2182 DisplayCurrentFrame(); 2170 Redraw();
2183 } 2171 }
2184 2172
2185 hasFocusOnInstance_ = false; 2173 hasFocusOnInstance_ = false;
2186 } 2174 }
2187 } 2175 }
2195 if (cursor_.get() != NULL && 2183 if (cursor_.get() != NULL &&
2196 frames_.get() != NULL && 2184 frames_.get() != NULL &&
2197 frames_->FindClosestFrame(cursorIndex, p, MAX_DISTANCE)) 2185 frames_->FindClosestFrame(cursorIndex, p, MAX_DISTANCE))
2198 { 2186 {
2199 cursor_->SetCurrentIndex(cursorIndex); 2187 cursor_->SetCurrentIndex(cursorIndex);
2200 DisplayCurrentFrame(); 2188 Redraw();
2201 } 2189 }
2202 } 2190 }
2203 }; 2191 };
2204 2192
2205 2193