Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1647:adff3cd78775
removed class FrameExtent
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 12 Nov 2020 16:57:15 +0100 |
parents | 4e14735e98f8 |
children | 4a43106bc122 |
comparison
equal
deleted
inserted
replaced
1646:4e14735e98f8 | 1647:adff3cd78775 |
---|---|
831 double& y1, | 831 double& y1, |
832 double& x2, | 832 double& x2, |
833 double& y2, | 833 double& y2, |
834 const OrthancStone::DicomInstanceParameters& instance1, | 834 const OrthancStone::DicomInstanceParameters& instance1, |
835 unsigned int frame1, | 835 unsigned int frame1, |
836 const OrthancStone::DicomInstanceParameters& instance2, | 836 const OrthancStone::CoordinateSystem3D& plane2) |
837 unsigned int frame2) | |
838 { | 837 { |
839 if (instance1.GetWidth() == 0 && | 838 if (instance1.GetWidth() == 0 && |
840 instance1.GetHeight() == 0) | 839 instance1.GetHeight() == 0) |
841 { | 840 { |
842 return false; | 841 return false; |
859 extent.AddPoint(ox, oy); | 858 extent.AddPoint(ox, oy); |
860 extent.AddPoint(ox + instance1.GetPixelSpacingX() * static_cast<double>(instance1.GetWidth()), | 859 extent.AddPoint(ox + instance1.GetPixelSpacingX() * static_cast<double>(instance1.GetWidth()), |
861 oy + instance1.GetPixelSpacingY() * static_cast<double>(instance1.GetHeight())); | 860 oy + instance1.GetPixelSpacingY() * static_cast<double>(instance1.GetHeight())); |
862 | 861 |
863 const OrthancStone::CoordinateSystem3D c1 = instance1.GetFrameGeometry(frame1); | 862 const OrthancStone::CoordinateSystem3D c1 = instance1.GetFrameGeometry(frame1); |
864 const OrthancStone::CoordinateSystem3D c2 = instance2.GetFrameGeometry(frame2); | |
865 | 863 |
866 OrthancStone::Vector direction, origin; | 864 OrthancStone::Vector direction, origin; |
867 | 865 |
868 if (!extent.IsEmpty() && | 866 if (!extent.IsEmpty() && |
869 instance1.GetFrameOfReferenceUid() == instance1.GetFrameOfReferenceUid() && | 867 instance1.GetFrameOfReferenceUid() == instance1.GetFrameOfReferenceUid() && |
870 OrthancStone::GeometryToolbox::IntersectTwoPlanes(origin, direction, | 868 OrthancStone::GeometryToolbox::IntersectTwoPlanes(origin, direction, |
871 c1.GetOrigin(), c1.GetNormal(), | 869 c1.GetOrigin(), c1.GetNormal(), |
872 c2.GetOrigin(), c2.GetNormal())) | 870 plane2.GetOrigin(), plane2.GetNormal())) |
873 { | 871 { |
874 double ax, ay, bx, by; | 872 double ax, ay, bx, by; |
875 c1.ProjectPoint(ax, ay, origin); | 873 c1.ProjectPoint(ax, ay, origin); |
876 c1.ProjectPoint(bx, by, origin + 100.0 * direction); | 874 c1.ProjectPoint(bx, by, origin + 100.0 * direction); |
877 | 875 |
885 return false; | 883 return false; |
886 } | 884 } |
887 } | 885 } |
888 } | 886 } |
889 | 887 |
890 | |
891 | |
892 class FrameExtent | |
893 { | |
894 private: | |
895 bool isValid_; | |
896 std::string frameOfReferenceUid_; | |
897 OrthancStone::CoordinateSystem3D coordinates_; | |
898 double pixelSpacingX_; | |
899 double pixelSpacingY_; | |
900 OrthancStone::Extent2D extent_; | |
901 | |
902 public: | |
903 explicit FrameExtent() : | |
904 isValid_(false), | |
905 pixelSpacingX_(1), | |
906 pixelSpacingY_(1) | |
907 { | |
908 } | |
909 | |
910 explicit FrameExtent(const Orthanc::DicomMap& tags) : | |
911 isValid_(false), | |
912 coordinates_(tags) | |
913 { | |
914 if (!tags.LookupStringValue( | |
915 frameOfReferenceUid_, Orthanc::DICOM_TAG_FRAME_OF_REFERENCE_UID, false)) | |
916 { | |
917 frameOfReferenceUid_.clear(); | |
918 } | |
919 | |
920 OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, tags); | |
921 | |
922 unsigned int rows, columns; | |
923 if (tags.HasTag(Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT) && | |
924 tags.HasTag(Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT) && | |
925 tags.ParseUnsignedInteger32(rows, Orthanc::DICOM_TAG_ROWS) && | |
926 tags.ParseUnsignedInteger32(columns, Orthanc::DICOM_TAG_COLUMNS)) | |
927 { | |
928 double ox = -pixelSpacingX_ / 2.0; | |
929 double oy = -pixelSpacingY_ / 2.0; | |
930 extent_.AddPoint(ox, oy); | |
931 extent_.AddPoint(ox + pixelSpacingX_ * static_cast<double>(columns), | |
932 oy + pixelSpacingY_ * static_cast<double>(rows)); | |
933 | |
934 isValid_ = true; | |
935 } | |
936 } | |
937 | |
938 bool IsValid() const | |
939 { | |
940 return isValid_; | |
941 } | |
942 | |
943 const std::string& GetFrameOfReferenceUid() const | |
944 { | |
945 if (isValid_) | |
946 { | |
947 return frameOfReferenceUid_; | |
948 } | |
949 else | |
950 { | |
951 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
952 } | |
953 } | |
954 | |
955 const OrthancStone::CoordinateSystem3D& GetCoordinates() const | |
956 { | |
957 if (isValid_) | |
958 { | |
959 return coordinates_; | |
960 } | |
961 else | |
962 { | |
963 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
964 } | |
965 } | |
966 | |
967 double GetPixelSpacingX() const | |
968 { | |
969 if (isValid_) | |
970 { | |
971 return pixelSpacingX_; | |
972 } | |
973 else | |
974 { | |
975 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
976 } | |
977 } | |
978 | |
979 double GetPixelSpacingY() const | |
980 { | |
981 if (isValid_) | |
982 { | |
983 return pixelSpacingY_; | |
984 } | |
985 else | |
986 { | |
987 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
988 } | |
989 } | |
990 | |
991 bool Intersect(double& x1, // Coordinates of the clipped line (out) | |
992 double& y1, | |
993 double& x2, | |
994 double& y2, | |
995 const FrameExtent& other) const | |
996 { | |
997 if (this == &other) | |
998 { | |
999 return false; | |
1000 } | |
1001 | |
1002 OrthancStone::Vector direction, origin; | |
1003 | |
1004 if (IsValid() && | |
1005 other.IsValid() && | |
1006 !extent_.IsEmpty() && | |
1007 frameOfReferenceUid_ == other.frameOfReferenceUid_ && | |
1008 OrthancStone::GeometryToolbox::IntersectTwoPlanes( | |
1009 origin, direction, | |
1010 coordinates_.GetOrigin(), coordinates_.GetNormal(), | |
1011 other.coordinates_.GetOrigin(), other.coordinates_.GetNormal())) | |
1012 { | |
1013 double ax, ay, bx, by; | |
1014 coordinates_.ProjectPoint(ax, ay, origin); | |
1015 coordinates_.ProjectPoint(bx, by, origin + 100.0 * direction); | |
1016 | |
1017 return OrthancStone::GeometryToolbox::ClipLineToRectangle( | |
1018 x1, y1, x2, y2, | |
1019 ax, ay, bx, by, | |
1020 extent_.GetX1(), extent_.GetY1(), extent_.GetX2(), extent_.GetY2()); | |
1021 } | |
1022 else | |
1023 { | |
1024 return false; | |
1025 } | |
1026 } | |
1027 | |
1028 | |
1029 bool ProjectPoint(double& x, | |
1030 double& y, | |
1031 const OrthancStone::Vector& v) const | |
1032 { | |
1033 if (IsValid()) | |
1034 { | |
1035 coordinates_.ProjectPoint(x, y, v); | |
1036 return true; | |
1037 } | |
1038 else | |
1039 { | |
1040 return false; | |
1041 } | |
1042 } | |
1043 }; | |
1044 | |
1045 | 888 |
1046 | 889 |
1047 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport> | 890 class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport> |
1048 { | 891 { |
1049 public: | 892 public: |
1373 bool inverted_; | 1216 bool inverted_; |
1374 bool flipX_; | 1217 bool flipX_; |
1375 bool flipY_; | 1218 bool flipY_; |
1376 bool fitNextContent_; | 1219 bool fitNextContent_; |
1377 bool isCtrlDown_; | 1220 bool isCtrlDown_; |
1378 FrameExtent currentFrameExtent_; | |
1379 std::list<PrefetchItem> prefetchQueue_; | 1221 std::list<PrefetchItem> prefetchQueue_; |
1380 | 1222 |
1381 | 1223 |
1382 bool hasFocusOnInstance_; | 1224 bool hasFocusOnInstance_; |
1383 std::string focusSopInstanceUid_; | 1225 std::string focusSopInstanceUid_; |
1475 else | 1317 else |
1476 { | 1318 { |
1477 quality = DisplayedFrameQuality_High; | 1319 quality = DisplayedFrameQuality_High; |
1478 } | 1320 } |
1479 | 1321 |
1480 currentFrameExtent_ = FrameExtent(frames_->GetInstanceOfFrame(index).GetTags()); | |
1481 | |
1482 { | 1322 { |
1483 // Prepare prefetching | 1323 // Prepare prefetching |
1484 prefetchQueue_.clear(); | 1324 prefetchQueue_.clear(); |
1485 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16; i++) | 1325 for (size_t i = 0; i < cursor_->GetPrefetchSize() && i < 16; i++) |
1486 { | 1326 { |
1498 { | 1338 { |
1499 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(), | 1339 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(), |
1500 frames_->GetFramesCount(), quality); | 1340 frames_->GetFramesCount(), quality); |
1501 } | 1341 } |
1502 } | 1342 } |
1503 else | |
1504 { | |
1505 currentFrameExtent_ = FrameExtent(); | |
1506 } | |
1507 } | 1343 } |
1508 | 1344 |
1509 | 1345 |
1510 void ClearViewport() | 1346 void ClearViewport() |
1511 { | 1347 { |
1597 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); | 1433 layer->SetPixelSpacing(pixelSpacingX, pixelSpacingY); |
1598 | 1434 |
1599 | 1435 |
1600 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer; | 1436 std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsLayer; |
1601 | 1437 |
1602 if (annotations_) | 1438 if (annotations_ && |
1603 { | 1439 cursor_.get() != NULL) |
1604 const FrameExtent& extent = GetCurrentFrameExtent(); | 1440 { |
1441 const OrthancStone::CoordinateSystem3D plane = frames_->GetFrameGeometry(cursor_->GetCurrentIndex()); | |
1605 | 1442 |
1606 std::set<size_t> a; | 1443 std::set<size_t> a; |
1607 annotations_->LookupSopInstanceUid(a, sopInstanceUid); | 1444 annotations_->LookupSopInstanceUid(a, sopInstanceUid); |
1608 if (extent.IsValid() && | 1445 if (plane.IsValid() && |
1609 !a.empty()) | 1446 !a.empty()) |
1610 { | 1447 { |
1611 annotationsLayer.reset(new OrthancStone::MacroSceneLayer); | 1448 annotationsLayer.reset(new OrthancStone::MacroSceneLayer); |
1612 annotationsLayer->Reserve(a.size()); | 1449 annotationsLayer->Reserve(a.size()); |
1613 | 1450 |
1615 factory.SetColor(0, 255, 0); | 1452 factory.SetColor(0, 255, 0); |
1616 | 1453 |
1617 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) | 1454 for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) |
1618 { | 1455 { |
1619 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(*it); | 1456 const OrthancStone::OsiriX::Annotation& annotation = annotations_->GetAnnotation(*it); |
1620 annotationsLayer->AddLayer(factory.Create(annotation, extent.GetCoordinates())); | 1457 annotationsLayer->AddLayer(factory.Create(annotation, plane)); |
1621 } | 1458 } |
1622 } | 1459 } |
1623 } | 1460 } |
1624 | 1461 |
1625 | 1462 |
1917 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); | 1754 LOG(INFO) << "Number of frames in series: " << frames_->GetFramesCount(); |
1918 | 1755 |
1919 ResetDefaultWindowing(); | 1756 ResetDefaultWindowing(); |
1920 ClearViewport(); | 1757 ClearViewport(); |
1921 prefetchQueue_.clear(); | 1758 prefetchQueue_.clear(); |
1922 currentFrameExtent_ = FrameExtent(); | |
1923 | 1759 |
1924 if (observer_.get() != NULL) | 1760 if (observer_.get() != NULL) |
1925 { | 1761 { |
1926 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(), | 1762 observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(), |
1927 frames_->GetFramesCount(), DisplayedFrameQuality_None); | 1763 frames_->GetFramesCount(), DisplayedFrameQuality_None); |
1997 DisplayCurrentFrame(); | 1833 DisplayCurrentFrame(); |
1998 } | 1834 } |
1999 } | 1835 } |
2000 } | 1836 } |
2001 | 1837 |
2002 const FrameExtent& GetCurrentFrameExtent() const | 1838 bool GetCurrentPlane(OrthancStone::CoordinateSystem3D& plane) const |
2003 { | 1839 { |
2004 return currentFrameExtent_; | 1840 if (cursor_.get() != NULL && |
2005 } | 1841 frames_.get() != NULL) |
2006 | 1842 { |
2007 void UpdateReferenceLines(const std::list<const FrameExtent*>& planes) | 1843 plane = frames_->GetFrameGeometry(cursor_->GetCurrentIndex()); |
1844 return true; | |
1845 } | |
1846 else | |
1847 { | |
1848 return false; | |
1849 } | |
1850 } | |
1851 | |
1852 void UpdateReferenceLines(const std::list<const ViewerViewport*>& viewports) | |
2008 { | 1853 { |
2009 std::unique_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer); | 1854 std::unique_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer); |
2010 | 1855 |
2011 if (GetCurrentFrameExtent().IsValid()) | 1856 if (cursor_.get() != NULL && |
2012 { | 1857 frames_.get() != NULL) |
2013 for (std::list<const FrameExtent*>::const_iterator | 1858 { |
2014 it = planes.begin(); it != planes.end(); ++it) | 1859 const size_t index = cursor_->GetCurrentIndex(); |
1860 const OrthancStone::DicomInstanceParameters& instance = frames_->GetInstanceOfFrame(index); | |
1861 const unsigned int frame = frames_->GetFrameNumberInInstance(index); | |
1862 | |
1863 for (std::list<const ViewerViewport*>::const_iterator | |
1864 it = viewports.begin(); it != viewports.end(); ++it) | |
2015 { | 1865 { |
2016 assert(*it != NULL); | 1866 assert(*it != NULL); |
2017 | 1867 |
2018 double x1, y1, x2, y2; | 1868 OrthancStone::CoordinateSystem3D plane; |
2019 if (GetCurrentFrameExtent().Intersect(x1, y1, x2, y2, **it)) | 1869 if ((*it)->GetCurrentPlane(plane)) |
2020 { | 1870 { |
2021 OrthancStone::PolylineSceneLayer::Chain chain; | 1871 double x1, y1, x2, y2; |
2022 chain.push_back(OrthancStone::ScenePoint2D(x1, y1)); | 1872 if (GetReferenceLineCoordinates(x1, y1, x2, y2, instance, frame, plane)) |
2023 chain.push_back(OrthancStone::ScenePoint2D(x2, y2)); | 1873 { |
2024 layer->AddChain(chain, false, 0, 255, 0); | 1874 OrthancStone::PolylineSceneLayer::Chain chain; |
1875 chain.push_back(OrthancStone::ScenePoint2D(x1, y1)); | |
1876 chain.push_back(OrthancStone::ScenePoint2D(x2, y2)); | |
1877 layer->AddChain(chain, false, 0, 255, 0); | |
1878 } | |
2025 } | 1879 } |
2026 } | 1880 } |
2027 } | 1881 } |
2028 | 1882 |
2029 { | 1883 { |
2030 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); | 1884 std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); |
2031 | 1885 |
2032 if (layer->GetChainsCount() == 0) | 1886 if (layer->GetChainsCount() == 0) |
2033 { | 1887 { |
2227 | 2081 |
2228 static void UpdateReferenceLines() | 2082 static void UpdateReferenceLines() |
2229 { | 2083 { |
2230 if (showReferenceLines_) | 2084 if (showReferenceLines_) |
2231 { | 2085 { |
2232 std::list<const FrameExtent*> planes; | 2086 std::list<const ViewerViewport*> viewports; |
2233 | 2087 |
2234 for (Viewports::const_iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) | 2088 for (Viewports::const_iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) |
2235 { | 2089 { |
2236 assert(it->second != NULL); | 2090 assert(it->second != NULL); |
2237 planes.push_back(&it->second->GetCurrentFrameExtent()); | 2091 viewports.push_back(it->second.get()); |
2238 } | 2092 } |
2239 | 2093 |
2240 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) | 2094 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) |
2241 { | 2095 { |
2242 assert(it->second != NULL); | 2096 assert(it->second != NULL); |
2243 it->second->UpdateReferenceLines(planes); | 2097 it->second->UpdateReferenceLines(viewports); |
2244 } | 2098 } |
2245 } | 2099 } |
2246 else | 2100 else |
2247 { | 2101 { |
2248 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) | 2102 for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) |