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