Mercurial > hg > orthanc-stone
changeset 2196:1c5d4541cfb5
refactoring by introducing OsiriXLayerSource
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Sat, 19 Apr 2025 10:54:40 +0200 |
parents | c4c6884b5f56 |
children | 874ff09fbe89 |
files | Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp |
diffstat | 1 files changed, 166 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Fri Apr 18 17:37:07 2025 +0200 +++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp Sat Apr 19 10:54:40 2025 +0200 @@ -83,10 +83,7 @@ #include "../../../OrthancStone/Sources/StoneException.h" #include "../../../OrthancStone/Sources/Toolbox/DicomInstanceParameters.h" #include "../../../OrthancStone/Sources/Toolbox/GeometryToolbox.h" -#include "../../../OrthancStone/Sources/Toolbox/OsiriX/AngleAnnotation.h" #include "../../../OrthancStone/Sources/Toolbox/OsiriX/CollectionOfAnnotations.h" -#include "../../../OrthancStone/Sources/Toolbox/OsiriX/LineAnnotation.h" -#include "../../../OrthancStone/Sources/Toolbox/OsiriX/TextAnnotation.h" #include "../../../OrthancStone/Sources/Toolbox/SortedFrames.h" #include "../../../OrthancStone/Sources/Viewport/DefaultViewportInteractor.h" @@ -104,6 +101,9 @@ static const double PI = boost::math::constants::pi<double>(); +static const int LAYER_ANNOTATIONS_OSIRIX = 4; + + #if !defined(STONE_WEB_VIEWER_EXPORT) // We are not running ParseWebAssemblyExports.py, but we're compiling the wasm # define STONE_WEB_VIEWER_EXPORT @@ -1784,6 +1784,137 @@ +class ILayerSource : public boost::noncopyable +{ +public: + virtual ~ILayerSource() + { + } + + virtual int GetDepth() const = 0; + + virtual OrthancStone::ISceneLayer* Create(const std::string& studyInstanceUid, + const std::string& seriesInstanceUid, + const std::string& sopInstanceUid, + unsigned int frameNumber, + const OrthancStone::CoordinateSystem3D& plane) = 0; +}; + + +class OsiriXLayerSource : public ILayerSource +{ +private: + int depth_; + + // The coordinates of OsiriX annotations are expressed in 3D world coordinates + OrthancStone::OsiriX::CollectionOfAnnotations annotations_; + +public: + OsiriXLayerSource(int depth) : + depth_(depth) + { + } + + OrthancStone::OsiriX::CollectionOfAnnotations& GetAnnotations() + { + return annotations_; + } + + virtual int GetDepth() const ORTHANC_OVERRIDE + { + return depth_; + } + + virtual OrthancStone::ISceneLayer* Create(const std::string& studyInstanceUid, + const std::string& seriesInstanceUid, + const std::string& sopInstanceUid, + unsigned int frameNumber, + const OrthancStone::CoordinateSystem3D& plane) ORTHANC_OVERRIDE + { + std::set<size_t> a; + annotations_.LookupSopInstanceUid(a, sopInstanceUid); + if (plane.IsValid() && + !a.empty()) + { + std::unique_ptr<OrthancStone::MacroSceneLayer> layer(new OrthancStone::MacroSceneLayer); + // layer->Reserve(a.size()); + + OrthancStone::OsiriXLayerFactory factory; + factory.SetColor(0, 255, 0); + + for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) + { + const OrthancStone::OsiriX::Annotation& annotation = annotations_.GetAnnotation(*it); + layer->AddLayer(factory.Create(annotation, plane)); + } + + return layer.release(); + } + + return NULL; + } +}; + + +class LayersHolder : public boost::noncopyable +{ +private: + typedef std::map<int, OrthancStone::ISceneLayer*> Layers; + + Layers layers_; + +public: + ~LayersHolder() + { + for (Layers::iterator it = layers_.begin(); it != layers_.end(); ++it) + { + if (it->second != NULL) + { + delete it->second; + } + } + } + + void AddLayer(int depth, + OrthancStone::ISceneLayer* layer) + { + std::unique_ptr<OrthancStone::ISceneLayer> protection(layer); + + if (layers_.find(depth) != layers_.end()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls, "Two layer sources are writing to the same depth: " + + boost::lexical_cast<std::string>(depth)); + } + else if (layer == NULL) + { + layers_[depth] = NULL; + } + else + { + layers_[depth] = protection.release(); + } + } + + void Commit(OrthancStone::Scene2D& scene) + { + for (Layers::iterator it = layers_.begin(); it != layers_.end(); ++it) + { + if (it->second == NULL) + { + scene.DeleteLayer(it->first); + } + else + { + std::unique_ptr<OrthancStone::ISceneLayer> layer(it->second); + it->second = NULL; + scene.SetLayer(it->first, layer.release()); + } + } + } +}; + + + class ViewerViewport : public OrthancStone::ObserverBase<ViewerViewport> { public: @@ -1833,7 +1964,6 @@ static const int LAYER_OVERLAY = 1; static const int LAYER_ORIENTATION_MARKERS = 2; static const int LAYER_REFERENCE_LINES = 3; - static const int LAYER_ANNOTATIONS_OSIRIX = 4; static const int LAYER_ANNOTATIONS_STONE = 5; @@ -2230,17 +2360,19 @@ std::string focusSopInstanceUid_; size_t focusFrameNumber_; - // The coordinates of OsiriX annotations are expressed in 3D world coordinates - boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> osiriXAnnotations_; - // The coordinates of Stone annotations are expressed in 2D // coordinates of the current texture, with (0,0) corresponding to // the center of the top-left pixel boost::shared_ptr<OrthancStone::AnnotationsSceneLayer> stoneAnnotations_; + bool linearInterpolation_; + // WARNING: The ownership is not transferred + std::list<ILayerSource*> layerSources_; + + void UpdateWindowing(WindowingState state, const OrthancStone::Windowing& windowing) { @@ -2515,29 +2647,6 @@ } } - std::unique_ptr<OrthancStone::MacroSceneLayer> annotationsOsiriX; - - if (osiriXAnnotations_) - { - std::set<size_t> a; - osiriXAnnotations_->LookupSopInstanceUid(a, instance.GetSopInstanceUid()); - if (plane.IsValid() && - !a.empty()) - { - annotationsOsiriX.reset(new OrthancStone::MacroSceneLayer); - // annotationsOsiriX->Reserve(a.size()); - - OrthancStone::OsiriXLayerFactory factory; - factory.SetColor(0, 255, 0); - - for (std::set<size_t>::const_iterator it = a.begin(); it != a.end(); ++it) - { - const OrthancStone::OsiriX::Annotation& annotation = osiriXAnnotations_->GetAnnotation(*it); - annotationsOsiriX->AddLayer(factory.Create(annotation, plane)); - } - } - } - StoneAnnotationsRegistry::GetInstance().Load(*stoneAnnotations_, instance.GetSopInstanceUid(), frameIndex); // Orientation markers, new in Stone Web viewer 2.4 @@ -2580,6 +2689,14 @@ } + LayersHolder holder; + + for (std::list<ILayerSource*>::const_iterator it = layerSources_.begin(); it != layerSources_.end(); ++it) + { + assert(*it != NULL); + holder.AddLayer((*it)->GetDepth(), (*it)->Create(instance.GetStudyInstanceUid(), instance.GetSeriesInstanceUid(), instance.GetSopInstanceUid(), frameIndex, plane)); + } + { std::unique_ptr<OrthancStone::IViewport::ILock> lock(viewport_->Lock()); @@ -2587,6 +2704,8 @@ scene.SetLayer(LAYER_TEXTURE, layer.release()); + holder.Commit(scene); + if (overlay.get() != NULL) { scene.SetLayer(LAYER_OVERLAY, overlay.release()); @@ -2596,15 +2715,6 @@ scene.DeleteLayer(LAYER_OVERLAY); } - if (annotationsOsiriX.get() != NULL) - { - scene.SetLayer(LAYER_ANNOTATIONS_OSIRIX, annotationsOsiriX.release()); - } - else - { - scene.DeleteLayer(LAYER_ANNOTATIONS_OSIRIX); - } - if (orientationMarkers.get() != NULL) { scene.SetLayer(LAYER_ORIENTATION_MARKERS, orientationMarkers.release()); @@ -3046,6 +3156,13 @@ return viewport; } + + void AddLayerSource(ILayerSource& source) // Ownership is not transfered + { + layerSources_.push_back(&source); + } + + void SetFrames(IFramesCollection* frames) { if (frames == NULL) @@ -3621,11 +3738,6 @@ viewport_->FitForPrint(); } - void SetOsiriXAnnotations(boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> annotations) - { - osiriXAnnotations_ = annotations; - } - void ScheduleFrameFocus(const std::string& sopInstanceUid, unsigned int frameNumber) { @@ -3784,7 +3896,7 @@ static Viewports allViewports_; static bool showReferenceLines_ = true; -static boost::shared_ptr<OrthancStone::OsiriX::CollectionOfAnnotations> osiriXAnnotations_; +static boost::shared_ptr<OsiriXLayerSource> osiriXLayerSource_; static void UpdateReferenceLines() @@ -4114,7 +4226,7 @@ ViewerViewport::Create(*context_, source_, canvas, framesCache_, instancesCache_, softwareRendering_, linearInterpolation_)); viewport->SetMouseButtonActions(leftButtonAction_, middleButtonAction_, rightButtonAction_); viewport->AcquireObserver(new WebAssemblyObserver); - viewport->SetOsiriXAnnotations(osiriXAnnotations_); + viewport->AddLayerSource(*osiriXLayerSource_); allViewports_[canvas] = viewport; return viewport; } @@ -4150,7 +4262,7 @@ framesCache_.reset(new FramesCache); instancesCache_.reset(new InstancesCache); - osiriXAnnotations_.reset(new OrthancStone::OsiriX::CollectionOfAnnotations); + osiriXLayerSource_.reset(new OsiriXLayerSource(LAYER_ANNOTATIONS_OSIRIX)); for (size_t i = 0; pluginsInitializers_[i] != NULL; i++) { @@ -4749,10 +4861,10 @@ { if (clearPreviousAnnotations) { - osiriXAnnotations_->Clear(); + osiriXLayerSource_->GetAnnotations().Clear(); } - osiriXAnnotations_->LoadXml(reinterpret_cast<const char*>(xmlPointer), xmlSize); + osiriXLayerSource_->GetAnnotations().LoadXml(reinterpret_cast<const char*>(xmlPointer), xmlSize); // Force redraw, as the annotations might have changed for (Viewports::iterator it = allViewports_.begin(); it != allViewports_.end(); ++it) @@ -4761,16 +4873,16 @@ it->second->Redraw(); } - if (osiriXAnnotations_->GetSize() == 0) + if (osiriXLayerSource_->GetAnnotations().GetSize() == 0) { stringBuffer_.clear(); } else { - stringBuffer_ = osiriXAnnotations_->GetAnnotation(0).GetSeriesInstanceUid(); + stringBuffer_ = osiriXLayerSource_->GetAnnotations().GetAnnotation(0).GetSeriesInstanceUid(); } - LOG(WARNING) << "Loaded " << osiriXAnnotations_->GetSize() << " annotations from OsiriX"; + LOG(WARNING) << "Loaded " << osiriXLayerSource_->GetAnnotations().GetSize() << " annotations from OsiriX"; return 1; } EXTERN_CATCH_EXCEPTIONS; @@ -4783,9 +4895,9 @@ { try { - if (osiriXAnnotations_->GetSize() != 0) + if (osiriXLayerSource_->GetAnnotations().GetSize() != 0) { - const OrthancStone::OsiriX::Annotation& annotation = osiriXAnnotations_->GetAnnotation(0); + const OrthancStone::OsiriX::Annotation& annotation = osiriXLayerSource_->GetAnnotations().GetAnnotation(0); boost::shared_ptr<ViewerViewport> viewport = GetViewport(canvas); viewport->ScheduleFrameFocus(annotation.GetSopInstanceUid(), 0 /* focus on first frame */);