Mercurial > hg > orthanc-stone
comparison Samples/Sdl/Loader.cpp @ 711:70d1c28560b3
simplification
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 20 May 2019 13:40:23 +0200 |
parents | 3046a603eebf |
children | f334b098b243 |
comparison
equal
deleted
inserted
replaced
710:3046a603eebf | 711:70d1c28560b3 |
---|---|
1403 | 1403 |
1404 | 1404 |
1405 class VolumeSeriesOrthancLoader : public OrthancStone::IObserver | 1405 class VolumeSeriesOrthancLoader : public OrthancStone::IObserver |
1406 { | 1406 { |
1407 private: | 1407 private: |
1408 class MessageHandler : public Orthanc::IDynamicObject | 1408 static const unsigned int LOW_QUALITY = 0; |
1409 { | 1409 static const unsigned int MIDDLE_QUALITY = 1; |
1410 public: | 1410 static const unsigned int BEST_QUALITY = 2; |
1411 virtual void Handle(const Json::Value& body) const | 1411 |
1412 { | 1412 |
1413 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 1413 static unsigned int GetSliceIndexPayload(const OracleCommandWithPayload& command) |
1414 } | 1414 { |
1415 | 1415 return dynamic_cast< const Orthanc::SingleValueObject<unsigned int>& >(command.GetPayload()).GetValue(); |
1416 virtual void Handle(const Orthanc::ImageAccessor& image, | |
1417 unsigned int quality) const | |
1418 { | |
1419 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
1420 } | |
1421 }; | |
1422 | |
1423 void Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
1424 { | |
1425 Json::Value body; | |
1426 message.ParseJsonBody(body); | |
1427 | |
1428 if (body.type() != Json::objectValue) | |
1429 { | |
1430 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
1431 } | |
1432 | |
1433 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(body); | |
1434 } | |
1435 | |
1436 void Handle(const Refactoring::GetOrthancImageCommand::SuccessMessage& message) | |
1437 { | |
1438 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage(), 2 /* best quality */); | |
1439 } | |
1440 | |
1441 void Handle(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | |
1442 { | |
1443 unsigned int quality; | |
1444 | |
1445 switch (message.GetOrigin().GetQuality()) | |
1446 { | |
1447 case 50: | |
1448 quality = 0; | |
1449 break; | |
1450 | |
1451 case 95: | |
1452 quality = 1; | |
1453 break; | |
1454 | |
1455 default: | |
1456 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1457 } | |
1458 | |
1459 dynamic_cast<const MessageHandler&>(message.GetOrigin().GetPayload()).Handle(message.GetImage(), quality); | |
1460 } | |
1461 | |
1462 | |
1463 class LoadSliceImage : public MessageHandler | |
1464 { | |
1465 private: | |
1466 VolumeSeriesOrthancLoader& that_; | |
1467 size_t slice_; | |
1468 | |
1469 public: | |
1470 LoadSliceImage(VolumeSeriesOrthancLoader& that, | |
1471 size_t slice) : | |
1472 that_(that), | |
1473 slice_(slice) | |
1474 { | |
1475 } | |
1476 | |
1477 virtual void Handle(const Orthanc::ImageAccessor& image, | |
1478 unsigned int quality) const | |
1479 { | |
1480 that_.SetSliceContent(slice_, image, quality); | |
1481 } | |
1482 }; | |
1483 | |
1484 | |
1485 class LoadSeriesGeometryHandler : public MessageHandler | |
1486 { | |
1487 private: | |
1488 VolumeSeriesOrthancLoader& that_; | |
1489 | |
1490 public: | |
1491 LoadSeriesGeometryHandler(VolumeSeriesOrthancLoader& that) : | |
1492 that_(that) | |
1493 { | |
1494 } | |
1495 | |
1496 virtual void Handle(const Json::Value& body) const | |
1497 { | |
1498 that_.SetGeometry(body); | |
1499 } | |
1500 }; | |
1501 | |
1502 | |
1503 void SetGeometry(const Json::Value& body) | |
1504 { | |
1505 { | |
1506 Json::Value::Members instances = body.getMemberNames(); | |
1507 | |
1508 OrthancStone::SlicesSorter slices; | |
1509 | |
1510 for (size_t i = 0; i < instances.size(); i++) | |
1511 { | |
1512 Orthanc::DicomMap dicom; | |
1513 dicom.FromDicomAsJson(body[instances[i]]); | |
1514 | |
1515 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom)); | |
1516 instance->SetOrthancInstanceIdentifier(instances[i]); | |
1517 | |
1518 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry(); | |
1519 slices.AddSlice(geometry, instance.release()); | |
1520 } | |
1521 | |
1522 volume_.SetGeometry(slices); | |
1523 } | |
1524 | |
1525 if (volume_.GetSlicesCount() != 0) | |
1526 { | |
1527 strategy_.reset(new OrthancStone::BasicFetchingStrategy( | |
1528 new OrthancStone::BasicFetchingItemsSorter(volume_.GetSlicesCount()), 2)); | |
1529 | |
1530 for (unsigned int i = 0; i < 4; i++) // Schedule up to 4 simultaneous downloads (TODO - parameter) | |
1531 { | |
1532 ScheduleNextSliceDownload(); | |
1533 } | |
1534 } | |
1535 } | 1416 } |
1536 | 1417 |
1537 | 1418 |
1538 void ScheduleNextSliceDownload() | 1419 void ScheduleNextSliceDownload() |
1539 { | 1420 { |
1541 | 1422 |
1542 unsigned int sliceIndex, quality; | 1423 unsigned int sliceIndex, quality; |
1543 | 1424 |
1544 if (strategy_->GetNext(sliceIndex, quality)) | 1425 if (strategy_->GetNext(sliceIndex, quality)) |
1545 { | 1426 { |
1546 assert(quality <= 2); | 1427 assert(quality <= BEST_QUALITY); |
1547 | 1428 |
1548 const DicomInstanceParameters& slice = volume_.GetSliceParameters(sliceIndex); | 1429 const DicomInstanceParameters& slice = volume_.GetSliceParameters(sliceIndex); |
1549 | 1430 |
1550 const std::string& instance = slice.GetOrthancInstanceIdentifier(); | 1431 const std::string& instance = slice.GetOrthancInstanceIdentifier(); |
1551 if (instance.empty()) | 1432 if (instance.empty()) |
1552 { | 1433 { |
1553 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | 1434 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
1554 } | 1435 } |
1555 | 1436 |
1556 std::auto_ptr<Refactoring::IOracleCommand> command; | 1437 std::auto_ptr<Refactoring::OracleCommandWithPayload> command; |
1557 | 1438 |
1558 if (quality == 2) // Best quality | 1439 if (quality == BEST_QUALITY) |
1559 { | 1440 { |
1560 std::auto_ptr<Refactoring::GetOrthancImageCommand> tmp( | 1441 std::auto_ptr<Refactoring::GetOrthancImageCommand> tmp( |
1561 new Refactoring::GetOrthancImageCommand); | 1442 new Refactoring::GetOrthancImageCommand); |
1562 tmp->SetHttpHeader("Accept-Encoding", "gzip"); | 1443 tmp->SetHttpHeader("Accept-Encoding", "gzip"); |
1563 tmp->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam))); | 1444 tmp->SetHttpHeader("Accept", std::string(Orthanc::EnumerationToString(Orthanc::MimeType_Pam))); |
1564 tmp->SetInstanceUri(instance, slice.GetExpectedPixelFormat()); | 1445 tmp->SetInstanceUri(instance, slice.GetExpectedPixelFormat()); |
1565 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); | 1446 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); |
1566 tmp->SetPayload(new LoadSliceImage(*this, sliceIndex)); | |
1567 command.reset(tmp.release()); | 1447 command.reset(tmp.release()); |
1568 } | 1448 } |
1569 else | 1449 else |
1570 { | 1450 { |
1571 std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> tmp( | 1451 std::auto_ptr<Refactoring::GetOrthancWebViewerJpegCommand> tmp( |
1572 new Refactoring::GetOrthancWebViewerJpegCommand); | 1452 new Refactoring::GetOrthancWebViewerJpegCommand); |
1573 tmp->SetHttpHeader("Accept-Encoding", "gzip"); | 1453 tmp->SetHttpHeader("Accept-Encoding", "gzip"); |
1574 tmp->SetInstance(instance); | 1454 tmp->SetInstance(instance); |
1575 tmp->SetQuality((quality == 0 ? 50 : 95)); | 1455 tmp->SetQuality((quality == 0 ? 50 : 95)); |
1576 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); | 1456 tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat()); |
1577 tmp->SetPayload(new LoadSliceImage(*this, sliceIndex)); | |
1578 command.reset(tmp.release()); | 1457 command.reset(tmp.release()); |
1579 } | 1458 } |
1580 | 1459 |
1460 command->SetPayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex)); | |
1581 oracle_.Schedule(*this, command.release()); | 1461 oracle_.Schedule(*this, command.release()); |
1582 } | 1462 } |
1583 } | 1463 } |
1584 | 1464 |
1585 | 1465 |
1586 void SetSliceContent(unsigned int sliceIndex, | 1466 void LoadGeometry(const OrthancRestApiCommand::SuccessMessage& message) |
1587 const Orthanc::ImageAccessor& image, | 1467 { |
1588 unsigned int quality) | 1468 Json::Value body; |
1589 { | 1469 message.ParseJsonBody(body); |
1590 assert(quality <= 2); | |
1591 | 1470 |
1592 volume_.SetSliceContent(sliceIndex, image, quality); | 1471 if (body.type() != Json::objectValue) |
1472 { | |
1473 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); | |
1474 } | |
1475 | |
1476 { | |
1477 Json::Value::Members instances = body.getMemberNames(); | |
1478 | |
1479 OrthancStone::SlicesSorter slices; | |
1480 | |
1481 for (size_t i = 0; i < instances.size(); i++) | |
1482 { | |
1483 Orthanc::DicomMap dicom; | |
1484 dicom.FromDicomAsJson(body[instances[i]]); | |
1485 | |
1486 std::auto_ptr<DicomInstanceParameters> instance(new DicomInstanceParameters(dicom)); | |
1487 instance->SetOrthancInstanceIdentifier(instances[i]); | |
1488 | |
1489 OrthancStone::CoordinateSystem3D geometry = instance->GetGeometry(); | |
1490 slices.AddSlice(geometry, instance.release()); | |
1491 } | |
1492 | |
1493 volume_.SetGeometry(slices); | |
1494 } | |
1495 | |
1496 if (volume_.GetSlicesCount() != 0) | |
1497 { | |
1498 strategy_.reset(new OrthancStone::BasicFetchingStrategy( | |
1499 new OrthancStone::BasicFetchingItemsSorter(volume_.GetSlicesCount()), BEST_QUALITY)); | |
1500 | |
1501 for (unsigned int i = 0; i < 4; i++) // Schedule up to 4 simultaneous downloads (TODO - parameter) | |
1502 { | |
1503 ScheduleNextSliceDownload(); | |
1504 } | |
1505 } | |
1506 } | |
1507 | |
1508 | |
1509 void LoadBestQualitySliceContent(const Refactoring::GetOrthancImageCommand::SuccessMessage& message) | |
1510 { | |
1511 volume_.SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), | |
1512 message.GetImage(), BEST_QUALITY); | |
1513 | |
1593 ScheduleNextSliceDownload(); | 1514 ScheduleNextSliceDownload(); |
1594 } | 1515 } |
1595 | 1516 |
1517 | |
1518 void LoadJpegSliceContent(const Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage& message) | |
1519 { | |
1520 unsigned int quality; | |
1521 | |
1522 switch (message.GetOrigin().GetQuality()) | |
1523 { | |
1524 case 50: | |
1525 quality = LOW_QUALITY; | |
1526 break; | |
1527 | |
1528 case 90: | |
1529 quality = MIDDLE_QUALITY; | |
1530 break; | |
1531 | |
1532 default: | |
1533 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1534 } | |
1535 | |
1536 volume_.SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality); | |
1537 | |
1538 ScheduleNextSliceDownload(); | |
1539 } | |
1540 | |
1596 | 1541 |
1597 IOracle& oracle_; | 1542 IOracle& oracle_; |
1598 bool active_; | 1543 bool active_; |
1599 DicomVolumeImage volume_; | 1544 DicomVolumeImage volume_; |
1600 | 1545 |
1607 oracle_(oracle), | 1552 oracle_(oracle), |
1608 active_(false) | 1553 active_(false) |
1609 { | 1554 { |
1610 oracleObservable.RegisterObserverCallback( | 1555 oracleObservable.RegisterObserverCallback( |
1611 new OrthancStone::Callable<VolumeSeriesOrthancLoader, OrthancRestApiCommand::SuccessMessage> | 1556 new OrthancStone::Callable<VolumeSeriesOrthancLoader, OrthancRestApiCommand::SuccessMessage> |
1612 (*this, &VolumeSeriesOrthancLoader::Handle)); | 1557 (*this, &VolumeSeriesOrthancLoader::LoadGeometry)); |
1613 | 1558 |
1614 oracleObservable.RegisterObserverCallback( | 1559 oracleObservable.RegisterObserverCallback( |
1615 new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancImageCommand::SuccessMessage> | 1560 new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancImageCommand::SuccessMessage> |
1616 (*this, &VolumeSeriesOrthancLoader::Handle)); | 1561 (*this, &VolumeSeriesOrthancLoader::LoadBestQualitySliceContent)); |
1617 | 1562 |
1618 oracleObservable.RegisterObserverCallback( | 1563 oracleObservable.RegisterObserverCallback( |
1619 new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancWebViewerJpegCommand::SuccessMessage> | 1564 new OrthancStone::Callable<VolumeSeriesOrthancLoader, GetOrthancWebViewerJpegCommand::SuccessMessage> |
1620 (*this, &VolumeSeriesOrthancLoader::Handle)); | 1565 (*this, &VolumeSeriesOrthancLoader::LoadJpegSliceContent)); |
1621 } | 1566 } |
1622 | 1567 |
1623 void LoadSeries(const std::string& seriesId) | 1568 void LoadSeries(const std::string& seriesId) |
1624 { | 1569 { |
1625 if (active_) | 1570 if (active_) |
1629 | 1574 |
1630 active_ = true; | 1575 active_ = true; |
1631 | 1576 |
1632 std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand); | 1577 std::auto_ptr<Refactoring::OrthancRestApiCommand> command(new Refactoring::OrthancRestApiCommand); |
1633 command->SetUri("/series/" + seriesId + "/instances-tags"); | 1578 command->SetUri("/series/" + seriesId + "/instances-tags"); |
1634 command->SetPayload(new LoadSeriesGeometryHandler(*this)); | |
1635 | 1579 |
1636 oracle_.Schedule(*this, command.release()); | 1580 oracle_.Schedule(*this, command.release()); |
1637 } | 1581 } |
1638 }; | 1582 }; |
1639 | 1583 |
1662 } | 1606 } |
1663 #endif | 1607 #endif |
1664 | 1608 |
1665 | 1609 |
1666 /* class VolumeSlicerBase : public IVolumeSlicer | 1610 /* class VolumeSlicerBase : public IVolumeSlicer |
1667 { | 1611 { |
1668 private: | 1612 private: |
1669 OrthancStone::Scene2D& scene_; | 1613 OrthancStone::Scene2D& scene_; |
1670 int layerDepth_; | 1614 int layerDepth_; |
1671 bool first_; | 1615 bool first_; |
1672 OrthancStone::CoordinateSystem3D lastPlane_; | 1616 OrthancStone::CoordinateSystem3D lastPlane_; |
1673 | 1617 |
1674 protected: | 1618 protected: |
1675 bool HasViewportPlaneChanged(const OrthancStone::CoordinateSystem3D& plane) const | 1619 bool HasViewportPlaneChanged(const OrthancStone::CoordinateSystem3D& plane) const |
1676 { | 1620 { |
1677 if (first_ || | 1621 if (first_ || |
1678 !OrthancStone::LinearAlgebra::IsCloseToZero( | 1622 !OrthancStone::LinearAlgebra::IsCloseToZero( |
1679 boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal()))) | 1623 boost::numeric::ublas::norm_2(lastPlane_.GetNormal() - plane.GetNormal()))) |
1680 { | 1624 { |
1681 // This is the first rendering, or the plane has not the same orientation | 1625 // This is the first rendering, or the plane has not the same orientation |
1682 return false; | 1626 return false; |
1683 } | 1627 } |
1684 else | 1628 else |
1685 { | 1629 { |
1686 double offset1 = lastPlane_.ProjectAlongNormal(plane.GetOrigin()); | 1630 double offset1 = lastPlane_.ProjectAlongNormal(plane.GetOrigin()); |
1687 double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin()); | 1631 double offset2 = lastPlane_.ProjectAlongNormal(lastPlane_.GetOrigin()); |
1688 return OrthancStone::LinearAlgebra::IsCloseToZero(offset2 - offset1); | 1632 return OrthancStone::LinearAlgebra::IsCloseToZero(offset2 - offset1); |
1689 } | 1633 } |
1690 } | 1634 } |
1691 | 1635 |
1692 void SetLastViewportPlane(const OrthancStone::CoordinateSystem3D& plane) | 1636 void SetLastViewportPlane(const OrthancStone::CoordinateSystem3D& plane) |
1693 { | 1637 { |
1694 first_ = false; | 1638 first_ = false; |
1695 lastPlane_ = plane; | 1639 lastPlane_ = plane; |
1696 } | 1640 } |
1697 | 1641 |
1698 void SetLayer(OrthancStone::ISceneLayer* layer) | 1642 void SetLayer(OrthancStone::ISceneLayer* layer) |
1699 { | 1643 { |
1700 scene_.SetLayer(layerDepth_, layer); | 1644 scene_.SetLayer(layerDepth_, layer); |
1701 } | 1645 } |
1702 | 1646 |
1703 void DeleteLayer() | 1647 void DeleteLayer() |
1704 { | 1648 { |
1705 scene_.DeleteLayer(layerDepth_); | 1649 scene_.DeleteLayer(layerDepth_); |
1706 } | 1650 } |
1707 | 1651 |
1708 public: | 1652 public: |
1709 VolumeSlicerBase(OrthancStone::Scene2D& scene, | 1653 VolumeSlicerBase(OrthancStone::Scene2D& scene, |
1710 int layerDepth) : | 1654 int layerDepth) : |
1711 scene_(scene), | 1655 scene_(scene), |
1712 layerDepth_(layerDepth), | 1656 layerDepth_(layerDepth), |
1713 first_(true) | 1657 first_(true) |
1714 { | 1658 { |
1715 } | 1659 } |
1716 };*/ | 1660 };*/ |
1717 | 1661 |
1718 | 1662 |
1719 | 1663 |
1720 class DicomVolumeSlicer : public IVolumeSlicer | 1664 class DicomVolumeSlicer : public IVolumeSlicer |
1721 { | 1665 { |
2053 } | 1997 } |
2054 | 1998 |
2055 | 1999 |
2056 public: | 2000 public: |
2057 NativeOracle(IMessageEmitter& emitter) : | 2001 NativeOracle(IMessageEmitter& emitter) : |
2058 emitter_(emitter), | 2002 emitter_(emitter), |
2059 state_(State_Setup), | 2003 state_(State_Setup), |
2060 workers_(4) | 2004 workers_(4) |
2061 { | 2005 { |
2062 } | 2006 } |
2063 | 2007 |
2165 NativeApplicationContext& that_; | 2109 NativeApplicationContext& that_; |
2166 boost::shared_lock<boost::shared_mutex> lock_; | 2110 boost::shared_lock<boost::shared_mutex> lock_; |
2167 | 2111 |
2168 public: | 2112 public: |
2169 ReaderLock(NativeApplicationContext& that) : | 2113 ReaderLock(NativeApplicationContext& that) : |
2170 that_(that), | 2114 that_(that), |
2171 lock_(that.mutex_) | 2115 lock_(that.mutex_) |
2172 { | 2116 { |
2173 } | 2117 } |
2174 }; | 2118 }; |
2175 | 2119 |
2176 | 2120 |
2180 NativeApplicationContext& that_; | 2124 NativeApplicationContext& that_; |
2181 boost::unique_lock<boost::shared_mutex> lock_; | 2125 boost::unique_lock<boost::shared_mutex> lock_; |
2182 | 2126 |
2183 public: | 2127 public: |
2184 WriterLock(NativeApplicationContext& that) : | 2128 WriterLock(NativeApplicationContext& that) : |
2185 that_(that), | 2129 that_(that), |
2186 lock_(that.mutex_) | 2130 lock_(that.mutex_) |
2187 { | 2131 { |
2188 } | 2132 } |
2189 | 2133 |
2190 OrthancStone::MessageBroker& GetBroker() | 2134 OrthancStone::MessageBroker& GetBroker() |
2191 { | 2135 { |
2251 (new OrthancStone::Callable | 2195 (new OrthancStone::Callable |
2252 <Toto, Refactoring::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle)); | 2196 <Toto, Refactoring::GetOrthancImageCommand::SuccessMessage>(*this, &Toto::Handle)); |
2253 | 2197 |
2254 oracle.RegisterObserverCallback | 2198 oracle.RegisterObserverCallback |
2255 (new OrthancStone::Callable | 2199 (new OrthancStone::Callable |
2256 <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle)); | 2200 <Toto, Refactoring::GetOrthancWebViewerJpegCommand::SuccessMessage>(*this, &Toto::Handle)); |
2257 | 2201 |
2258 oracle.RegisterObserverCallback | 2202 oracle.RegisterObserverCallback |
2259 (new OrthancStone::Callable | 2203 (new OrthancStone::Callable |
2260 <Toto, Refactoring::OracleCommandExceptionMessage>(*this, &Toto::Handle)); | 2204 <Toto, Refactoring::OracleCommandExceptionMessage>(*this, &Toto::Handle)); |
2261 } | 2205 } |