Mercurial > hg > orthanc-stone
comparison Samples/Sdl/Loader.cpp @ 778:78fcb907caf6
VolumeGeometryReadyMessage
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 27 May 2019 09:49:44 +0200 |
parents | 0387485f048b |
children | e72a9fef3d19 |
comparison
equal
deleted
inserted
replaced
777:7b404c853e66 | 778:78fcb907caf6 |
---|---|
219 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const = 0; | 219 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const = 0; |
220 }; | 220 }; |
221 | 221 |
222 | 222 |
223 | 223 |
224 // TODO -> Remove | 224 class VolumeGeometryReadyMessage : public OriginMessage<IVolumeSlicer> |
225 class IVolumeImageSlicer : public IVolumeSlicer | 225 { |
226 { | 226 ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); |
227 | |
228 private: | |
229 const VolumeImageGeometry& geometry_; | |
230 | |
227 public: | 231 public: |
228 virtual bool HasGeometry() const = 0; | 232 VolumeGeometryReadyMessage(const IVolumeSlicer& slicer, |
229 | 233 const VolumeImageGeometry& geometry) : |
230 virtual const VolumeImageGeometry& GetGeometry() const = 0; | 234 OriginMessage(slicer), |
235 geometry_(geometry) | |
236 { | |
237 } | |
238 | |
239 const VolumeImageGeometry& GetGeometry() const | |
240 { | |
241 return geometry_; | |
242 } | |
231 }; | 243 }; |
232 | 244 |
245 | |
233 | 246 |
234 class InvalidExtractedSlice : public IVolumeSlicer::ExtractedSlice | 247 class InvalidExtractedSlice : public IVolumeSlicer::ExtractedSlice |
235 { | 248 { |
236 public: | 249 public: |
237 virtual bool IsValid() | 250 virtual bool IsValid() |
664 }; | 677 }; |
665 | 678 |
666 | 679 |
667 | 680 |
668 class OrthancSeriesVolumeProgressiveLoader : | 681 class OrthancSeriesVolumeProgressiveLoader : |
669 public IObserver | 682 public IObserver, |
683 public IObservable, | |
684 public IVolumeSlicer | |
670 { | 685 { |
671 private: | 686 private: |
672 static const unsigned int LOW_QUALITY = 0; | 687 static const unsigned int LOW_QUALITY = 0; |
673 static const unsigned int MIDDLE_QUALITY = 1; | 688 static const unsigned int MIDDLE_QUALITY = 1; |
674 static const unsigned int BEST_QUALITY = 2; | 689 static const unsigned int BEST_QUALITY = 2; |
751 CoordinateSystem3D geometry = instance->GetGeometry(); | 766 CoordinateSystem3D geometry = instance->GetGeometry(); |
752 slices.AddSlice(geometry, instance.release()); | 767 slices.AddSlice(geometry, instance.release()); |
753 } | 768 } |
754 | 769 |
755 volume_.SetGeometry(slices); | 770 volume_.SetGeometry(slices); |
771 | |
772 BroadcastMessage(VolumeGeometryReadyMessage(*this, volume_.GetGeometry())); | |
756 } | 773 } |
757 | 774 |
758 if (volume_.GetSlicesCount() != 0) | 775 if (volume_.GetSlicesCount() != 0) |
759 { | 776 { |
760 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter( | 777 strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter( |
809 | 826 |
810 std::auto_ptr<IFetchingItemsSorter::IFactory> sorter_; | 827 std::auto_ptr<IFetchingItemsSorter::IFactory> sorter_; |
811 std::auto_ptr<IFetchingStrategy> strategy_; | 828 std::auto_ptr<IFetchingStrategy> strategy_; |
812 | 829 |
813 | 830 |
814 IVolumeSlicer::ExtractedSlice* ExtractOrthogonalSlice(const CoordinateSystem3D& cuttingPlane) const | |
815 { | |
816 if (volume_.HasGeometry() && | |
817 volume_.GetSlicesCount() != 0) | |
818 { | |
819 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice | |
820 (new DicomSeriesVolumeImage::ExtractedOrthogonalSlice(volume_, cuttingPlane)); | |
821 | |
822 assert(slice.get() != NULL && | |
823 strategy_.get() != NULL); | |
824 | |
825 if (slice->IsValid() && | |
826 slice->GetProjection() == VolumeProjection_Axial) | |
827 { | |
828 strategy_->SetCurrent(slice->GetSliceIndex()); | |
829 } | |
830 | |
831 return slice.release(); | |
832 } | |
833 else | |
834 { | |
835 return new InvalidExtractedSlice; | |
836 } | |
837 } | |
838 | |
839 | |
840 public: | 831 public: |
841 class MPRSlicer : public IVolumeImageSlicer | |
842 { | |
843 private: | |
844 boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> that_; | |
845 | |
846 public: | |
847 MPRSlicer(const boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader>& that) : | |
848 that_(that) | |
849 { | |
850 } | |
851 | |
852 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | |
853 { | |
854 return that_->ExtractOrthogonalSlice(cuttingPlane); | |
855 } | |
856 | |
857 virtual bool HasGeometry() const | |
858 { | |
859 return that_->GetVolume().HasGeometry(); | |
860 } | |
861 | |
862 virtual const VolumeImageGeometry& GetGeometry() const | |
863 { | |
864 return that_->GetVolume().GetGeometry(); | |
865 } | |
866 }; | |
867 | |
868 OrthancSeriesVolumeProgressiveLoader(IOracle& oracle, | 832 OrthancSeriesVolumeProgressiveLoader(IOracle& oracle, |
869 IObservable& oracleObservable) : | 833 IObservable& oracleObservable) : |
870 IObserver(oracleObservable.GetBroker()), | 834 IObserver(oracleObservable.GetBroker()), |
835 IObservable(oracleObservable.GetBroker()), | |
871 oracle_(oracle), | 836 oracle_(oracle), |
872 active_(false), | 837 active_(false), |
873 simultaneousDownloads_(4), | 838 simultaneousDownloads_(4), |
874 sorter_(new BasicFetchingItemsSorter::Factory) | 839 sorter_(new BasicFetchingItemsSorter::Factory) |
875 { | 840 { |
922 | 887 |
923 const DicomSeriesVolumeImage& GetVolume() const | 888 const DicomSeriesVolumeImage& GetVolume() const |
924 { | 889 { |
925 return volume_; | 890 return volume_; |
926 } | 891 } |
892 | |
893 | |
894 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | |
895 { | |
896 if (volume_.HasGeometry() && | |
897 volume_.GetSlicesCount() != 0) | |
898 { | |
899 std::auto_ptr<DicomVolumeImageOrthogonalSlice> slice | |
900 (new DicomSeriesVolumeImage::ExtractedOrthogonalSlice(volume_, cuttingPlane)); | |
901 | |
902 assert(slice.get() != NULL && | |
903 strategy_.get() != NULL); | |
904 | |
905 if (slice->IsValid() && | |
906 slice->GetProjection() == VolumeProjection_Axial) | |
907 { | |
908 strategy_->SetCurrent(slice->GetSliceIndex()); | |
909 } | |
910 | |
911 return slice.release(); | |
912 } | |
913 else | |
914 { | |
915 return new InvalidExtractedSlice; | |
916 } | |
917 } | |
927 }; | 918 }; |
928 | 919 |
929 | 920 |
930 | 921 |
931 class OrthancMultiframeVolumeLoader : public IObserver | 922 class OrthancMultiframeVolumeLoader : |
923 public IObserver, | |
924 public IObservable, | |
925 public IVolumeSlicer | |
932 { | 926 { |
933 private: | 927 private: |
934 class State : public Orthanc::IDynamicObject | 928 class State : public Orthanc::IDynamicObject |
935 { | 929 { |
936 private: | 930 private: |
1174 image_.reset(new ImageBuffer3D(format, width, height, depth, | 1168 image_.reset(new ImageBuffer3D(format, width, height, depth, |
1175 false /* don't compute range */)); | 1169 false /* don't compute range */)); |
1176 image_->Clear(); | 1170 image_->Clear(); |
1177 | 1171 |
1178 ScheduleFrameDownloads(); | 1172 ScheduleFrameDownloads(); |
1173 | |
1174 BroadcastMessage(VolumeGeometryReadyMessage(*this, *geometry_)); | |
1179 } | 1175 } |
1180 | 1176 |
1181 | 1177 |
1182 ORTHANC_FORCE_INLINE | 1178 ORTHANC_FORCE_INLINE |
1183 static void CopyPixel(uint32_t& target, | 1179 static void CopyPixel(uint32_t& target, |
1279 } | 1275 } |
1280 }; | 1276 }; |
1281 | 1277 |
1282 | 1278 |
1283 public: | 1279 public: |
1284 class MPRSlicer : public IVolumeImageSlicer | |
1285 { | |
1286 private: | |
1287 boost::shared_ptr<OrthancMultiframeVolumeLoader> that_; | |
1288 | |
1289 public: | |
1290 MPRSlicer(const boost::shared_ptr<OrthancMultiframeVolumeLoader>& that) : | |
1291 that_(that) | |
1292 { | |
1293 } | |
1294 | |
1295 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | |
1296 { | |
1297 if (that_->HasGeometry()) | |
1298 { | |
1299 return new ExtractedOrthogonalSlice(*that_, cuttingPlane); | |
1300 } | |
1301 else | |
1302 { | |
1303 return new InvalidExtractedSlice; | |
1304 } | |
1305 } | |
1306 | |
1307 virtual bool HasGeometry() const | |
1308 { | |
1309 return that_->HasGeometry(); | |
1310 } | |
1311 | |
1312 virtual const VolumeImageGeometry& GetGeometry() const | |
1313 { | |
1314 return that_->GetGeometry(); | |
1315 } | |
1316 }; | |
1317 | |
1318 | |
1319 OrthancMultiframeVolumeLoader(IOracle& oracle, | 1280 OrthancMultiframeVolumeLoader(IOracle& oracle, |
1320 IObservable& oracleObservable) : | 1281 IObservable& oracleObservable) : |
1321 IObserver(oracleObservable.GetBroker()), | 1282 IObserver(oracleObservable.GetBroker()), |
1283 IObservable(oracleObservable.GetBroker()), | |
1322 oracle_(oracle), | 1284 oracle_(oracle), |
1323 active_(false), | 1285 active_(false), |
1324 revision_(0) | 1286 revision_(0) |
1325 { | 1287 { |
1326 oracleObservable.RegisterObserverCallback( | 1288 oracleObservable.RegisterObserverCallback( |
1399 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 1361 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
1400 command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax"); | 1362 command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax"); |
1401 command->SetPayload(new LoadTransferSyntax(*this)); | 1363 command->SetPayload(new LoadTransferSyntax(*this)); |
1402 oracle_.Schedule(*this, command.release()); | 1364 oracle_.Schedule(*this, command.release()); |
1403 } | 1365 } |
1366 } | |
1367 } | |
1368 | |
1369 | |
1370 virtual ExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) const | |
1371 { | |
1372 if (HasGeometry()) | |
1373 { | |
1374 return new ExtractedOrthogonalSlice(*this, cuttingPlane); | |
1375 } | |
1376 else | |
1377 { | |
1378 return new InvalidExtractedSlice; | |
1404 } | 1379 } |
1405 } | 1380 } |
1406 }; | 1381 }; |
1407 | 1382 |
1408 | 1383 |
1428 } | 1403 } |
1429 | 1404 |
1430 public: | 1405 public: |
1431 VolumeSceneLayerSource(Scene2D& scene, | 1406 VolumeSceneLayerSource(Scene2D& scene, |
1432 int layerDepth, | 1407 int layerDepth, |
1433 IVolumeSlicer* slicer) : // Takes ownership | 1408 const boost::shared_ptr<IVolumeSlicer>& slicer) : |
1434 scene_(scene), | 1409 scene_(scene), |
1435 layerDepth_(layerDepth), | 1410 layerDepth_(layerDepth), |
1436 slicer_(slicer) | 1411 slicer_(slicer) |
1437 { | 1412 { |
1438 if (slicer == NULL) | 1413 if (slicer == NULL) |
1610 | 1585 |
1611 | 1586 |
1612 class Toto : public OrthancStone::IObserver | 1587 class Toto : public OrthancStone::IObserver |
1613 { | 1588 { |
1614 private: | 1589 private: |
1615 OrthancStone::IOracle& oracle_; | 1590 OrthancStone::CoordinateSystem3D plane_; |
1591 OrthancStone::IOracle& oracle_; | |
1616 OrthancStone::Scene2D scene_; | 1592 OrthancStone::Scene2D scene_; |
1617 std::auto_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_; | 1593 std::auto_ptr<OrthancStone::VolumeSceneLayerSource> source1_, source2_; |
1618 | 1594 |
1595 | |
1596 void Handle(const OrthancStone::VolumeGeometryReadyMessage& message) | |
1597 { | |
1598 printf("Geometry ready\n"); | |
1599 | |
1600 if (&source1_->GetSlicer() == &message.GetOrigin()) | |
1601 { | |
1602 //plane_ = message.GetGeometry().GetSagittalGeometry(); | |
1603 //plane_ = message.GetGeometry().GetAxialGeometry(); | |
1604 plane_ = message.GetGeometry().GetCoronalGeometry(); | |
1605 plane_.SetOrigin(message.GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); | |
1606 } | |
1607 } | |
1619 | 1608 |
1620 OrthancStone::CoordinateSystem3D GetSamplePlane | |
1621 (const OrthancStone::VolumeSceneLayerSource& source) const | |
1622 { | |
1623 const OrthancStone::IVolumeImageSlicer& slicer = | |
1624 dynamic_cast<const OrthancStone::IVolumeImageSlicer&>(source.GetSlicer()); | |
1625 | |
1626 OrthancStone::CoordinateSystem3D plane; | |
1627 | |
1628 if (slicer.HasGeometry()) | |
1629 { | |
1630 //plane = slicer.GetGeometry().GetSagittalGeometry(); | |
1631 //plane = slicer.GetGeometry().GetAxialGeometry(); | |
1632 plane = slicer.GetGeometry().GetCoronalGeometry(); | |
1633 plane.SetOrigin(slicer.GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); | |
1634 } | |
1635 | |
1636 return plane; | |
1637 } | |
1638 | 1609 |
1639 | |
1640 void Handle(const OrthancStone::SleepOracleCommand::TimeoutMessage& message) | 1610 void Handle(const OrthancStone::SleepOracleCommand::TimeoutMessage& message) |
1641 { | 1611 { |
1642 if (message.GetOrigin().HasPayload()) | 1612 if (message.GetOrigin().HasPayload()) |
1643 { | 1613 { |
1644 printf("TIMEOUT! %d\n", dynamic_cast<const Orthanc::SingleValueObject<unsigned int>& >(message.GetOrigin().GetPayload()).GetValue()); | 1614 printf("TIMEOUT! %d\n", dynamic_cast<const Orthanc::SingleValueObject<unsigned int>& >(message.GetOrigin().GetPayload()).GetValue()); |
1645 } | 1615 } |
1646 else | 1616 else |
1647 { | 1617 { |
1648 printf("TIMEOUT\n"); | 1618 printf("TIMEOUT\n"); |
1649 | 1619 |
1650 OrthancStone::CoordinateSystem3D plane; | |
1651 | |
1652 if (source1_.get() != NULL) | 1620 if (source1_.get() != NULL) |
1653 { | 1621 { |
1654 plane = GetSamplePlane(*source1_); | 1622 source1_->Update(plane_); |
1655 } | |
1656 else if (source2_.get() != NULL) | |
1657 { | |
1658 plane = GetSamplePlane(*source2_); | |
1659 } | |
1660 | |
1661 if (source1_.get() != NULL) | |
1662 { | |
1663 source1_->Update(plane); | |
1664 } | 1623 } |
1665 | 1624 |
1666 if (source2_.get() != NULL) | 1625 if (source2_.get() != NULL) |
1667 { | 1626 { |
1668 source2_->Update(plane); | 1627 source2_->Update(plane_); |
1669 } | 1628 } |
1670 | 1629 |
1671 scene_.FitContent(1024, 768); | 1630 scene_.FitContent(1024, 768); |
1672 | 1631 |
1673 { | 1632 { |
1759 (new OrthancStone::Callable | 1718 (new OrthancStone::Callable |
1760 <Toto, OrthancStone::OracleCommandExceptionMessage>(*this, &Toto::Handle)); | 1719 <Toto, OrthancStone::OracleCommandExceptionMessage>(*this, &Toto::Handle)); |
1761 } | 1720 } |
1762 | 1721 |
1763 void SetVolume1(int depth, | 1722 void SetVolume1(int depth, |
1764 OrthancStone::IVolumeSlicer* volume, | 1723 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, |
1765 OrthancStone::ILayerStyleConfigurator* style) | 1724 OrthancStone::ILayerStyleConfigurator* style) |
1766 { | 1725 { |
1726 dynamic_cast<OrthancStone::IObservable&>(*volume).RegisterObserverCallback | |
1727 (new OrthancStone::Callable | |
1728 <Toto, OrthancStone::VolumeGeometryReadyMessage>(*this, &Toto::Handle)); | |
1729 | |
1767 source1_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | 1730 source1_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); |
1768 | 1731 |
1769 if (style != NULL) | 1732 if (style != NULL) |
1770 { | 1733 { |
1771 source1_->SetConfigurator(style); | 1734 source1_->SetConfigurator(style); |
1772 } | 1735 } |
1773 } | 1736 } |
1774 | 1737 |
1775 void SetVolume2(int depth, | 1738 void SetVolume2(int depth, |
1776 OrthancStone::IVolumeSlicer* volume, | 1739 const boost::shared_ptr<OrthancStone::IVolumeSlicer>& volume, |
1777 OrthancStone::ILayerStyleConfigurator* style) | 1740 OrthancStone::ILayerStyleConfigurator* style) |
1778 { | 1741 { |
1742 dynamic_cast<OrthancStone::IObservable&>(*volume).RegisterObserverCallback | |
1743 (new OrthancStone::Callable | |
1744 <Toto, OrthancStone::VolumeGeometryReadyMessage>(*this, &Toto::Handle)); | |
1745 | |
1779 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); | 1746 source2_.reset(new OrthancStone::VolumeSceneLayerSource(scene_, depth, volume)); |
1780 | 1747 |
1781 if (style != NULL) | 1748 if (style != NULL) |
1782 { | 1749 { |
1783 source2_->SetConfigurator(style); | 1750 source2_->SetConfigurator(style); |
1799 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); | 1766 loader1.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); |
1800 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); | 1767 loader2.reset(new OrthancStone::OrthancSeriesVolumeProgressiveLoader(oracle, lock.GetOracleObservable())); |
1801 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable())); | 1768 loader3.reset(new OrthancStone::OrthancMultiframeVolumeLoader(oracle, lock.GetOracleObservable())); |
1802 } | 1769 } |
1803 | 1770 |
1771 toto->SetVolume1(0, loader1, new OrthancStone::GrayscaleStyleConfigurator); | |
1772 toto->SetVolume2(1, loader3, new OrthancStone::LookupTableStyleConfigurator); | |
1773 | |
1804 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100)); | 1774 oracle.Schedule(*toto, new OrthancStone::SleepOracleCommand(100)); |
1805 | 1775 |
1806 if (0) | 1776 if (0) |
1807 { | 1777 { |
1808 Json::Value v = Json::objectValue; | 1778 Json::Value v = Json::objectValue; |
1888 // Delphine | 1858 // Delphine |
1889 //loader1->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT | 1859 //loader1->LoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // CT |
1890 //loader1->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm | 1860 //loader1->LoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); // Lung 1/10mm |
1891 | 1861 |
1892 | 1862 |
1893 toto->SetVolume2(1, new OrthancStone::OrthancMultiframeVolumeLoader::MPRSlicer(loader3), | 1863 { |
1894 new OrthancStone::LookupTableStyleConfigurator); | 1864 LOG(WARNING) << "...Waiting for Ctrl-C..."; |
1895 toto->SetVolume1(0, new OrthancStone::OrthancSeriesVolumeProgressiveLoader::MPRSlicer(loader1), | 1865 |
1896 new OrthancStone::GrayscaleStyleConfigurator); | |
1897 | |
1898 { | |
1899 oracle.Start(); | 1866 oracle.Start(); |
1900 | 1867 |
1901 LOG(WARNING) << "...Waiting for Ctrl-C..."; | |
1902 Orthanc::SystemToolbox::ServerBarrier(); | 1868 Orthanc::SystemToolbox::ServerBarrier(); |
1903 | 1869 |
1904 /** | 1870 /** |
1905 * WARNING => The oracle must be stopped BEFORE the objects using | 1871 * WARNING => The oracle must be stopped BEFORE the objects using |
1906 * it are destroyed!!! This forces to wait for the completion of | 1872 * it are destroyed!!! This forces to wait for the completion of |
1922 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows | 1888 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows |
1923 **/ | 1889 **/ |
1924 int main(int argc, char* argv[]) | 1890 int main(int argc, char* argv[]) |
1925 { | 1891 { |
1926 OrthancStone::StoneInitialize(); | 1892 OrthancStone::StoneInitialize(); |
1927 Orthanc::Logging::EnableInfoLevel(true); | 1893 //Orthanc::Logging::EnableInfoLevel(true); |
1928 | 1894 |
1929 try | 1895 try |
1930 { | 1896 { |
1931 OrthancStone::NativeApplicationContext context; | 1897 OrthancStone::NativeApplicationContext context; |
1932 | 1898 |