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)