Mercurial > hg > orthanc-stone
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 |