comparison Samples/Sdl/Loader.cpp @ 794:04f518ebd132

LoaderStateMachine
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 28 May 2019 12:26:16 +0200
parents f72b49954f62
children bc20e4c417ec
comparison
equal deleted inserted replaced
793:f72b49954f62 794:04f518ebd132
973 } 973 }
974 }; 974 };
975 975
976 976
977 977
978 class LoaderStateMachine : public IObserver
979 {
980 protected:
981 class State : public Orthanc::IDynamicObject
982 {
983 private:
984 LoaderStateMachine& that_;
985
986 public:
987 State(LoaderStateMachine& that) :
988 that_(that)
989 {
990 }
991
992 void Schedule(OracleCommandWithPayload* command)
993 {
994 that_.Schedule(command);
995 }
996
997 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const
998 {
999 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1000 }
1001
1002 virtual void Handle(const GetOrthancImageCommand::SuccessMessage& message) const
1003 {
1004 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1005 }
1006
1007 virtual void Handle(const GetOrthancWebViewerJpegCommand::SuccessMessage& message) const
1008 {
1009 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1010 }
1011 };
1012
1013 void Schedule(OracleCommandWithPayload* command)
1014 {
1015 std::auto_ptr<OracleCommandWithPayload> protection(command);
1016
1017 if (!command->HasPayload())
1018 {
1019 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange,
1020 "The payload must contain the next state");
1021 }
1022
1023 pendingCommands_.push_back(protection.release());
1024 }
1025
1026 void Start()
1027 {
1028 if (active_)
1029 {
1030 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1031 }
1032
1033 for (size_t i = 0; i < simultaneousDownloads_; i++)
1034 {
1035 Step();
1036 }
1037 }
1038
1039 private:
1040 void Step()
1041 {
1042 if (!pendingCommands_.empty())
1043 {
1044 oracle_.Schedule(*this, pendingCommands_.front());
1045 pendingCommands_.pop_front();
1046 }
1047 }
1048
1049 void Handle(const OrthancRestApiCommand::SuccessMessage& message)
1050 {
1051 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
1052 Step();
1053 }
1054
1055 void Handle(const GetOrthancImageCommand::SuccessMessage& message)
1056 {
1057 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
1058 Step();
1059 }
1060
1061 void Handle(const GetOrthancWebViewerJpegCommand::SuccessMessage& message)
1062 {
1063 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message);
1064 Step();
1065 }
1066
1067 typedef std::list<IOracleCommand*> PendingCommands;
1068
1069 IOracle& oracle_;
1070 bool active_;
1071 unsigned int simultaneousDownloads_;
1072 PendingCommands pendingCommands_;
1073
1074 public:
1075 LoaderStateMachine(IOracle& oracle,
1076 IObservable& oracleObservable) :
1077 IObserver(oracleObservable.GetBroker()),
1078 oracle_(oracle),
1079 active_(false),
1080 simultaneousDownloads_(4)
1081 {
1082 oracleObservable.RegisterObserverCallback(
1083 new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage>
1084 (*this, &LoaderStateMachine::Handle));
1085
1086 oracleObservable.RegisterObserverCallback(
1087 new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage>
1088 (*this, &LoaderStateMachine::Handle));
1089
1090 oracleObservable.RegisterObserverCallback(
1091 new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage>
1092 (*this, &LoaderStateMachine::Handle));
1093 }
1094
1095 virtual ~LoaderStateMachine()
1096 {
1097 for (PendingCommands::iterator it = pendingCommands_.begin();
1098 it != pendingCommands_.end(); ++it)
1099 {
1100 delete *it;
1101 }
1102 }
1103
1104 virtual void SetSimultaneousDownloads(unsigned int count)
1105 {
1106 if (active_)
1107 {
1108 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1109 }
1110 else if (count == 0)
1111 {
1112 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
1113 }
1114 else
1115 {
1116 simultaneousDownloads_ = count;
1117 }
1118 }
1119 };
1120
1121
1122
978 class OrthancMultiframeVolumeLoader : 1123 class OrthancMultiframeVolumeLoader :
979 public IObserver, 1124 public IObserver,
980 public IObservable 1125 public IObservable
981 { 1126 {
982 private: 1127 private:
1474 class DicomStructureSetLoader : 1619 class DicomStructureSetLoader :
1475 public IObserver, 1620 public IObserver,
1476 public IVolumeSlicer 1621 public IVolumeSlicer
1477 { 1622 {
1478 private: 1623 private:
1479 enum State
1480 {
1481 State_Setup,
1482 State_Loading,
1483 State_Ready
1484 };
1485
1486
1487 std::auto_ptr<DicomStructureSet> content_; 1624 std::auto_ptr<DicomStructureSet> content_;
1488 IOracle& oracle_; 1625 IOracle& oracle_;
1489 State state_; 1626 bool active_;
1627 uint64_t revision_;
1490 std::string instanceId_; 1628 std::string instanceId_;
1491 1629
1492 void Handle(const OrthancRestApiCommand::SuccessMessage& message) 1630 void Handle(const OrthancRestApiCommand::SuccessMessage& message)
1493 { 1631 {
1494 if (state_ != State_Loading) 1632 assert(active_);
1495 {
1496 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1497 }
1498
1499 const boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
1500 1633
1501 { 1634 {
1502 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); 1635 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer());
1503 content_.reset(new DicomStructureSet(dicom)); 1636 content_.reset(new DicomStructureSet(dicom));
1504 } 1637 }
1505 1638
1506 const boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time(); 1639 std::set<std::string> instances;
1507 1640 content_->GetReferencedInstances(instances);
1508 printf("LOADED: %d\n", (end - start).total_milliseconds()); 1641
1509 state_ = State_Ready; 1642 for (std::set<std::string>::const_iterator
1510 } 1643 it = instances.begin(); it != instances.end(); ++it)
1511 1644 {
1645 printf("[%s]\n", it->c_str());
1646 }
1647 }
1648
1649
1650 class Slice : public IExtractedSlice
1651 {
1652 private:
1653 const DicomStructureSet& content_;
1654 uint64_t revision_;
1655 bool isValid_;
1656
1657 public:
1658 Slice(const DicomStructureSet& content,
1659 uint64_t revision,
1660 const CoordinateSystem3D& cuttingPlane) :
1661 content_(content),
1662 revision_(revision)
1663 {
1664 bool opposite;
1665
1666 const Vector normal = content.GetNormal();
1667 isValid_ = (
1668 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) ||
1669 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisX()) ||
1670 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisY()));
1671 }
1672
1673 virtual bool IsValid()
1674 {
1675 return isValid_;
1676 }
1677
1678 virtual uint64_t GetRevision()
1679 {
1680 return revision_;
1681 }
1682
1683 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator,
1684 const CoordinateSystem3D& cuttingPlane)
1685 {
1686 assert(isValid_);
1687
1688 std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer);
1689
1690 for (size_t i = 0; i < content_.GetStructuresCount(); i++)
1691 {
1692 std::vector< std::vector<DicomStructureSet::PolygonPoint> > polygons;
1693
1694 if (content_.ProjectStructure(polygons, i, cuttingPlane))
1695 {
1696 printf(">> %d\n", polygons.size());
1697
1698 for (size_t j = 0; j < polygons.size(); j++)
1699 {
1700 PolylineSceneLayer::Chain chain;
1701 chain.resize(polygons[j].size());
1702
1703 for (size_t k = 0; k < polygons[i].size(); k++)
1704 {
1705 chain[k] = ScenePoint2D(polygons[j][k].first, polygons[j][k].second);
1706 }
1707
1708 layer->AddChain(chain, true /* closed */);
1709 }
1710 }
1711 }
1712
1713 printf("OK\n");
1714
1715 return layer.release();
1716 }
1717 };
1512 1718
1513 public: 1719 public:
1514 DicomStructureSetLoader(IOracle& oracle, 1720 DicomStructureSetLoader(IOracle& oracle,
1515 IObservable& oracleObservable) : 1721 IObservable& oracleObservable) :
1516 IObserver(oracleObservable.GetBroker()), 1722 IObserver(oracleObservable.GetBroker()),
1517 oracle_(oracle), 1723 oracle_(oracle),
1518 state_(State_Setup) 1724 active_(false),
1725 revision_(0)
1519 { 1726 {
1520 oracleObservable.RegisterObserverCallback( 1727 oracleObservable.RegisterObserverCallback(
1521 new Callable<DicomStructureSetLoader, OrthancRestApiCommand::SuccessMessage> 1728 new Callable<DicomStructureSetLoader, OrthancRestApiCommand::SuccessMessage>
1522 (*this, &DicomStructureSetLoader::Handle)); 1729 (*this, &DicomStructureSetLoader::Handle));
1523 } 1730 }
1524 1731
1525 1732
1526 void LoadInstance(const std::string& instanceId) 1733 void LoadInstance(const std::string& instanceId)
1527 { 1734 {
1528 if (state_ != State_Setup) 1735 if (active_)
1529 { 1736 {
1530 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); 1737 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
1531 } 1738 }
1532 else 1739 else
1533 { 1740 {
1534 state_ = State_Loading; 1741 active_ = true;
1535 instanceId_ = instanceId; 1742 instanceId_ = instanceId;
1536 1743
1537 { 1744 {
1538 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); 1745 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand);
1539 command->SetHttpHeader("Accept-Encoding", "gzip"); 1746 command->SetHttpHeader("Accept-Encoding", "gzip");
1543 } 1750 }
1544 } 1751 }
1545 1752
1546 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) 1753 virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane)
1547 { 1754 {
1548 return NULL; 1755 if (content_.get() == NULL)
1756 {
1757 // Geometry is not available yet
1758 return new IVolumeSlicer::InvalidSlice;
1759 }
1760 else
1761 {
1762 return new Slice(*content_, revision_, cuttingPlane);
1763 }
1549 } 1764 }
1550 }; 1765 };
1551 1766
1552 1767
1553 1768
1764 { 1979 {
1765 private: 1980 private:
1766 OrthancStone::CoordinateSystem3D plane_; 1981 OrthancStone::CoordinateSystem3D plane_;
1767 OrthancStone::IOracle& oracle_; 1982 OrthancStone::IOracle& oracle_;
1768 OrthancStone::Scene2D scene_; 1983 OrthancStone::Scene2D scene_;
1769 std::auto_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_; 1984 std::auto_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_, source3_;
1770 1985
1771 1986
1772 void Refresh() 1987 void Refresh()
1773 { 1988 {
1774 if (source1_.get() != NULL) 1989 if (source1_.get() != NULL)
1777 } 1992 }
1778 1993
1779 if (source2_.get() != NULL) 1994 if (source2_.get() != NULL)
1780 { 1995 {
1781 source2_->Update(plane_); 1996 source2_->Update(plane_);
1997 }
1998
1999 if (source3_.get() != NULL)
2000 {
2001 source3_->Update(plane_);
1782 } 2002 }
1783 2003
1784 scene_.FitContent(1024, 768); 2004 scene_.FitContent(1024, 768);
1785 2005
1786 { 2006 {
1806 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message) 2026 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message)
1807 { 2027 {
1808 printf("Geometry ready\n"); 2028 printf("Geometry ready\n");
1809 2029
1810 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); 2030 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry();
1811 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); 2031 plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry();
1812 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); 2032 //plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry();
1813 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); 2033 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f));
1814 2034
1815 Refresh(); 2035 Refresh();
1816 } 2036 }
1817 2037
1928 if (style != NULL) 2148 if (style != NULL)
1929 { 2149 {
1930 source2_->SetConfigurator(style); 2150 source2_->SetConfigurator(style);
1931 } 2151 }
1932 } 2152 }
2153
2154 void SetStructureSet(int depth,
2155 const boost::shared_ptr<OrthancStone::DicomStructureSetLoader>& volume)
2156 {
2157 source3_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume));
2158 }
2159
1933 }; 2160 };
1934 2161
1935 2162
1936 void Run(OrthancStone::NativeApplicationContext& context, 2163 void Run(OrthancStone::NativeApplicationContext& context,
1937 OrthancStone::ThreadedOracle& oracle) 2164 OrthancStone::ThreadedOracle& oracle)
1952 doseLoader.reset(new OrthancStone::OrthancMultiframeVolumeLoader(dose, oracle, lock.GetOracleObservable())); 2179 doseLoader.reset(new OrthancStone::OrthancMultiframeVolumeLoader(dose, oracle, lock.GetOracleObservable()));
1953 rtstructLoader.reset(new OrthancStone::DicomStructureSetLoader(oracle, lock.GetOracleObservable())); 2180 rtstructLoader.reset(new OrthancStone::DicomStructureSetLoader(oracle, lock.GetOracleObservable()));
1954 } 2181 }
1955 2182
1956 2183
1957 toto->SetReferenceLoader(*ctLoader); 2184 //toto->SetReferenceLoader(*ctLoader);
2185 toto->SetReferenceLoader(*doseLoader);
1958 2186
1959 2187
1960 #if 1 2188 #if 1
1961 toto->SetVolume1(0, ctLoader, new OrthancStone::GrayscaleStyleConfigurator); 2189 toto->SetVolume1(0, ctLoader, new OrthancStone::GrayscaleStyleConfigurator);
1962 #else 2190 #else
1973 2201
1974 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose)); 2202 boost::shared_ptr<OrthancStone::DicomVolumeImageMPRSlicer> tmp(new OrthancStone::DicomVolumeImageMPRSlicer(dose));
1975 toto->SetVolume2(1, tmp, config.release()); 2203 toto->SetVolume2(1, tmp, config.release());
1976 } 2204 }
1977 2205
2206 toto->SetStructureSet(2, rtstructLoader);
2207
1978 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100)); 2208 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100));
1979 2209
1980 if (0) 2210 if (0)
1981 { 2211 {
1982 Json::Value v = Json::objectValue; 2212 Json::Value v = Json::objectValue;
2052 } 2282 }
2053 } 2283 }
2054 2284
2055 2285
2056 // 2017-11-17-Anonymized 2286 // 2017-11-17-Anonymized
2057 ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT 2287 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT
2058 doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE 2288 doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE
2059 rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT 2289 rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT
2060 2290
2061 // 2015-01-28-Multiframe 2291 // 2015-01-28-Multiframe
2062 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT 2292 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT