Mercurial > hg > orthanc-stone
changeset 2325:27b730ba6d4d refactoring
removed class SdlSimpleViewerApplication
| author | Sebastien Jodogne <s.jodogne@gmail.com> |
|---|---|
| date | Wed, 30 Sep 2026 20:06:19 +0200 |
| parents | fbaca52e8ecc |
| children | f5d2e4b76439 |
| files | Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewerApplication.h |
| diffstat | 2 files changed, 122 insertions(+), 231 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Wed Sep 30 18:36:20 2026 +0200 +++ b/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewer.cpp Wed Sep 30 20:06:19 2026 +0200 @@ -20,26 +20,23 @@ **/ -#include "SdlSimpleViewerApplication.h" -#include "../SdlHelpers.h" -#include "../../Common/SampleHelpers.h" - -#include "../../../../OrthancStone/Sources/Platforms/Sdl/SdlViewport.h" +#include "../../../../OrthancStone/Sources/Loaders/DicomResourcesLoader.h" +#include "../../../../OrthancStone/Sources/Loaders/SeriesFramesLoader.h" #include "../../../../OrthancStone/Sources/Scene2D/AnnotationsSceneLayer.h" -#include "../../../../OrthancStone/Sources/Scene2DViewport/AngleMeasureTool.h" -#include "../../../../OrthancStone/Sources/Scene2DViewport/LineMeasureTool.h" #include "../../../../OrthancStone/Sources/Scene2DViewport/UndoStack.h" +#include "../../../../OrthancStone/Sources/Scene2DViewport/ViewportController.h" #include "../../../../OrthancStone/Sources/StoneException.h" #include "../../../../OrthancStone/Sources/StoneInitialization.h" #include "../../../../OrthancStone/Sources/Viewport/DefaultViewportInteractor.h" +#include "../../Common/SampleHelpers.h" +#include "../SdlHelpers.h" -#include <EmbeddedResources.h> #include <Compatibility.h> // For std::unique_ptr<> -#include <OrthancException.h> +#include <EmbeddedResources.h> +#include <SDL.h> +#include <boost/make_shared.hpp> #include <boost/program_options.hpp> -#include <SDL.h> - #include <string> @@ -94,9 +91,7 @@ virtual void CreateComponents(const boost::shared_ptr<StoneApplication::Context>& context, const boost::shared_ptr<IViewport>& viewport) = 0; - virtual void HandleKeyDown(const boost::shared_ptr<StoneApplication::Context>& context, - const boost::shared_ptr<IViewport>& viewport, - char key) = 0; + virtual bool HandleKeyDown(char key) = 0; virtual void HandleMouseDown(OrthancStone::IViewport::ILock& lock, const OrthancStone::PointerEvent& p) = 0; @@ -111,8 +106,8 @@ class SingleViewportSdlApplication : public StoneApplication { private: - std::unique_ptr<ISingleViewportApplicationCore> core_; - boost::shared_ptr<SdlViewport> viewport_; + boost::shared_ptr<ISingleViewportApplicationCore> core_; + boost::shared_ptr<SdlViewport> viewport_; protected: virtual void RunInternal(const boost::shared_ptr<Context>& context) @@ -171,7 +166,7 @@ } else { - core_->HandleKeyDown(context, viewport_, s[0]); + paint = core_->HandleKeyDown(s[0]); } } } @@ -225,7 +220,7 @@ public: SingleViewportSdlApplication(const Configuration& configuration, - ISingleViewportApplicationCore* core /* takes ownership */, + const boost::shared_ptr<ISingleViewportApplicationCore>& core, const std::string& title, unsigned int width, unsigned int height, @@ -233,7 +228,7 @@ StoneApplication(configuration), core_(core) { - if (core == NULL) + if (!core) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); } @@ -258,24 +253,102 @@ }; - class SimpleViewerApp : public ISingleViewportApplicationCore + class SimpleViewerApp : public ISingleViewportApplicationCore, + public ObserverBase<SimpleViewerApp> // TODO Refactoring - Remove { private: std::string instanceId_; unsigned int frameIndex_; - boost::shared_ptr<SdlSimpleViewerApplication> application_; + boost::shared_ptr<StoneApplication::Context> context_; + boost::shared_ptr<IViewport> viewport_; AnnotationsSceneLayer annotations_; OrthancStone::DefaultViewportInteractor interactor_; boost::shared_ptr<Toto> toto_; + boost::shared_ptr<DicomResourcesLoader> dicomLoader_; + boost::shared_ptr<SeriesFramesLoader> framesLoader_; + OrthancStone::Units units_; + + void Handle(const SeriesFramesLoader::FrameLoadedMessage& message) + { + LOG(INFO) << "Frame decoded! " + << message.GetImage().GetWidth() << "x" << message.GetImage().GetHeight() + << " " << Orthanc::EnumerationToString(message.GetImage().GetFormat()); + + std::unique_ptr<TextureBaseSceneLayer> layer( + message.GetInstanceParameters().CreateTexture(message.GetImage())); + //layer->SetLinearInterpolation(true); + layer->SetLinearInterpolation(false); + + { + std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); + lock->GetController().GetScene().SetLayer(0, layer.release()); + lock->GetCompositor().FitContent(lock->GetController().GetScene()); + lock->Invalidate(); + } + } + + void Handle(const DicomResourcesLoader::SuccessMessage& message) + { + if (message.GetResources()->GetSize() != 1) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + OrthancStone::DicomInstanceParameters parameters(message.GetResources()->GetResource(0)); + if (parameters.HasPixelSpacing()) + { + /** + * TODO - Ultrasound (US) images store an equivalent to + * "PixelSpacing" in the "SequenceOfUltrasoundRegions" + * (0018,6011) sequence, cf. tags "PhysicalDeltaX" (0018,602c) + * and "PhysicalDeltaY" (0018,602e) => This would require + * parsing "message.GetResources()->GetSourceJson(0)" + * => cf. "DicomInstanceParameters::EnrichUsingDicomWeb()" + **/ + + // std::cout << message.GetResources()->GetSourceJson(0).toStyledString(); + + LOG(INFO) << "Using millimeters units, as the DICOM instance contains the PixelSpacing tag"; + units_ = OrthancStone::Units_Millimeters; + } + else + { + LOG(INFO) << "Using pixels units, as the DICOM instance does *not* contain the PixelSpacing tag"; + } + + //message.GetResources()->GetResource(0).Print(stdout); + + { + std::unique_ptr<OrthancStone::IEnvironment::ILock> lock(context_->GetEnvironment().AcquireLock()); + + framesLoader_ = SeriesFramesLoader::Create(*context_, *message.GetResources()); + + Register<SeriesFramesLoader::FrameLoadedMessage>(*framesLoader_, &SimpleViewerApp::Handle); + + assert(message.HasUserPayload()); + + const Orthanc::SingleValueObject<unsigned int>& payload = + dynamic_cast<const Orthanc::SingleValueObject<unsigned int>&>( + message.GetUserPayload()); + + LOG(INFO) << "Loading pixel data of frame: " << payload.GetValue(); + framesLoader_->ScheduleLoadFrame( + 0, message.GetDicomSource(), payload.GetValue(), + message.GetDicomSource().GetQualityCount() - 1 /* download best quality available */, + NULL); + } + } protected: virtual void CreateComponents(const boost::shared_ptr<StoneApplication::Context>& context, const boost::shared_ptr<IViewport>& viewport) ORTHANC_OVERRIDE { - application_ = SdlSimpleViewerApplication::Create(*context, viewport); + context_ = context; + viewport_ = viewport; - OrthancStone::DicomSource source; - application_->LoadOrthancFrame(source, instanceId_, frameIndex_); + dicomLoader_ = DicomResourcesLoader::Create(*context); + + Register<DicomResourcesLoader::SuccessMessage>(*dicomLoader_, &SimpleViewerApp::Handle); annotations_.SetActiveTool(OrthancStone::AnnotationsSceneLayer::Tool_Edit); annotations_.SetProbedLayer(0); @@ -288,19 +361,25 @@ std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->Lock()); lock->GetController().SetUndoStack(boost::make_shared<OrthancStone::UndoStack>()); } + + { + // std::unique_ptr<OrthancStone::IEnvironment::ILock> lock(context->GetEnvironment().AcquireLock()); + OrthancStone::DicomSource source; + dicomLoader_->ScheduleLoadOrthancResource(boost::make_shared<LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID), + 0, source, Orthanc::ResourceType_Instance, instanceId_, + new Orthanc::SingleValueObject<unsigned int>(frameIndex_)); + } } - virtual void HandleKeyDown(const boost::shared_ptr<StoneApplication::Context>& context, - const boost::shared_ptr<IViewport>& viewport, - char key) ORTHANC_OVERRIDE + virtual bool HandleKeyDown(char key) ORTHANC_OVERRIDE { switch (key) { case 'b': { // TODO Refactoring - OrthancStone::IEnvironment& environment = context->GetEnvironment(); - OrthancStone::IOracle& oracle = context->GetOracle(); + OrthancStone::IEnvironment& environment = context_->GetEnvironment(); + OrthancStone::IOracle& oracle = context_->GetOracle(); oracle.Submit(environment, toto_, new OrthancStone::SleepOracleCommand(1000)); @@ -326,12 +405,16 @@ } case 's': - application_->FitContent(); + { + std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); + lock->GetCompositor().FitContent(lock->GetController().GetScene()); + lock->Invalidate(); break; + } case 'u': { - std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->Lock()); + std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); if (lock->GetController().CanUndo()) { lock->GetController().Undo(); @@ -341,7 +424,7 @@ case 'U': { - std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport->Lock()); + std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); if (lock->GetController().CanRedo()) { lock->GetController().Redo(); @@ -384,12 +467,14 @@ default: break; } + + return false; // No need to repaint } virtual void HandleMouseDown(OrthancStone::IViewport::ILock& lock, const OrthancStone::PointerEvent& p) ORTHANC_OVERRIDE { - annotations_.SetUnits(application_->GetUnits()); // TODO Refactoring, should happen after loading the image + annotations_.SetUnits(units_); boost::shared_ptr<OrthancStone::IFlexiblePointerTracker> t; @@ -444,7 +529,8 @@ unsigned int frameIndex) : instanceId_(instanceId), frameIndex_(frameIndex), - annotations_(10) + annotations_(10), + units_(OrthancStone::Units_Pixels) { } }; @@ -565,10 +651,10 @@ configuration.SetDicomCacheSize(128 * 1024 * 1024); // TODO Refactoring - Remove this configuration.SetRootDirectory("/tmp"); // TODO Refactoring - Remove this - std::unique_ptr<OrthancStone::SimpleViewerApp> core(new OrthancStone::SimpleViewerApp(instanceId, frameIndex)); + boost::shared_ptr<OrthancStone::SimpleViewerApp> core(new OrthancStone::SimpleViewerApp(instanceId, frameIndex)); OrthancStone::SingleViewportSdlApplication app( - configuration, core.release(), "Stone of Orthanc", 800, 600, true /* use OpenGL */); + configuration, core, "Stone of Orthanc", 800, 600, true /* use OpenGL */); app.Run(); }
--- a/Applications/Samples/Sdl/SingleFrameViewer/SdlSimpleViewerApplication.h Wed Sep 30 18:36:20 2026 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2023 Osimis S.A., Belgium - * Copyright (C) 2021-2026 Sebastien Jodogne, ICTEAM UCLouvain, Belgium - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU Affero General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - **/ - - -#pragma once - -#include "../../../../OrthancStone/Sources/Loaders/DicomResourcesLoader.h" -#include "../../../../OrthancStone/Sources/Loaders/SeriesFramesLoader.h" -#include "../../../../OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h" -#include "../../../../OrthancStone/Sources/Scene2DViewport/ViewportController.h" -#include "../../../../OrthancStone/Sources/StoneApplication.h" -#include "../../../../OrthancStone/Sources/Viewport/IViewport.h" - -#include <Compatibility.h> // For std::unique_ptr<> - -#include <boost/make_shared.hpp> - - -using OrthancStone::ObserverBase; -using OrthancStone::IViewport; -using OrthancStone::DicomResourcesLoader; -using OrthancStone::SeriesFramesLoader; -using OrthancStone::TextureBaseSceneLayer; -using OrthancStone::DicomSource; -using OrthancStone::SeriesThumbnailsLoader; -using OrthancStone::LoadedDicomResources; -using OrthancStone::SeriesThumbnailType; -using OrthancStone::OracleScheduler; -using OrthancStone::OrthancRestApiCommand; -using OrthancStone::OracleScheduler; -using OrthancStone::OracleScheduler; -using OrthancStone::OracleScheduler; - - -class SdlSimpleViewerApplication : public ObserverBase<SdlSimpleViewerApplication> -{ - -public: - static boost::shared_ptr<SdlSimpleViewerApplication> Create(OrthancStone::StoneApplication::Context& context, - boost::shared_ptr<IViewport> viewport) - { - boost::shared_ptr<SdlSimpleViewerApplication> application(new SdlSimpleViewerApplication(context, viewport)); - - application->dicomLoader_ = DicomResourcesLoader::Create(context); - - application->Register<DicomResourcesLoader::SuccessMessage>(*application->dicomLoader_, &SdlSimpleViewerApplication::Handle); - - return application; - } - - void LoadOrthancFrame(const DicomSource& source, const std::string& instanceId, unsigned int frame) - { - std::unique_ptr<OrthancStone::IEnvironment::ILock> lock(context_.GetEnvironment().AcquireLock()); - - dicomLoader_->ScheduleLoadOrthancResource(boost::make_shared<LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID), - 0, source, Orthanc::ResourceType_Instance, instanceId, - new Orthanc::SingleValueObject<unsigned int>(frame)); - } - -#if 0 - void LoadDicomWebFrame(const DicomSource& source, - const std::string& studyInstanceUid, - const std::string& seriesInstanceUid, - const std::string& sopInstanceUid, - unsigned int frame) - { - std::unique_ptr<ILoadersContext::ILock> lock(context_.Lock()); - - // We first must load the "/metadata" to know the number of frames - dicomLoader_->ScheduleGetDicomWeb( - boost::make_shared<LoadedDicomResources>(Orthanc::DICOM_TAG_SOP_INSTANCE_UID), 0, source, - "/studies/" + studyInstanceUid + "/series/" + seriesInstanceUid + "/instances/" + sopInstanceUid + "/metadata", - new Orthanc::SingleValueObject<unsigned int>(frame)); - } -#endif - - void FitContent() - { - std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); - lock->GetCompositor().FitContent(lock->GetController().GetScene()); - lock->Invalidate(); - } - - OrthancStone::Units GetUnits() const - { - return units_; - } - -private: - OrthancStone::StoneApplication::Context& context_; - boost::shared_ptr<IViewport> viewport_; - boost::shared_ptr<DicomResourcesLoader> dicomLoader_; - boost::shared_ptr<SeriesFramesLoader> framesLoader_; - OrthancStone::Units units_; - - SdlSimpleViewerApplication(OrthancStone::StoneApplication::Context& context, - boost::shared_ptr<IViewport> viewport) : - context_(context), - viewport_(viewport), - units_(OrthancStone::Units_Pixels) - { - } - - void Handle(const SeriesFramesLoader::FrameLoadedMessage& message) - { - LOG(INFO) << "Frame decoded! " - << message.GetImage().GetWidth() << "x" << message.GetImage().GetHeight() - << " " << Orthanc::EnumerationToString(message.GetImage().GetFormat()); - - std::unique_ptr<TextureBaseSceneLayer> layer( - message.GetInstanceParameters().CreateTexture(message.GetImage())); - //layer->SetLinearInterpolation(true); - layer->SetLinearInterpolation(false); - - { - std::unique_ptr<IViewport::ILock> lock(viewport_->Lock()); - lock->GetController().GetScene().SetLayer(0, layer.release()); - lock->GetCompositor().FitContent(lock->GetController().GetScene()); - lock->Invalidate(); - } - } - - void Handle(const DicomResourcesLoader::SuccessMessage& message) - { - if (message.GetResources()->GetSize() != 1) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - OrthancStone::DicomInstanceParameters parameters(message.GetResources()->GetResource(0)); - if (parameters.HasPixelSpacing()) - { - /** - * TODO - Ultrasound (US) images store an equivalent to - * "PixelSpacing" in the "SequenceOfUltrasoundRegions" - * (0018,6011) sequence, cf. tags "PhysicalDeltaX" (0018,602c) - * and "PhysicalDeltaY" (0018,602e) => This would require - * parsing "message.GetResources()->GetSourceJson(0)" - * => cf. "DicomInstanceParameters::EnrichUsingDicomWeb()" - **/ - - // std::cout << message.GetResources()->GetSourceJson(0).toStyledString(); - - LOG(INFO) << "Using millimeters units, as the DICOM instance contains the PixelSpacing tag"; - units_ = OrthancStone::Units_Millimeters; - } - else - { - LOG(INFO) << "Using pixels units, as the DICOM instance does *not* contain the PixelSpacing tag"; - } - - //message.GetResources()->GetResource(0).Print(stdout); - - { - std::unique_ptr<OrthancStone::IEnvironment::ILock> lock(context_.GetEnvironment().AcquireLock()); - - framesLoader_ = SeriesFramesLoader::Create(context_, *message.GetResources()); - - Register<SeriesFramesLoader::FrameLoadedMessage>( - *framesLoader_, &SdlSimpleViewerApplication::Handle); - - assert(message.HasUserPayload()); - - const Orthanc::SingleValueObject<unsigned int>& payload = - dynamic_cast<const Orthanc::SingleValueObject<unsigned int>&>( - message.GetUserPayload()); - - LOG(INFO) << "Loading pixel data of frame: " << payload.GetValue(); - framesLoader_->ScheduleLoadFrame( - 0, message.GetDicomSource(), payload.GetValue(), - message.GetDicomSource().GetQualityCount() - 1 /* download best quality available */, - NULL); - } - } - -}; -
