# HG changeset patch # User Sebastien Jodogne # Date 1558441655 -7200 # Node ID c35e98d22764617113d88f583609c714bdfde196 # Parent 529189f399ece073e6b3e310d70ac411e31eb201 move Deprecated classes to a separate folder diff -r 529189f399ec -r c35e98d22764 Applications/Generic/NativeStoneApplicationContext.h --- a/Applications/Generic/NativeStoneApplicationContext.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Generic/NativeStoneApplicationContext.h Tue May 21 14:27:35 2019 +0200 @@ -21,9 +21,9 @@ #pragma once -#include "../../Framework/Viewport/WidgetViewport.h" -#include "../../Framework/Volumes/ISlicedVolume.h" -#include "../../Framework/Volumes/IVolumeLoader.h" +#include "../../Framework/Deprecated/Viewport/WidgetViewport.h" +#include "../../Framework/Deprecated/Volumes/ISlicedVolume.h" +#include "../../Framework/Deprecated/Volumes/IVolumeLoader.h" #include #include diff -r 529189f399ec -r c35e98d22764 Applications/IStoneApplication.h --- a/Applications/IStoneApplication.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/IStoneApplication.h Tue May 21 14:27:35 2019 +0200 @@ -22,9 +22,10 @@ #pragma once #include "StoneApplicationContext.h" +#include "../Framework/Deprecated/Viewport/WidgetViewport.h" + #include -#include "../Framework/Viewport/WidgetViewport.h" -#include "json/json.h" +#include namespace OrthancStone { diff -r 529189f399ec -r c35e98d22764 Applications/Samples/CMakeLists.txt --- a/Applications/Samples/CMakeLists.txt Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/CMakeLists.txt Tue May 21 14:27:35 2019 +0200 @@ -208,7 +208,6 @@ ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/AppStatus.h ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.h - ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Messages.h ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.h ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SampleApplicationBase.h --- a/Applications/Samples/SampleApplicationBase.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SampleApplicationBase.h Tue May 21 14:27:35 2019 +0200 @@ -22,7 +22,7 @@ #pragma once #include "../../Applications/IStoneApplication.h" -#include "../../Framework/Widgets/WorldSceneWidget.h" +#include "../../Framework/Deprecated/Widgets/WorldSceneWidget.h" #if ORTHANC_ENABLE_WASM==1 #include "../../Platforms/Wasm/WasmPlatformApplicationAdapter.h" diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SimpleViewer/MainWidgetInteractor.h --- a/Applications/Samples/SimpleViewer/MainWidgetInteractor.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SimpleViewer/MainWidgetInteractor.h Tue May 21 14:27:35 2019 +0200 @@ -20,7 +20,7 @@ #pragma once -#include "Framework/Widgets/IWorldSceneInteractor.h" +#include "../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h" using namespace OrthancStone; diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SimpleViewer/SimpleViewerApplication.h --- a/Applications/Samples/SimpleViewer/SimpleViewerApplication.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.h Tue May 21 14:27:35 2019 +0200 @@ -29,12 +29,12 @@ #include "Applications/IStoneApplication.h" -#include "Framework/Layers/CircleMeasureTracker.h" -#include "Framework/Layers/LineMeasureTracker.h" -#include "Framework/Widgets/SliceViewerWidget.h" -#include "Framework/Widgets/LayoutWidget.h" -#include "Framework/Messages/IObserver.h" -#include "Framework/SmartLoader.h" +#include "../../../Framework/Deprecated/Layers/CircleMeasureTracker.h" +#include "../../../Framework/Deprecated/Layers/LineMeasureTracker.h" +#include "../../../Framework/Deprecated/SmartLoader.h" +#include "../../../Framework/Deprecated/Widgets/LayoutWidget.h" +#include "../../../Framework/Deprecated/Widgets/SliceViewerWidget.h" +#include "../../../Framework/Messages/IObserver.h" #if ORTHANC_ENABLE_WASM==1 #include "Platforms/Wasm/WasmPlatformApplicationAdapter.h" diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SimpleViewer/ThumbnailInteractor.h --- a/Applications/Samples/SimpleViewer/ThumbnailInteractor.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SimpleViewer/ThumbnailInteractor.h Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #pragma once -#include "Framework/Widgets/IWorldSceneInteractor.h" +#include "../../../Framework/Deprecated/Widgets/IWorldSceneInteractor.h" using namespace OrthancStone; diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SimpleViewerApplicationSingleFile.h --- a/Applications/Samples/SimpleViewerApplicationSingleFile.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SimpleViewerApplicationSingleFile.h Tue May 21 14:27:35 2019 +0200 @@ -23,12 +23,12 @@ #include "SampleApplicationBase.h" -#include "../../Framework/Layers/CircleMeasureTracker.h" -#include "../../Framework/Layers/LineMeasureTracker.h" -#include "../../Framework/Widgets/SliceViewerWidget.h" -#include "../../Framework/Widgets/LayoutWidget.h" +#include "../../Framework/Deprecated/Layers/CircleMeasureTracker.h" +#include "../../Framework/Deprecated/Layers/LineMeasureTracker.h" +#include "../../Framework/Deprecated/SmartLoader.h" +#include "../../Framework/Deprecated/Widgets/LayoutWidget.h" +#include "../../Framework/Deprecated/Widgets/SliceViewerWidget.h" #include "../../Framework/Messages/IObserver.h" -#include "../../Framework/SmartLoader.h" #if ORTHANC_ENABLE_WASM==1 #include "../../Platforms/Wasm/WasmPlatformApplicationAdapter.h" diff -r 529189f399ec -r c35e98d22764 Applications/Samples/SingleFrameApplication.h --- a/Applications/Samples/SingleFrameApplication.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Samples/SingleFrameApplication.h Tue May 21 14:27:35 2019 +0200 @@ -23,8 +23,8 @@ #include "SampleApplicationBase.h" -#include "../../Framework/Layers/DicomSeriesVolumeSlicer.h" -#include "../../Framework/Widgets/SliceViewerWidget.h" +#include "../../Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h" +#include "../../Framework/Deprecated/Widgets/SliceViewerWidget.h" #include #include diff -r 529189f399ec -r c35e98d22764 Applications/Sdl/SdlCairoSurface.h --- a/Applications/Sdl/SdlCairoSurface.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/Sdl/SdlCairoSurface.h Tue May 21 14:27:35 2019 +0200 @@ -25,7 +25,7 @@ #include "SdlWindow.h" #include "../../Framework/Viewport/CairoSurface.h" -#include "../../Framework/Viewport/IViewport.h" +#include "../../Framework/Deprecated/Viewport/IViewport.h" #include diff -r 529189f399ec -r c35e98d22764 Applications/StoneApplicationContext.h --- a/Applications/StoneApplicationContext.h Tue May 21 13:27:54 2019 +0200 +++ b/Applications/StoneApplicationContext.h Tue May 21 14:27:35 2019 +0200 @@ -21,10 +21,10 @@ #pragma once -#include "../Framework/Toolbox/IWebService.h" -#include "../Framework/Toolbox/IDelayedCallExecutor.h" -#include "../Framework/Toolbox/OrthancApiClient.h" -#include "../Framework/Viewport/WidgetViewport.h" +#include "../Framework/Deprecated/Toolbox/IWebService.h" +#include "../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h" +#include "../Framework/Deprecated/Toolbox/OrthancApiClient.h" +#include "../Framework/Deprecated/Viewport/WidgetViewport.h" #ifdef _MSC_VER diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/CircleMeasureTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/CircleMeasureTracker.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,106 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "CircleMeasureTracker.h" + +#include +#include + +namespace Deprecated +{ + CircleMeasureTracker::CircleMeasureTracker(IStatusBar* statusBar, + const OrthancStone::CoordinateSystem3D& slice, + double x, + double y, + uint8_t red, + uint8_t green, + uint8_t blue, + const Orthanc::Font& font) : + statusBar_(statusBar), + slice_(slice), + x1_(x), + y1_(y), + x2_(x), + y2_(y), + font_(font) + { + color_[0] = red; + color_[1] = green; + color_[2] = blue; + } + + + void CircleMeasureTracker::Render(OrthancStone::CairoContext& context, + double zoom) + { + double x = (x1_ + x2_) / 2.0; + double y = (y1_ + y2_) / 2.0; + + OrthancStone::Vector tmp; + OrthancStone::LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_); + double r = boost::numeric::ublas::norm_2(tmp) / 2.0; + + context.SetSourceColor(color_[0], color_[1], color_[2]); + + cairo_t* cr = context.GetObject(); + cairo_save(cr); + cairo_set_line_width(cr, 2.0 / zoom); + cairo_translate(cr, x, y); + cairo_arc(cr, 0, 0, r, 0, 2.0 * boost::math::constants::pi()); + cairo_stroke_preserve(cr); + cairo_stroke(cr); + cairo_restore(cr); + + context.DrawText(font_, FormatRadius(), x, y, OrthancStone::BitmapAnchor_Center); + } + + + double CircleMeasureTracker::GetRadius() const // In millimeters + { + OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_); + OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_); + return boost::numeric::ublas::norm_2(b - a) / 2.0; + } + + + std::string CircleMeasureTracker::FormatRadius() const + { + char buf[64]; + sprintf(buf, "%0.01f cm", GetRadius() / 10.0); + return buf; + } + + void CircleMeasureTracker::MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches) + { + x2_ = x; + y2_ = y; + + if (statusBar_ != NULL) + { + statusBar_->SetMessage("Circle radius: " + FormatRadius()); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/CircleMeasureTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/CircleMeasureTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,78 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Viewport/IStatusBar.h" +#include "../../Toolbox/CoordinateSystem3D.h" + +#include + +namespace Deprecated +{ + class CircleMeasureTracker : public IWorldSceneMouseTracker + { + private: + IStatusBar* statusBar_; + OrthancStone::CoordinateSystem3D slice_; + double x1_; + double y1_; + double x2_; + double y2_; + uint8_t color_[3]; + const Orthanc::Font& font_; + + public: + CircleMeasureTracker(IStatusBar* statusBar, + const OrthancStone::CoordinateSystem3D& slice, + double x, + double y, + uint8_t red, + uint8_t green, + uint8_t blue, + const Orthanc::Font& font); + + virtual bool HasRender() const + { + return true; + } + + virtual void Render(OrthancStone::CairoContext& context, + double zoom); + + double GetRadius() const; // In millimeters + + std::string FormatRadius() const; + + virtual void MouseUp() + { + // Possibly create a new landmark "volume" with the circle in subclasses + } + + virtual void MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/ColorFrameRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/ColorFrameRenderer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,62 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "ColorFrameRenderer.h" + +#include +#include +#include + +namespace Deprecated +{ + OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style) + { + std::auto_ptr display + (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */)); + + Orthanc::ImageAccessor target; + display->GetWriteableAccessor(target); + + Orthanc::ImageProcessing::Convert(target, *frame_); + + return display.release(); + } + + + ColorFrameRenderer::ColorFrameRenderer(const Orthanc::ImageAccessor& frame, + const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality) : + FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality), + frame_(Orthanc::Image::Clone(frame)) + { + if (frame_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + if (frame_->GetFormat() != Orthanc::PixelFormat_RGB24) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/ColorFrameRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/ColorFrameRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,43 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "FrameRenderer.h" + +namespace Deprecated +{ + class ColorFrameRenderer : public FrameRenderer + { + private: + std::auto_ptr frame_; // In RGB24 + + protected: + virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style); + + public: + ColorFrameRenderer(const Orthanc::ImageAccessor& frame, + const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,162 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "DicomSeriesVolumeSlicer.h" + +#include "FrameRenderer.h" +#include "../Toolbox/DicomFrameConverter.h" + +#include +#include + +#include + +namespace Deprecated +{ + + void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) + { + if (message.GetOrigin().GetSlicesCount() > 0) + { + BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); + } + else + { + BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); + } + } + + void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) + { + BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); + } + + + class DicomSeriesVolumeSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory + { + private: + const OrthancSlicesLoader::SliceImageReadyMessage& message_; + + public: + RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) : + message_(message) + { + } + + virtual ILayerRenderer* CreateRenderer() const + { + bool isFull = (message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPng || + message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPam); + + return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull); + } + }; + + void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) + { + // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache) + BroadcastMessage(FrameReadyMessage(*this, message.GetImage(), + message.GetEffectiveQuality(), message.GetSlice())); + + // then notify that the layer is ready for rendering + RendererFactory factory(message); + BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry())); + } + + void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) + { + BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry())); + } + + + DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc) : + IVolumeSlicer(broker), + IObserver(broker), + loader_(broker, orthanc), + quality_(OrthancStone::SliceImageQuality_FullPng) + { + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &DicomSeriesVolumeSlicer::OnSliceImageError)); + } + + + void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId) + { + loader_.ScheduleLoadSeries(seriesId); + } + + + void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId) + { + loader_.ScheduleLoadInstance(instanceId); + } + + + void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId, + unsigned int frame) + { + loader_.ScheduleLoadFrame(instanceId, frame); + } + + + bool DicomSeriesVolumeSlicer::GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice) + { + size_t index; + + if (loader_.IsGeometryReady() && + loader_.LookupSlice(index, viewportSlice)) + { + loader_.GetSlice(index).GetExtent(points); + return true; + } + else + { + return false; + } + } + + + void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) + { + size_t index; + + if (loader_.IsGeometryReady() && + loader_.LookupSlice(index, viewportSlice)) + { + loader_.ScheduleLoadSliceImage(index, quality_); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,127 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IVolumeSlicer.h" +#include "../Toolbox/IWebService.h" +#include "../Toolbox/OrthancSlicesLoader.h" +#include "../Toolbox/OrthancApiClient.h" + +namespace Deprecated +{ + // this class is in charge of loading a Frame. + // once it's been loaded (first the geometry and then the image), + // messages are sent to observers so they can use it + class DicomSeriesVolumeSlicer : + public IVolumeSlicer, + public OrthancStone::IObserver + //private OrthancSlicesLoader::ISliceLoaderObserver + { + public: + // TODO: Add "frame" and "instanceId" + class FrameReadyMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const Orthanc::ImageAccessor& frame_; + OrthancStone::SliceImageQuality imageQuality_; + const Slice& slice_; + + public: + FrameReadyMessage(DicomSeriesVolumeSlicer& origin, + const Orthanc::ImageAccessor& frame, + OrthancStone::SliceImageQuality imageQuality, + const Slice& slice) : + OriginMessage(origin), + frame_(frame), + imageQuality_(imageQuality), + slice_(slice) + { + } + + const Orthanc::ImageAccessor& GetFrame() const + { + return frame_; + } + + OrthancStone::SliceImageQuality GetImageQuality() const + { + return imageQuality_; + } + + const Slice& GetSlice() const + { + return slice_; + } + }; + + + private: + class RendererFactory; + + OrthancSlicesLoader loader_; + OrthancStone::SliceImageQuality quality_; + + public: + DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc); + + void LoadSeries(const std::string& seriesId); + + void LoadInstance(const std::string& instanceId); + + void LoadFrame(const std::string& instanceId, + unsigned int frame); + + void SetImageQuality(OrthancStone::SliceImageQuality quality) + { + quality_ = quality; + } + + OrthancStone::SliceImageQuality GetImageQuality() const + { + return quality_; + } + + size_t GetSlicesCount() const + { + return loader_.GetSlicesCount(); + } + + const Slice& GetSlice(size_t slice) const + { + return loader_.GetSlice(slice); + } + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice); + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice); + +protected: + void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message); + void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message); + void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message); + void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,170 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "DicomStructureSetSlicer.h" + +namespace Deprecated +{ + class DicomStructureSetSlicer::Renderer : public ILayerRenderer + { + private: + class Structure + { + private: + bool visible_; + uint8_t red_; + uint8_t green_; + uint8_t blue_; + std::string name_; + std::vector< std::vector > polygons_; + + public: + Structure(OrthancStone::DicomStructureSet& structureSet, + const OrthancStone::CoordinateSystem3D& plane, + size_t index) : + name_(structureSet.GetStructureName(index)) + { + structureSet.GetStructureColor(red_, green_, blue_, index); + visible_ = structureSet.ProjectStructure(polygons_, index, plane); + } + + void Render(OrthancStone::CairoContext& context) + { + if (visible_) + { + cairo_t* cr = context.GetObject(); + + context.SetSourceColor(red_, green_, blue_); + + for (size_t i = 0; i < polygons_.size(); i++) + { + cairo_move_to(cr, polygons_[i][0].first, polygons_[i][0].second); + + for (size_t j = 1; j < polygons_[i].size(); j++) + { + cairo_line_to(cr, polygons_[i][j].first, polygons_[i][j].second); + } + + cairo_line_to(cr, polygons_[i][0].first, polygons_[i][0].second); + cairo_stroke(cr); + } + } + } + }; + + typedef std::list Structures; + + OrthancStone::CoordinateSystem3D plane_; + Structures structures_; + + public: + Renderer(OrthancStone::DicomStructureSet& structureSet, + const OrthancStone::CoordinateSystem3D& plane) : + plane_(plane) + { + for (size_t k = 0; k < structureSet.GetStructureCount(); k++) + { + structures_.push_back(new Structure(structureSet, plane, k)); + } + } + + virtual ~Renderer() + { + for (Structures::iterator it = structures_.begin(); + it != structures_.end(); ++it) + { + delete *it; + } + } + + virtual bool RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + cairo_set_line_width(context.GetObject(), 2.0f / view.GetZoom()); + + for (Structures::const_iterator it = structures_.begin(); + it != structures_.end(); ++it) + { + assert(*it != NULL); + (*it)->Render(context); + } + + return true; + } + + virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() + { + return plane_; + } + + virtual void SetLayerStyle(const RenderStyle& style) + { + } + + virtual bool IsFullQuality() + { + return true; + } + }; + + + class DicomStructureSetSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory + { + private: + OrthancStone::DicomStructureSet& structureSet_; + const OrthancStone::CoordinateSystem3D& plane_; + + public: + RendererFactory(OrthancStone::DicomStructureSet& structureSet, + const OrthancStone::CoordinateSystem3D& plane) : + structureSet_(structureSet), + plane_(plane) + { + } + + virtual ILayerRenderer* CreateRenderer() const + { + return new Renderer(structureSet_, plane_); + } + }; + + + DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, + StructureSetLoader& loader) : + IVolumeSlicer(broker), + IObserver(broker), + loader_(loader) + { + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &DicomStructureSetSlicer::OnStructureSetLoaded)); + } + + + void DicomStructureSetSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane) + { + if (loader_.HasStructureSet()) + { + RendererFactory factory(loader_.GetStructureSet(), viewportPlane); + BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane)); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/DicomStructureSetSlicer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/DicomStructureSetSlicer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,56 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IVolumeSlicer.h" +#include "../Volumes/StructureSetLoader.h" + +namespace Deprecated +{ + class DicomStructureSetSlicer : + public IVolumeSlicer, + public OrthancStone::IObserver + { + private: + class Renderer; + class RendererFactory; + + StructureSetLoader& loader_; + + void OnStructureSetLoaded(const IVolumeLoader::ContentChangedMessage& message) + { + BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); + } + + public: + DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, + StructureSetLoader& loader); + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportPlane) + { + return false; + } + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/FrameRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/FrameRenderer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,140 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "FrameRenderer.h" + +#include "GrayscaleFrameRenderer.h" +#include "ColorFrameRenderer.h" + +#include + +namespace Deprecated +{ + FrameRenderer::FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality) : + framePlane_(framePlane), + pixelSpacingX_(pixelSpacingX), + pixelSpacingY_(pixelSpacingY), + isFullQuality_(isFullQuality) + { + } + + + bool FrameRenderer::RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + if (!style_.visible_) + { + return true; + } + + if (display_.get() == NULL) + { + display_.reset(GenerateDisplay(style_)); + } + + assert(display_.get() != NULL); + + cairo_t *cr = context.GetObject(); + + cairo_save(cr); + + cairo_matrix_t transform; + cairo_matrix_init_identity(&transform); + cairo_matrix_scale(&transform, pixelSpacingX_, pixelSpacingY_); + cairo_matrix_translate(&transform, -0.5, -0.5); + cairo_transform(cr, &transform); + + //cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cr, display_->GetObject(), 0, 0); + + switch (style_.interpolation_) + { + case OrthancStone::ImageInterpolation_Nearest: + cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); + break; + + case OrthancStone::ImageInterpolation_Bilinear: + cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + cairo_paint_with_alpha(cr, style_.alpha_); + + if (style_.drawGrid_) + { + context.SetSourceColor(style_.drawColor_); + cairo_set_line_width(cr, 0.5 / view.GetZoom()); + + for (unsigned int x = 0; x <= display_->GetWidth(); x++) + { + cairo_move_to(cr, x, 0); + cairo_line_to(cr, x, display_->GetHeight()); + } + + for (unsigned int y = 0; y <= display_->GetHeight(); y++) + { + cairo_move_to(cr, 0, y); + cairo_line_to(cr, display_->GetWidth(), y); + } + + cairo_stroke(cr); + } + + cairo_restore(cr); + + return true; + } + + + void FrameRenderer::SetLayerStyle(const RenderStyle& style) + { + style_ = style; + display_.reset(NULL); + } + + + ILayerRenderer* FrameRenderer::CreateRenderer(const Orthanc::ImageAccessor& frame, + const Deprecated::Slice& framePlane, + bool isFullQuality) + { + if (frame.GetFormat() == Orthanc::PixelFormat_RGB24) + { + return new ColorFrameRenderer(frame, + framePlane.GetGeometry(), + framePlane.GetPixelSpacingX(), + framePlane.GetPixelSpacingY(), isFullQuality); + } + else + { + return new GrayscaleFrameRenderer(frame, + framePlane.GetConverter(), + framePlane.GetGeometry(), + framePlane.GetPixelSpacingX(), + framePlane.GetPixelSpacingY(), isFullQuality); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/FrameRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/FrameRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,69 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRenderer.h" + +#include "../Toolbox/Slice.h" + +namespace Deprecated +{ + class FrameRenderer : public ILayerRenderer + { + private: + OrthancStone::CoordinateSystem3D framePlane_; + double pixelSpacingX_; + double pixelSpacingY_; + RenderStyle style_; + bool isFullQuality_; + std::auto_ptr display_; + + protected: + virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0; + + public: + FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality); + + virtual bool RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view); + + virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() + { + return framePlane_; + } + + virtual void SetLayerStyle(const RenderStyle& style); + + virtual bool IsFullQuality() + { + return isFullQuality_; + } + + // TODO: Avoid cloning the "frame" + static ILayerRenderer* CreateRenderer(const Orthanc::ImageAccessor& frame, + const Deprecated::Slice& framePlane, + bool isFullQuality); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,141 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "GrayscaleFrameRenderer.h" + +#include +#include + +namespace Deprecated +{ + OrthancStone::CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style) + { + assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32); + + std::auto_ptr result; + + float windowCenter, windowWidth; + style.ComputeWindowing(windowCenter, windowWidth, + defaultWindowCenter_, defaultWindowWidth_); + + float x0 = windowCenter - windowWidth / 2.0f; + float x1 = windowCenter + windowWidth / 2.0f; + + //LOG(INFO) << "Window: " << x0 << " => " << x1; + + result.reset(new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */)); + + const uint8_t* lut = NULL; + if (style.applyLut_) + { + if (Orthanc::EmbeddedResources::GetFileResourceSize(style.lut_) != 3 * 256) + { + // Invalid colormap + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + lut = reinterpret_cast(Orthanc::EmbeddedResources::GetFileResourceBuffer(style.lut_)); + } + + Orthanc::ImageAccessor target; + result->GetWriteableAccessor(target); + + const unsigned int width = target.GetWidth(); + const unsigned int height = target.GetHeight(); + + for (unsigned int y = 0; y < height; y++) + { + const float* p = reinterpret_cast(frame_->GetConstRow(y)); + uint8_t* q = reinterpret_cast(target.GetRow(y)); + + for (unsigned int x = 0; x < width; x++, p++, q += 4) + { + uint8_t v = 0; + if (windowWidth >= 0.001f) // Avoid division by zero + { + if (*p >= x1) + { + v = 255; + } + else if (*p <= x0) + { + v = 0; + } + else + { + // https://en.wikipedia.org/wiki/Linear_interpolation + v = static_cast(255.0f * (*p - x0) / (x1 - x0)); + } + + if (style.reverse_ ^ (photometric_ == Orthanc::PhotometricInterpretation_Monochrome1)) + { + v = 255 - v; + } + } + + if (style.applyLut_) + { + assert(lut != NULL); + q[3] = 255; + q[2] = lut[3 * v]; + q[1] = lut[3 * v + 1]; + q[0] = lut[3 * v + 2]; + } + else + { + q[3] = 255; + q[2] = v; + q[1] = v; + q[0] = v; + } + } + } + + return result.release(); + } + + + GrayscaleFrameRenderer::GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame, + const Deprecated::DicomFrameConverter& converter, + const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality) : + FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality), + frame_(Orthanc::Image::Clone(frame)), + defaultWindowCenter_(static_cast(converter.GetDefaultWindowCenter())), + defaultWindowWidth_(static_cast(converter.GetDefaultWindowWidth())), + photometric_(converter.GetPhotometricInterpretation()) + { + if (frame_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + converter.ConvertFrameInplace(frame_); + assert(frame_.get() != NULL); + + if (frame_->GetFormat() != Orthanc::PixelFormat_Float32) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/GrayscaleFrameRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/GrayscaleFrameRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,48 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "FrameRenderer.h" +#include "../Toolbox/DicomFrameConverter.h" + +namespace Deprecated +{ + class GrayscaleFrameRenderer : public FrameRenderer + { + private: + std::auto_ptr frame_; // In Float32 + float defaultWindowCenter_; + float defaultWindowWidth_; + Orthanc::PhotometricInterpretation photometric_; + + protected: + virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style); + + public: + GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame, + const Deprecated::DicomFrameConverter& converter, + const OrthancStone::CoordinateSystem3D& framePlane, + double pixelSpacingX, + double pixelSpacingY, + bool isFullQuality); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/ILayerRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/ILayerRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,47 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Viewport/CairoContext.h" +#include "../../Toolbox/CoordinateSystem3D.h" +#include "../Toolbox/ViewportGeometry.h" +#include "RenderStyle.h" + +namespace Deprecated +{ + class ILayerRenderer : public boost::noncopyable + { + public: + virtual ~ILayerRenderer() + { + } + + virtual bool RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view) = 0; + + virtual void SetLayerStyle(const RenderStyle& style) = 0; + + virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() = 0; + + virtual bool IsFullQuality() = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/IVolumeSlicer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/IVolumeSlicer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,139 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRenderer.h" +#include "../Toolbox/Slice.h" +#include "../../Messages/IObservable.h" +#include "../../Messages/IMessage.h" +#include "Core/Images/Image.h" +#include + +namespace Deprecated +{ + class IVolumeSlicer : public OrthancStone::IObservable + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeSlicer); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeSlicer); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeSlicer); + + class SliceContentChangedMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const Deprecated::Slice& slice_; + + public: + SliceContentChangedMessage(IVolumeSlicer& origin, + const Deprecated::Slice& slice) : + OriginMessage(origin), + slice_(slice) + { + } + + const Deprecated::Slice& GetSlice() const + { + return slice_; + } + }; + + + class LayerReadyMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + public: + class IRendererFactory : public boost::noncopyable + { + public: + virtual ~IRendererFactory() + { + } + + virtual ILayerRenderer* CreateRenderer() const = 0; + }; + + private: + const IRendererFactory& factory_; + const OrthancStone::CoordinateSystem3D& slice_; + + public: + LayerReadyMessage(IVolumeSlicer& origin, + const IRendererFactory& rendererFactory, + const OrthancStone::CoordinateSystem3D& slice) : + OriginMessage(origin), + factory_(rendererFactory), + slice_(slice) + { + } + + ILayerRenderer* CreateRenderer() const + { + return factory_.CreateRenderer(); + } + + const OrthancStone::CoordinateSystem3D& GetSlice() const + { + return slice_; + } + }; + + + class LayerErrorMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const OrthancStone::CoordinateSystem3D& slice_; + + public: + LayerErrorMessage(IVolumeSlicer& origin, + const OrthancStone::CoordinateSystem3D& slice) : + OriginMessage(origin), + slice_(slice) + { + } + + const OrthancStone::CoordinateSystem3D& GetSlice() const + { + return slice_; + } + }; + + + IVolumeSlicer(OrthancStone::MessageBroker& broker) : + IObservable(broker) + { + } + + virtual ~IVolumeSlicer() + { + } + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice) = 0; + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/LineLayerRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/LineLayerRenderer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,67 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "LineLayerRenderer.h" + +namespace Deprecated +{ + LineLayerRenderer::LineLayerRenderer(double x1, + double y1, + double x2, + double y2, + const OrthancStone::CoordinateSystem3D& plane) : + x1_(x1), + y1_(y1), + x2_(x2), + y2_(y2), + plane_(plane) + { + RenderStyle style; + SetLayerStyle(style); + } + + + bool LineLayerRenderer::RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + if (visible_) + { + context.SetSourceColor(color_); + + cairo_t *cr = context.GetObject(); + cairo_set_line_width(cr, 1.0 / view.GetZoom()); + cairo_move_to(cr, x1_, y1_); + cairo_line_to(cr, x2_, y2_); + cairo_stroke(cr); + } + + return true; + } + + + void LineLayerRenderer::SetLayerStyle(const RenderStyle& style) + { + visible_ = style.visible_; + color_[0] = style.drawColor_[0]; + color_[1] = style.drawColor_[1]; + color_[2] = style.drawColor_[2]; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/LineLayerRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/LineLayerRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,61 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRenderer.h" + +namespace Deprecated +{ + class LineLayerRenderer : public ILayerRenderer + { + private: + double x1_; + double y1_; + double x2_; + double y2_; + OrthancStone::CoordinateSystem3D plane_; + bool visible_; + uint8_t color_[3]; + + public: + LineLayerRenderer(double x1, + double y1, + double x2, + double y2, + const OrthancStone::CoordinateSystem3D& plane); + + virtual bool RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view); + + virtual void SetLayerStyle(const RenderStyle& style); + + virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() + { + return plane_; + } + + virtual bool IsFullQuality() + { + return true; + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/LineMeasureTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/LineMeasureTracker.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,102 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "LineMeasureTracker.h" + +#include + +namespace Deprecated +{ + LineMeasureTracker::LineMeasureTracker(IStatusBar* statusBar, + const OrthancStone::CoordinateSystem3D& slice, + double x, + double y, + uint8_t red, + uint8_t green, + uint8_t blue, + const Orthanc::Font& font) : + statusBar_(statusBar), + slice_(slice), + x1_(x), + y1_(y), + x2_(x), + y2_(y), + font_(font) + { + color_[0] = red; + color_[1] = green; + color_[2] = blue; + } + + + void LineMeasureTracker::Render(OrthancStone::CairoContext& context, + double zoom) + { + context.SetSourceColor(color_[0], color_[1], color_[2]); + + cairo_t* cr = context.GetObject(); + cairo_set_line_width(cr, 2.0 / zoom); + cairo_move_to(cr, x1_, y1_); + cairo_line_to(cr, x2_, y2_); + cairo_stroke(cr); + + if (y2_ - y1_ < 0) + { + context.DrawText(font_, FormatLength(), x2_, y2_ - 5, OrthancStone::BitmapAnchor_BottomCenter); + } + else + { + context.DrawText(font_, FormatLength(), x2_, y2_ + 5, OrthancStone::BitmapAnchor_TopCenter); + } + } + + + double LineMeasureTracker::GetLength() const // In millimeters + { + OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_); + OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_); + return boost::numeric::ublas::norm_2(b - a); + } + + + std::string LineMeasureTracker::FormatLength() const + { + char buf[64]; + sprintf(buf, "%0.01f cm", GetLength() / 10.0); + return buf; + } + + void LineMeasureTracker::MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches) + { + x2_ = x; + y2_ = y; + + if (statusBar_ != NULL) + { + statusBar_->SetMessage("Line length: " + FormatLength()); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/LineMeasureTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/LineMeasureTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,78 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../Widgets/IWorldSceneMouseTracker.h" + +#include "../Viewport/IStatusBar.h" +#include "../../Toolbox/CoordinateSystem3D.h" + +namespace Deprecated +{ + class LineMeasureTracker : public IWorldSceneMouseTracker + { + private: + IStatusBar* statusBar_; + OrthancStone::CoordinateSystem3D slice_; + double x1_; + double y1_; + double x2_; + double y2_; + uint8_t color_[3]; + unsigned int fontSize_; + const Orthanc::Font& font_; + + public: + LineMeasureTracker(IStatusBar* statusBar, + const OrthancStone::CoordinateSystem3D& slice, + double x, + double y, + uint8_t red, + uint8_t green, + uint8_t blue, + const Orthanc::Font& font); + + virtual bool HasRender() const + { + return true; + } + + virtual void Render(OrthancStone::CairoContext& context, + double zoom); + + double GetLength() const; // In millimeters + + std::string FormatLength() const; + + virtual void MouseUp() + { + // Possibly create a new landmark "volume" with the line in subclasses + } + + virtual void MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/RenderStyle.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/RenderStyle.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,73 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "RenderStyle.h" + +#include + +namespace Deprecated +{ + RenderStyle::RenderStyle() + { + visible_ = true; + reverse_ = false; + windowing_ = OrthancStone::ImageWindowing_Custom; + alpha_ = 1; + applyLut_ = false; + lut_ = Orthanc::EmbeddedResources::COLORMAP_HOT; + drawGrid_ = false; + drawColor_[0] = 255; + drawColor_[1] = 255; + drawColor_[2] = 255; + customWindowCenter_ = 128; + customWindowWidth_ = 256; + interpolation_ = OrthancStone::ImageInterpolation_Nearest; + fontSize_ = 14; + } + + + void RenderStyle::ComputeWindowing(float& targetCenter, + float& targetWidth, + float defaultCenter, + float defaultWidth) const + { + if (windowing_ == OrthancStone::ImageWindowing_Custom) + { + targetCenter = customWindowCenter_; + targetWidth = customWindowWidth_; + } + else + { + return ::OrthancStone::ComputeWindowing + (targetCenter, targetWidth, windowing_, defaultCenter, defaultWidth); + } + } + + + void RenderStyle::SetColor(uint8_t red, + uint8_t green, + uint8_t blue) + { + drawColor_[0] = red; + drawColor_[1] = green; + drawColor_[2] = blue; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/RenderStyle.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/RenderStyle.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,58 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../StoneEnumerations.h" + +#include + +#include + +namespace Deprecated +{ + struct RenderStyle + { + bool visible_; + bool reverse_; + OrthancStone::ImageWindowing windowing_; + float alpha_; // In [0,1] + bool applyLut_; + Orthanc::EmbeddedResources::FileResourceId lut_; + bool drawGrid_; + uint8_t drawColor_[3]; + float customWindowCenter_; + float customWindowWidth_; + OrthancStone::ImageInterpolation interpolation_; + unsigned int fontSize_; + + RenderStyle(); + + void ComputeWindowing(float& targetCenter, + float& targetWidth, + float defaultCenter, + float defaultWidth) const; + + void SetColor(uint8_t red, + uint8_t green, + uint8_t blue); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SeriesFrameRendererFactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SeriesFrameRendererFactory.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,177 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "SeriesFrameRendererFactory.h" + +#include "FrameRenderer.h" + +#include +#include +#include +#include +#include + + +namespace Deprecated +{ + void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame) + { + if (currentDataset_.get() != NULL && + (fast_ || currentFrame_ == frame)) + { + // The frame has not changed since the previous call, no need to + // update the DICOM dataset + return; + } + + currentDataset_.reset(loader_->DownloadDicom(frame)); + currentFrame_ = frame; + + if (currentDataset_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + void SeriesFrameRendererFactory::GetCurrentPixelSpacing(double& spacingX, + double& spacingY) const + { + if (currentDataset_.get() == NULL) + { + // There was no previous call "ReadCurrentFrameDataset()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_); + } + + + double SeriesFrameRendererFactory::GetCurrentSliceThickness() const + { + if (currentDataset_.get() == NULL) + { + // There was no previous call "ReadCurrentFrameDataset()" + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + try + { + OrthancPlugins::DicomDatasetReader reader(*currentDataset_); + + double thickness; + if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) + { + return thickness; + } + } + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) + { + } + + // Some arbitrary large slice thickness + return std::numeric_limits::infinity(); + } + + + SeriesFrameRendererFactory::SeriesFrameRendererFactory(ISeriesLoader* loader, // Takes ownership + bool fast) : + loader_(loader), + currentFrame_(0), + fast_(fast) + { + if (loader == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + bool SeriesFrameRendererFactory::GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice) + { + if (currentDataset_.get() == NULL) + { + // There has been no previous call to + // "CreateLayerRenderer". Read some arbitrary DICOM frame, the + // one at the middle of the series. + unsigned int depth = loader_->GetGeometry().GetSliceCount(); + ReadCurrentFrameDataset(depth / 2); + } + + double spacingX, spacingY; + GetCurrentPixelSpacing(spacingX, spacingY); + + return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, + viewportSlice, + loader_->GetGeometry().GetSlice(0), + loader_->GetWidth(), + loader_->GetHeight(), + spacingX, spacingY); + } + + + ILayerRenderer* SeriesFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) + { + size_t closest; + double distance; + + bool isOpposite; + if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, loader_->GetGeometry().GetNormal(), viewportSlice.GetNormal()) || + !loader_->GetGeometry().ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin())) + { + // Unable to compute the slice in the series that is the + // closest to the slice displayed by the viewport + return NULL; + } + + ReadCurrentFrameDataset(closest); + assert(currentDataset_.get() != NULL); + + double spacingX, spacingY; + GetCurrentPixelSpacing(spacingX, spacingY); + + if (distance <= GetCurrentSliceThickness() / 2.0) + { + SliceGeometry frameSlice(*currentDataset_); + return FrameRenderer::CreateRenderer(loader_->DownloadFrame(closest), + frameSlice, + *currentDataset_, + spacingX, spacingY, + true); + } + else + { + // The closest slice of the series is too far away from the + // slice displayed by the viewport + return NULL; + } + } + + + ISliceableVolume& SeriesFrameRendererFactory::GetSourceVolume() const + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SeriesFrameRendererFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SeriesFrameRendererFactory.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,65 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRendererFactory.h" + +#include "../Toolbox/ISeriesLoader.h" + +namespace Deprecated +{ + class SeriesFrameRendererFactory : public ILayerRendererFactory + { + private: + std::auto_ptr loader_; + size_t currentFrame_; + bool fast_; + + std::auto_ptr currentDataset_; + + void ReadCurrentFrameDataset(size_t frame); + + void GetCurrentPixelSpacing(double& spacingX, + double& spacingY) const; + + double GetCurrentSliceThickness() const; + + public: + SeriesFrameRendererFactory(ISeriesLoader* loader, // Takes ownership + bool fast); + + virtual bool GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice); + + virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice); + + virtual bool HasSourceVolume() const + { + return false; + } + + virtual ISliceableVolume& GetSourceVolume() const; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SingleFrameRendererFactory.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SingleFrameRendererFactory.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,88 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "SingleFrameRendererFactory.h" + +#include "FrameRenderer.h" +#include "../Toolbox/MessagingToolbox.h" +#include "../Toolbox/DicomFrameConverter.h" + +#include +#include +#include + +namespace Deprecated +{ + SingleFrameRendererFactory::SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instanceId, + unsigned int frame) : + orthanc_(orthanc), + instance_(instanceId), + frame_(frame) + { + dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags")); + + DicomFrameConverter converter; + converter.ReadParameters(*dicom_); + format_ = converter.GetExpectedPixelFormat(); + } + + + bool SingleFrameRendererFactory::GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice) + { + // Assume that PixelSpacingX == PixelSpacingY == 1 + + OrthancPlugins::DicomDatasetReader reader(*dicom_); + + unsigned int width, height; + + if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) || + !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + x1 = 0; + y1 = 0; + x2 = static_cast(width); + y2 = static_cast(height); + + return true; + } + + + ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) + { + SliceGeometry frameSlice(*dicom_); + return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), + frameSlice, *dicom_, 1, 1, true); + } + + + ISliceableVolume& SingleFrameRendererFactory::GetSourceVolume() const + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SingleFrameRendererFactory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SingleFrameRendererFactory.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,69 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRendererFactory.h" +#include + +namespace Deprecated +{ + class SingleFrameRendererFactory : public ILayerRendererFactory + { + private: + OrthancPlugins::IOrthancConnection& orthanc_; + std::auto_ptr dicom_; + + std::string instance_; + unsigned int frame_; + Orthanc::PixelFormat format_; + + public: + SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc, + const std::string& instanceId, + unsigned int frame); + + const OrthancPlugins::IDicomDataset& GetDataset() const + { + return *dicom_; + } + + SliceGeometry GetSliceGeometry() + { + return SliceGeometry(*dicom_); + } + + virtual bool GetExtent(double& x1, + double& y1, + double& x2, + double& y2, + const SliceGeometry& viewportSlice); + + virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice); + + virtual bool HasSourceVolume() const + { + return false; + } + + virtual ISliceableVolume& GetSourceVolume() const; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SliceOutlineRenderer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SliceOutlineRenderer.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,54 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "SliceOutlineRenderer.h" + +namespace Deprecated +{ + bool SliceOutlineRenderer::RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + if (style_.visible_) + { + cairo_t *cr = context.GetObject(); + cairo_save(cr); + + context.SetSourceColor(style_.drawColor_); + + double x1 = -0.5 * pixelSpacingX_; + double y1 = -0.5 * pixelSpacingY_; + + cairo_set_line_width(cr, 1.0 / view.GetZoom()); + cairo_rectangle(cr, x1, y1, + static_cast(width_) * pixelSpacingX_, + static_cast(height_) * pixelSpacingY_); + + double handleSize = 10.0f / view.GetZoom(); + cairo_move_to(cr, x1 + handleSize, y1); + cairo_line_to(cr, x1, y1 + handleSize); + + cairo_stroke(cr); + cairo_restore(cr); + } + + return true; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Layers/SliceOutlineRenderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Layers/SliceOutlineRenderer.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,67 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "ILayerRenderer.h" +#include "../Toolbox/Slice.h" + +namespace Deprecated +{ + class SliceOutlineRenderer : public ILayerRenderer + { + private: + OrthancStone::CoordinateSystem3D geometry_; + double pixelSpacingX_; + double pixelSpacingY_; + unsigned int width_; + unsigned int height_; + RenderStyle style_; + + public: + SliceOutlineRenderer(const Slice& slice) : + geometry_(slice.GetGeometry()), + pixelSpacingX_(slice.GetPixelSpacingX()), + pixelSpacingY_(slice.GetPixelSpacingY()), + width_(slice.GetWidth()), + height_(slice.GetHeight()) + { + } + + virtual bool RenderLayer(OrthancStone::CairoContext& context, + const ViewportGeometry& view); + + virtual void SetLayerStyle(const RenderStyle& style) + { + style_ = style; + } + + virtual const OrthancStone::CoordinateSystem3D& GetLayerSlice() + { + return geometry_; + } + + virtual bool IsFullQuality() + { + return true; + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/SmartLoader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/SmartLoader.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,292 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "SmartLoader.h" + +#include "../Messages/MessageForwarder.h" +#include "../StoneException.h" +#include "Core/Images/Image.h" +#include "Core/Logging.h" +#include "Layers/DicomSeriesVolumeSlicer.h" +#include "Layers/FrameRenderer.h" +#include "Widgets/SliceViewerWidget.h" + +namespace Deprecated +{ + enum CachedSliceStatus + { + CachedSliceStatus_ScheduledToLoad, + CachedSliceStatus_GeometryLoaded, + CachedSliceStatus_ImageLoaded + }; + + class SmartLoader::CachedSlice : public IVolumeSlicer + { + public: + class RendererFactory : public LayerReadyMessage::IRendererFactory + { + private: + const CachedSlice& that_; + + public: + RendererFactory(const CachedSlice& that) : + that_(that) + { + } + + virtual ILayerRenderer* CreateRenderer() const + { + bool isFull = (that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPng || + that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPam); + + return FrameRenderer::CreateRenderer(*that_.image_, *that_.slice_, isFull); + } + }; + + unsigned int sliceIndex_; + std::auto_ptr slice_; + boost::shared_ptr image_; + OrthancStone::SliceImageQuality effectiveQuality_; + CachedSliceStatus status_; + + public: + CachedSlice(OrthancStone::MessageBroker& broker) : + IVolumeSlicer(broker) + { + } + + virtual ~CachedSlice() + { + } + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice) + { + // TODO: viewportSlice is not used !!!! + slice_->GetExtent(points); + return true; + } + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) + { + // TODO: viewportSlice is not used !!!! + + // it has already been loaded -> trigger the "layer ready" message immediately otherwise, do nothing now. The LayerReady will be triggered + // once the VolumeSlicer is ready + if (status_ == CachedSliceStatus_ImageLoaded) + { + LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId(); + + RendererFactory factory(*this); + BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry())); + } + else + { + LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId(); + } + } + + CachedSlice* Clone() const + { + CachedSlice* output = new CachedSlice(GetBroker()); + output->sliceIndex_ = sliceIndex_; + output->slice_.reset(slice_->Clone()); + output->image_ = image_; + output->effectiveQuality_ = effectiveQuality_; + output->status_ = status_; + + return output; + } + + }; + + + SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthancApiClient) : + IObservable(broker), + IObserver(broker), + imageQuality_(OrthancStone::SliceImageQuality_FullPam), + orthancApiClient_(orthancApiClient) + { + } + + void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer, + size_t layerIndex, + const std::string& instanceId, + unsigned int frame) + { + // TODO: check if this frame has already been loaded or is already being loaded. + // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately" + // (it can not be immediate because Observers needs to register first and this is done after this method returns) + // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward + // the messages to its observables + // in both cases, we must be carefull about objects lifecycle !!! + + std::auto_ptr layerSource; + std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); + SmartLoader::CachedSlice* cachedSlice = NULL; + + if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded) + { + layerSource.reset(cachedSlices_[sliceKeyId]->Clone()); + cachedSlice = dynamic_cast(layerSource.get()); + } + else + { + layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); + dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); + dynamic_cast(layerSource.get())->LoadFrame(instanceId, frame); + } + + // make sure that the widget registers the events before we trigger them + if (sliceViewer.GetLayerCount() == layerIndex) + { + sliceViewer.AddLayer(layerSource.release()); + } + else if (sliceViewer.GetLayerCount() > layerIndex) + { + sliceViewer.ReplaceLayer(layerIndex, layerSource.release()); + } + else + { + throw OrthancStone::StoneException(OrthancStone::ErrorCode_CanOnlyAddOneLayerAtATime); + } + + if (cachedSlice != NULL) + { + BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice)); + } + + } + + void SmartLoader::PreloadSlice(const std::string instanceId, + unsigned int frame) + { + // TODO: reactivate -> need to be able to ScheduleLayerLoading in IVolumeSlicer without calling ScheduleLayerCreation + return; + // TODO: check if it is already in the cache + + + + // create the slice in the cache with "empty" data + boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); + cachedSlice->slice_.reset(new Slice(instanceId, frame)); + cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad; + std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); + + LOG(WARNING) << "Will preload: " << sliceKeyId; + + cachedSlices_[sliceKeyId] = boost::shared_ptr(cachedSlice); + + std::auto_ptr layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); + + dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); + layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); + dynamic_cast(layerSource.get())->LoadFrame(instanceId, frame); + + // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache + preloadingInstances_[sliceKeyId] = boost::shared_ptr(layerSource.release()); + } + + +// void PreloadStudy(const std::string studyId) +// { +// /* TODO */ +// } + +// void PreloadSeries(const std::string seriesId) +// { +// /* TODO */ +// } + + + void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message) + { + const DicomSeriesVolumeSlicer& source = + dynamic_cast(message.GetOrigin()); + + // save/replace the slice in cache + const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() + std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + + boost::lexical_cast(slice.GetFrame())); + + LOG(WARNING) << "Geometry ready: " << sliceKeyId; + + boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); + cachedSlice->slice_.reset(slice.Clone()); + cachedSlice->effectiveQuality_ = source.GetImageQuality(); + cachedSlice->status_ = CachedSliceStatus_GeometryLoaded; + + cachedSlices_[sliceKeyId] = boost::shared_ptr(cachedSlice); + + // re-emit original Layer message to observers + BroadcastMessage(message); + } + + + void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message) + { + // save/replace the slice in cache + const Slice& slice = message.GetSlice(); + std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + + boost::lexical_cast(slice.GetFrame())); + + LOG(WARNING) << "Image ready: " << sliceKeyId; + + boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); + cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame())); + cachedSlice->effectiveQuality_ = message.GetImageQuality(); + cachedSlice->slice_.reset(message.GetSlice().Clone()); + cachedSlice->status_ = CachedSliceStatus_ImageLoaded; + + cachedSlices_[sliceKeyId] = cachedSlice; + + // re-emit original Layer message to observers + BroadcastMessage(message); + } + + + void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message) + { + const DicomSeriesVolumeSlicer& source = + dynamic_cast(message.GetOrigin()); + + const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ? + std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + + boost::lexical_cast(slice.GetFrame())); + + LOG(WARNING) << "Layer ready: " << sliceKeyId; + + // remove the slice from the preloading slices now that it has been fully loaded and it is referenced in the cache + if (preloadingInstances_.find(sliceKeyId) != preloadingInstances_.end()) + { + preloadingInstances_.erase(sliceKeyId); + } + + // re-emit original Layer message to observers + BroadcastMessage(message); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/SmartLoader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/SmartLoader.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,67 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once +#include + +#include "Layers/DicomSeriesVolumeSlicer.h" +#include "../Messages/IObservable.h" +#include "Toolbox/OrthancApiClient.h" + +namespace Deprecated +{ + class SliceViewerWidget; + + class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver + { + class CachedSlice; + + protected: + typedef std::map > CachedSlices; + CachedSlices cachedSlices_; + + typedef std::map > PreloadingInstances; + PreloadingInstances preloadingInstances_; + + OrthancStone::SliceImageQuality imageQuality_; + OrthancApiClient& orthancApiClient_; + + public: + SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes + +// void PreloadStudy(const std::string studyId); +// void PreloadSeries(const std::string seriesId); + void PreloadSlice(const std::string instanceId, unsigned int frame); + + void SetImageQuality(OrthancStone::SliceImageQuality imageQuality) { imageQuality_ = imageQuality; } + + void SetFrameInWidget(SliceViewerWidget& sliceViewer, size_t layerIndex, const std::string& instanceId, unsigned int frame); + + void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId); + + private: + void OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message); + void OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message); + void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message); + + }; + +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/BaseWebService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/BaseWebService.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,143 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 . + **/ + + +#include "BaseWebService.h" + +#include +#include "Framework/Messages/IObservable.h" +#include "Platforms/Generic/IOracleCommand.h" +#include + +namespace Deprecated +{ + + + class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject + { + private: + std::auto_ptr< OrthancStone::MessageHandler > userSuccessHandler_; + std::auto_ptr< OrthancStone::MessageHandler > userFailureHandler_; + std::auto_ptr< Orthanc::IDynamicObject> userPayload_; + + public: + BaseWebServicePayload(OrthancStone::MessageHandler* userSuccessHandler, + OrthancStone::MessageHandler* userFailureHandler, + Orthanc::IDynamicObject* userPayload) : + userSuccessHandler_(userSuccessHandler), + userFailureHandler_(userFailureHandler), + userPayload_(userPayload) + { + } + + void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const + { + if (userSuccessHandler_.get() != NULL) + { + // recreate a success message with the user payload + IWebService::HttpRequestSuccessMessage successMessage(message.GetUri(), + message.GetAnswer(), + message.GetAnswerSize(), + message.GetAnswerHttpHeaders(), + userPayload_.get()); + userSuccessHandler_->Apply(successMessage); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const + { + if (userFailureHandler_.get() != NULL) + { + // recreate a failure message with the user payload + IWebService::HttpRequestErrorMessage failureMessage(message.GetUri(), + userPayload_.get()); + + userFailureHandler_->Apply(failureMessage); + } + } + + }; + + + void BaseWebService::GetAsync(const std::string& uri, + const HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + unsigned int timeoutInSeconds) + { + if (cache_.find(uri) == cache_.end()) + { + GetAsyncInternal(uri, headers, + new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered + new OrthancStone::Callable + (*this, &BaseWebService::CacheAndNotifyHttpSuccess), + new OrthancStone::Callable + (*this, &BaseWebService::NotifyHttpError), + timeoutInSeconds); + } + else + { + // create a command and "post" it to the Oracle so it is executed and commited "later" + NotifyHttpSuccessLater(cache_[uri], payload, successCallback); + } + + } + + + + void BaseWebService::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) + { + if (message.HasPayload()) + { + dynamic_cast(message.GetPayload()).HandleSuccess(message); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + void BaseWebService::CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) + { + cache_[message.GetUri()] = boost::shared_ptr(new CachedHttpRequestSuccessMessage(message)); + NotifyHttpSuccess(message); + } + + void BaseWebService::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message) + { + if (message.HasPayload()) + { + dynamic_cast(message.GetPayload()).HandleFailure(message); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + + +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/BaseWebService.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/BaseWebService.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,131 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IWebService.h" + +#include +#include + +namespace Deprecated +{ + // This is an intermediate of IWebService that implements some caching on + // the HTTP GET requests + class BaseWebService : public IWebService, public OrthancStone::IObserver + { + public: + class CachedHttpRequestSuccessMessage + { + protected: + std::string uri_; + void* answer_; + size_t answerSize_; + IWebService::HttpHeaders answerHeaders_; + + public: + CachedHttpRequestSuccessMessage(const IWebService::HttpRequestSuccessMessage& message) : + uri_(message.GetUri()), + answerSize_(message.GetAnswerSize()), + answerHeaders_(message.GetAnswerHttpHeaders()) + { + answer_ = malloc(answerSize_); + memcpy(answer_, message.GetAnswer(), answerSize_); + } + + ~CachedHttpRequestSuccessMessage() + { + free(answer_); + } + + const std::string& GetUri() const + { + return uri_; + } + + const void* GetAnswer() const + { + return answer_; + } + + size_t GetAnswerSize() const + { + return answerSize_; + } + + const IWebService::HttpHeaders& GetAnswerHttpHeaders() const + { + return answerHeaders_; + } + + }; + protected: + class BaseWebServicePayload; + + bool cacheEnabled_; + std::map > cache_; // TODO: this is currently an infinite cache ! + + public: + + BaseWebService(OrthancStone::MessageBroker& broker) : + IWebService(broker), + IObserver(broker), + cacheEnabled_(true) + { + } + + virtual ~BaseWebService() + { + } + + virtual void EnableCache(bool enable) + { + cacheEnabled_ = enable; + } + + virtual void GetAsync(const std::string& uri, + const HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60); + + protected: + virtual void GetAsyncInternal(const std::string& uri, + const HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; + + virtual void NotifyHttpSuccessLater(boost::shared_ptr cachedHttpMessage, + Orthanc::IDynamicObject* payload, // takes ownership + OrthancStone::MessageHandler* successCallback) = 0; + + private: + void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); + + void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message); + + void CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); + + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/DicomFrameConverter.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,282 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "DicomFrameConverter.h" + +#include "../../Toolbox/LinearAlgebra.h" + +#include +#include +#include +#include + +namespace Deprecated +{ + static const Orthanc::DicomTag IMAGE_TAGS[] = + { + Orthanc::DICOM_TAG_BITS_STORED, + Orthanc::DICOM_TAG_DOSE_GRID_SCALING, + Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, + Orthanc::DICOM_TAG_PIXEL_REPRESENTATION, + Orthanc::DICOM_TAG_RESCALE_INTERCEPT, + Orthanc::DICOM_TAG_RESCALE_SLOPE, + Orthanc::DICOM_TAG_WINDOW_CENTER, + Orthanc::DICOM_TAG_WINDOW_WIDTH + }; + + + void DicomFrameConverter::SetDefaultParameters() + { + isSigned_ = true; + isColor_ = false; + hasRescale_ = false; + rescaleIntercept_ = 0; + rescaleSlope_ = 1; + hasDefaultWindow_ = false; + defaultWindowCenter_ = 128; + defaultWindowWidth_ = 256; + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + } + + + void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom) + { + SetDefaultParameters(); + + OrthancStone::Vector c, w; + if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) && + OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) && + c.size() > 0 && + w.size() > 0) + { + hasDefaultWindow_ = true; + defaultWindowCenter_ = static_cast(c[0]); + defaultWindowWidth_ = static_cast(w[0]); + } + + int32_t tmp; + if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION)) + { + // Type 1 tag, must be present + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + isSigned_ = (tmp == 1); + + double doseGridScaling; + bool isRTDose = false; + + if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && + dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) + { + hasRescale_ = true; + } + else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING)) + { + // This is for RT-DOSE + hasRescale_ = true; + isRTDose = true; + rescaleIntercept_ = 0; + rescaleSlope_ = doseGridScaling; + + if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED)) + { + // Type 1 tag, must be present + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + switch (tmp) + { + case 16: + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + break; + + case 32: + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + } + + std::string photometric; + if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false)) + { + photometric = Orthanc::Toolbox::StripSpaces(photometric); + } + else + { + // Type 1 tag, must be present + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + photometric_ = Orthanc::StringToPhotometricInterpretation(photometric.c_str()); + + isColor_ = (photometric != "MONOCHROME1" && + photometric != "MONOCHROME2"); + + // TODO Add more checks, e.g. on the number of bytes per value + // (cf. DicomImageInformation.h in Orthanc) + + if (!isRTDose) + { + if (isColor_) + { + expectedPixelFormat_ = Orthanc::PixelFormat_RGB24; + } + else if (isSigned_) + { + expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; + } + else + { + expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; + } + } + } + + + void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom) + { + Orthanc::DicomMap converted; + + for (size_t i = 0; i < sizeof(IMAGE_TAGS) / sizeof(Orthanc::DicomTag); i++) + { + OrthancPlugins::DicomTag tag(IMAGE_TAGS[i].GetGroup(), IMAGE_TAGS[i].GetElement()); + + std::string value; + if (dicom.GetStringValue(value, tag)) + { + converted.SetValue(IMAGE_TAGS[i], value, false); + } + } + + ReadParameters(converted); + } + + + void DicomFrameConverter::ConvertFrameInplace(std::auto_ptr& source) const + { + assert(sizeof(float) == 4); + + if (source.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + if (source->GetFormat() == GetExpectedPixelFormat() && + source->GetFormat() == Orthanc::PixelFormat_RGB24) + { + // No conversion has to be done, check out (*) + return; + } + else + { + source.reset(ConvertFrame(*source)); + } + } + + + Orthanc::ImageAccessor* DicomFrameConverter::ConvertFrame(const Orthanc::ImageAccessor& source) const + { + assert(sizeof(float) == 4); + + Orthanc::PixelFormat sourceFormat = source.GetFormat(); + + if (sourceFormat != GetExpectedPixelFormat()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); + } + + if (sourceFormat == Orthanc::PixelFormat_RGB24) + { + // This is the case of a color image. No conversion has to be done (*) + std::auto_ptr converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, + source.GetWidth(), + source.GetHeight(), + false)); + Orthanc::ImageProcessing::Copy(*converted, source); + return converted.release(); + } + else + { + assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 || + sourceFormat == Orthanc::PixelFormat_Grayscale32 || + sourceFormat == Orthanc::PixelFormat_SignedGrayscale16); + + // This is the case of a grayscale frame. Convert it to Float32. + std::auto_ptr converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, + source.GetWidth(), + source.GetHeight(), + false)); + Orthanc::ImageProcessing::Convert(*converted, source); + + // Correct rescale slope/intercept if need be + ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32); + + return converted.release(); + } + } + + + void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image, + bool useDouble) const + { + if (image.GetFormat() != Orthanc::PixelFormat_Float32) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); + } + + if (hasRescale_) + { + for (unsigned int y = 0; y < image.GetHeight(); y++) + { + float* p = reinterpret_cast(image.GetRow(y)); + + if (useDouble) + { + // Slower, accurate implementation using double + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + double value = static_cast(*p); + *p = static_cast(value * rescaleSlope_ + rescaleIntercept_); + } + } + else + { + // Fast, approximate implementation using float + for (unsigned int x = 0; x < image.GetWidth(); x++, p++) + { + *p = (*p) * static_cast(rescaleSlope_) + static_cast(rescaleIntercept_); + } + } + } + } + } + + + double DicomFrameConverter::Apply(double x) const + { + return x * rescaleSlope_ + rescaleIntercept_; + } + +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/DicomFrameConverter.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/DicomFrameConverter.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,169 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include +#include +#include + +#include + +namespace Deprecated +{ + /** + * This class is responsible for converting the pixel format of a + * DICOM frame coming from Orthanc, into a pixel format that is + * suitable for Stone, given the relevant DICOM tags: + * - Color frames will stay in the RGB24 format. + * - Grayscale frames will be converted to the Float32 format. + **/ + class DicomFrameConverter + { + private: + bool isSigned_; + bool isColor_; + bool hasRescale_; + double rescaleIntercept_; + double rescaleSlope_; + bool hasDefaultWindow_; + double defaultWindowCenter_; + double defaultWindowWidth_; + + Orthanc::PhotometricInterpretation photometric_; + Orthanc::PixelFormat expectedPixelFormat_; + + void SetDefaultParameters(); + + public: + DicomFrameConverter() + { + SetDefaultParameters(); + } + + ~DicomFrameConverter() + { + // TODO: check whether this dtor is called or not + // An MSVC warning explains that declaring an + // std::auto_ptr with a forward-declared type + // prevents its dtor from being called. Does not + // seem an issue here (only POD types inside), but + // definitely something to keep an eye on. + (void)0; + } + + // AM: this is required to serialize/deserialize it + DicomFrameConverter( + bool isSigned, + bool isColor, + bool hasRescale, + double rescaleIntercept, + double rescaleSlope, + bool hasDefaultWindow, + double defaultWindowCenter, + double defaultWindowWidth, + Orthanc::PhotometricInterpretation photometric, + Orthanc::PixelFormat expectedPixelFormat + ): + isSigned_(isSigned), + isColor_(isColor), + hasRescale_(hasRescale), + rescaleIntercept_(rescaleIntercept), + rescaleSlope_(rescaleSlope), + hasDefaultWindow_(hasDefaultWindow), + defaultWindowCenter_(defaultWindowCenter), + defaultWindowWidth_(defaultWindowWidth), + photometric_(photometric), + expectedPixelFormat_(expectedPixelFormat) + {} + + void GetParameters(bool& isSigned, + bool& isColor, + bool& hasRescale, + double& rescaleIntercept, + double& rescaleSlope, + bool& hasDefaultWindow, + double& defaultWindowCenter, + double& defaultWindowWidth, + Orthanc::PhotometricInterpretation& photometric, + Orthanc::PixelFormat& expectedPixelFormat) const + { + isSigned = isSigned_; + isColor = isColor_; + hasRescale = hasRescale_; + rescaleIntercept = rescaleIntercept_; + rescaleSlope = rescaleSlope_; + hasDefaultWindow = hasDefaultWindow_; + defaultWindowCenter = defaultWindowCenter_; + defaultWindowWidth = defaultWindowWidth_; + photometric = photometric_; + expectedPixelFormat = expectedPixelFormat_; + } + + Orthanc::PixelFormat GetExpectedPixelFormat() const + { + return expectedPixelFormat_; + } + + Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const + { + return photometric_; + } + + void ReadParameters(const Orthanc::DicomMap& dicom); + + void ReadParameters(const OrthancPlugins::IDicomDataset& dicom); + + bool HasDefaultWindow() const + { + return hasDefaultWindow_; + } + + double GetDefaultWindowCenter() const + { + return defaultWindowCenter_; + } + + double GetDefaultWindowWidth() const + { + return defaultWindowWidth_; + } + + double GetRescaleIntercept() const + { + return rescaleIntercept_; + } + + double GetRescaleSlope() const + { + return rescaleSlope_; + } + + void ConvertFrameInplace(std::auto_ptr& source) const; + + Orthanc::ImageAccessor* ConvertFrame(const Orthanc::ImageAccessor& source) const; + + void ApplyRescale(Orthanc::ImageAccessor& image, + bool useDouble) const; + + double Apply(double x) const; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/DownloadStack.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/DownloadStack.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,196 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "DownloadStack.h" + +#include + +#include + +namespace Deprecated +{ + bool DownloadStack::CheckInvariants() const + { + std::vector dequeued(nodes_.size(), true); + + int i = firstNode_; + while (i != NIL) + { + const Node& node = nodes_[i]; + + dequeued[i] = false; + + if (node.next_ != NIL && + nodes_[node.next_].prev_ != i) + { + return false; + } + + if (node.prev_ != NIL && + nodes_[node.prev_].next_ != i) + { + return false; + } + + i = nodes_[i].next_; + } + + for (size_t i = 0; i < nodes_.size(); i++) + { + if (nodes_[i].dequeued_ != dequeued[i]) + { + return false; + } + } + + return true; + } + + + DownloadStack::DownloadStack(unsigned int size) + { + nodes_.resize(size); + + if (size == 0) + { + firstNode_ = NIL; + } + else + { + for (size_t i = 0; i < size; i++) + { + nodes_[i].prev_ = static_cast(i - 1); + nodes_[i].next_ = static_cast(i + 1); + nodes_[i].dequeued_ = false; + } + + nodes_.front().prev_ = NIL; + nodes_.back().next_ = NIL; + firstNode_ = 0; + } + + assert(CheckInvariants()); + } + + + DownloadStack::~DownloadStack() + { + assert(CheckInvariants()); + } + + + bool DownloadStack::Pop(unsigned int& value) + { + assert(CheckInvariants()); + + if (firstNode_ == NIL) + { + for (size_t i = 0; i < nodes_.size(); i++) + { + assert(nodes_[i].dequeued_); + } + + return false; + } + else + { + assert(firstNode_ >= 0 && firstNode_ < static_cast(nodes_.size())); + value = firstNode_; + + Node& node = nodes_[firstNode_]; + assert(node.prev_ == NIL); + assert(!node.dequeued_); + + node.dequeued_ = true; + firstNode_ = node.next_; + + if (firstNode_ != NIL) + { + nodes_[firstNode_].prev_ = NIL; + } + + return true; + } + } + + + void DownloadStack::SetTopNodeInternal(unsigned int value) + { + assert(CheckInvariants()); + + Node& node = nodes_[value]; + + if (node.dequeued_) + { + // This node has already been processed by the download thread, nothing to do + return; + } + + // Remove the node from the list + if (node.prev_ == NIL) + { + assert(firstNode_ == static_cast(value)); + + // This is already the top node in the list, nothing to do + return; + } + + nodes_[node.prev_].next_ = node.next_; + + if (node.next_ != NIL) + { + nodes_[node.next_].prev_ = node.prev_; + } + + // Add back the node at the top of the list + assert(firstNode_ != NIL); + + Node& old = nodes_[firstNode_]; + assert(old.prev_ == NIL); + assert(!old.dequeued_); + node.prev_ = NIL; + node.next_ = firstNode_; + old.prev_ = value; + + firstNode_ = value; + } + + + void DownloadStack::SetTopNode(unsigned int value) + { + if (value >= nodes_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + SetTopNodeInternal(value); + } + + + void DownloadStack::SetTopNodePermissive(int value) + { + if (value >= 0 && + value < static_cast(nodes_.size())) + { + SetTopNodeInternal(value); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/DownloadStack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/DownloadStack.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include +#include + +namespace Deprecated +{ + class DownloadStack : public boost::noncopyable + { + private: + static const int NIL = -1; + + // This is a doubly-linked list + struct Node + { + int next_; + int prev_; + bool dequeued_; + }; + + std::vector nodes_; + int firstNode_; + + bool CheckInvariants() const; + + void SetTopNodeInternal(unsigned int value); + + public: + DownloadStack(unsigned int size); + + ~DownloadStack(); + + bool Pop(unsigned int& value); + + void SetTopNode(unsigned int value); + + void SetTopNodePermissive(int value); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/IDelayedCallExecutor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,58 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Messages/IObserver.h" +#include "../../Messages/ICallable.h" + +#include +#include + +#include +#include + +namespace Deprecated +{ + // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript). + class IDelayedCallExecutor : public boost::noncopyable + { + protected: + OrthancStone::MessageBroker& broker_; + + public: + ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage); + + IDelayedCallExecutor(OrthancStone::MessageBroker& broker) : + broker_(broker) + { + } + + + virtual ~IDelayedCallExecutor() + { + } + + + virtual void Schedule(OrthancStone::MessageHandler* callback, + unsigned int timeoutInMs = 1000) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/IWebService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/IWebService.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,55 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "IWebService.h" + +#include + + +namespace Deprecated +{ + const Orthanc::IDynamicObject& + IWebService::HttpRequestSuccessMessage::GetPayload() const + { + if (HasPayload()) + { + return *payload_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + const Orthanc::IDynamicObject& + IWebService::HttpRequestErrorMessage::GetPayload() const + { + if (HasPayload()) + { + return *payload_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/IWebService.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/IWebService.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,166 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Messages/IObserver.h" +#include "../../Messages/ICallable.h" + +#include +#include + +#include +#include + +namespace Deprecated +{ + // The IWebService performs HTTP requests. + // Since applications can run in native or WASM environment and, since + // in a WASM environment, the WebService is asynchronous, the IWebservice + // also implements an asynchronous interface: you must schedule a request + // and you'll be notified when the response/error is ready. + class IWebService : public boost::noncopyable + { + protected: + OrthancStone::MessageBroker& broker_; + + public: + typedef std::map HttpHeaders; + + class HttpRequestSuccessMessage : public OrthancStone::IMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const std::string& uri_; + const void* answer_; + size_t answerSize_; + const HttpHeaders& answerHeaders_; + const Orthanc::IDynamicObject* payload_; + + public: + HttpRequestSuccessMessage(const std::string& uri, + const void* answer, + size_t answerSize, + const HttpHeaders& answerHeaders, + const Orthanc::IDynamicObject* payload) : + uri_(uri), + answer_(answer), + answerSize_(answerSize), + answerHeaders_(answerHeaders), + payload_(payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + const void* GetAnswer() const + { + return answer_; + } + + size_t GetAnswerSize() const + { + return answerSize_; + } + + const HttpHeaders& GetAnswerHttpHeaders() const + { + return answerHeaders_; + } + + bool HasPayload() const + { + return payload_ != NULL; + } + + const Orthanc::IDynamicObject& GetPayload() const; + }; + + + class HttpRequestErrorMessage : public OrthancStone::IMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const std::string& uri_; + const Orthanc::IDynamicObject* payload_; + + public: + HttpRequestErrorMessage(const std::string& uri, + const Orthanc::IDynamicObject* payload) : + uri_(uri), + payload_(payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + bool HasPayload() const + { + return payload_ != NULL; + } + + const Orthanc::IDynamicObject& GetPayload() const; + }; + + + IWebService(OrthancStone::MessageBroker& broker) : + broker_(broker) + { + } + + + virtual ~IWebService() + { + } + + virtual void EnableCache(bool enable) = 0; + + virtual void GetAsync(const std::string& uri, + const HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; + + virtual void PostAsync(const std::string& uri, + const HttpHeaders& headers, + const std::string& body, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; + + virtual void DeleteAsync(const std::string& uri, + const HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + unsigned int timeoutInSeconds = 60) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/OrthancApiClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,336 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + +#include "OrthancApiClient.h" + +#include "../../Toolbox/MessagingToolbox.h" + +#include + +namespace Deprecated +{ + const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const + { + if (HasPayload()) + { + return *payload_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const + { + if (HasPayload()) + { + return *payload_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const + { + if (HasPayload()) + { + return *payload_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject + { + private: + std::auto_ptr< OrthancStone::MessageHandler > emptyHandler_; + std::auto_ptr< OrthancStone::MessageHandler > jsonHandler_; + std::auto_ptr< OrthancStone::MessageHandler > binaryHandler_; + std::auto_ptr< OrthancStone::MessageHandler > failureHandler_; + std::auto_ptr< Orthanc::IDynamicObject > userPayload_; + + void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const + { + if (failureHandler_.get() != NULL) + { + failureHandler_->Apply(IWebService::HttpRequestErrorMessage + (message.GetUri(), userPayload_.get())); + } + } + + public: + WebServicePayload(OrthancStone::MessageHandler* handler, + OrthancStone::MessageHandler* failureHandler, + Orthanc::IDynamicObject* userPayload) : + emptyHandler_(handler), + failureHandler_(failureHandler), + userPayload_(userPayload) + { + if (handler == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + WebServicePayload(OrthancStone::MessageHandler* handler, + OrthancStone::MessageHandler* failureHandler, + Orthanc::IDynamicObject* userPayload) : + binaryHandler_(handler), + failureHandler_(failureHandler), + userPayload_(userPayload) + { + if (handler == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + WebServicePayload(OrthancStone::MessageHandler* handler, + OrthancStone::MessageHandler* failureHandler, + Orthanc::IDynamicObject* userPayload) : + jsonHandler_(handler), + failureHandler_(failureHandler), + userPayload_(userPayload) + { + if (handler == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const + { + if (emptyHandler_.get() != NULL) + { + emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage + (message.GetUri(), userPayload_.get())); + } + else if (binaryHandler_.get() != NULL) + { + binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage + (message.GetUri(), message.GetAnswer(), + message.GetAnswerSize(), userPayload_.get())); + } + else if (jsonHandler_.get() != NULL) + { + Json::Value response; + if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) + { + jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage + (message.GetUri(), response, userPayload_.get())); + } + else + { + NotifyConversionError(message); + } + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const + { + if (failureHandler_.get() != NULL) + { + failureHandler_->Apply(IWebService::HttpRequestErrorMessage + (message.GetUri(), userPayload_.get())); + } + } + }; + + + OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker, + IWebService& web, + const std::string& baseUrl) : + IObservable(broker), + IObserver(broker), + web_(web), + baseUrl_(baseUrl) + { + } + + + void OrthancApiClient::GetJsonAsync( + const std::string& uri, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + IWebService::HttpHeaders emptyHeaders; + web_.GetAsync(baseUrl_ + uri, + emptyHeaders, + new WebServicePayload(successCallback, failureCallback, payload), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpSuccess), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpError)); + } + + + void OrthancApiClient::GetBinaryAsync( + const std::string& uri, + const std::string& contentType, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + IWebService::HttpHeaders headers; + headers["Accept"] = contentType; + GetBinaryAsync(uri, headers, successCallback, failureCallback, payload); + } + + void OrthancApiClient::GetBinaryAsync( + const std::string& uri, + const IWebService::HttpHeaders& headers, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str()); + + web_.GetAsync(baseUrl_ + uri, headers, + new WebServicePayload(successCallback, failureCallback, payload), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpSuccess), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpError)); + } + + + void OrthancApiClient::PostBinaryAsyncExpectJson( + const std::string& uri, + const std::string& body, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, + new WebServicePayload(successCallback, failureCallback, payload), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpSuccess), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpError)); + + } + + void OrthancApiClient::PostBinaryAsync( + const std::string& uri, + const std::string& body) + { + web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, NULL, NULL, NULL); + } + + void OrthancApiClient::PostBinaryAsync( + const std::string& uri, + const std::string& body, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload /* takes ownership */) + { + web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, + new WebServicePayload(successCallback, failureCallback, payload), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpSuccess), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpError)); + } + + void OrthancApiClient::PostJsonAsyncExpectJson( + const std::string& uri, + const Json::Value& data, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + std::string body; + OrthancStone::MessagingToolbox::JsonToString(body, data); + return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload); + } + + void OrthancApiClient::PostJsonAsync( + const std::string& uri, + const Json::Value& data) + { + std::string body; + OrthancStone::MessagingToolbox::JsonToString(body, data); + return PostBinaryAsync(uri, body); + } + + void OrthancApiClient::PostJsonAsync( + const std::string& uri, + const Json::Value& data, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload /* takes ownership */) + { + std::string body; + OrthancStone::MessagingToolbox::JsonToString(body, data); + return PostBinaryAsync(uri, body, successCallback, failureCallback, payload); + } + + void OrthancApiClient::DeleteAsync( + const std::string& uri, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback, + Orthanc::IDynamicObject* payload) + { + web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(), + new WebServicePayload(successCallback, failureCallback, payload), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpSuccess), + new OrthancStone::Callable + (*this, &OrthancApiClient::NotifyHttpError)); + } + + + void OrthancApiClient::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) + { + if (message.HasPayload()) + { + dynamic_cast(message.GetPayload()).HandleSuccess(message); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + void OrthancApiClient::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message) + { + if (message.HasPayload()) + { + dynamic_cast(message.GetPayload()).HandleFailure(message); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/OrthancApiClient.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,243 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include +#include + +#include "IWebService.h" +#include "../../Messages/IObservable.h" +#include "../../Messages/Promise.h" + +namespace Deprecated +{ + class OrthancApiClient : + public OrthancStone::IObservable, + public OrthancStone::IObserver + { + public: + class JsonResponseReadyMessage : public OrthancStone::IMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const std::string& uri_; + const Json::Value& json_; + const Orthanc::IDynamicObject* payload_; + + public: + JsonResponseReadyMessage(const std::string& uri, + const Json::Value& json, + const Orthanc::IDynamicObject* payload) : + uri_(uri), + json_(json), + payload_(payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + const Json::Value& GetJson() const + { + return json_; + } + + bool HasPayload() const + { + return payload_ != NULL; + } + + const Orthanc::IDynamicObject& GetPayload() const; + }; + + + class BinaryResponseReadyMessage : public OrthancStone::IMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const std::string& uri_; + const void* answer_; + size_t answerSize_; + const Orthanc::IDynamicObject* payload_; + + public: + BinaryResponseReadyMessage(const std::string& uri, + const void* answer, + size_t answerSize, + const Orthanc::IDynamicObject* payload) : + uri_(uri), + answer_(answer), + answerSize_(answerSize), + payload_(payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + const void* GetAnswer() const + { + return answer_; + } + + size_t GetAnswerSize() const + { + return answerSize_; + } + + bool HasPayload() const + { + return payload_ != NULL; + } + + const Orthanc::IDynamicObject& GetPayload() const; + }; + + + class EmptyResponseReadyMessage : public OrthancStone::IMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const std::string& uri_; + const Orthanc::IDynamicObject* payload_; + + public: + EmptyResponseReadyMessage(const std::string& uri, + const Orthanc::IDynamicObject* payload) : + uri_(uri), + payload_(payload) + { + } + + const std::string& GetUri() const + { + return uri_; + } + + bool HasPayload() const + { + return payload_ != NULL; + } + + const Orthanc::IDynamicObject& GetPayload() const; + }; + + + + private: + class WebServicePayload; + + protected: + IWebService& web_; + std::string baseUrl_; + + public: + OrthancApiClient(OrthancStone::MessageBroker& broker, + IWebService& web, + const std::string& baseUrl); + + virtual ~OrthancApiClient() + { + } + + const std::string& GetBaseUrl() const {return baseUrl_;} + + // schedule a GET request expecting a JSON response. + void GetJsonAsync(const std::string& uri, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a GET request expecting a binary response. + void GetBinaryAsync(const std::string& uri, + const std::string& contentType, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a GET request expecting a binary response. + void GetBinaryAsync(const std::string& uri, + const IWebService::HttpHeaders& headers, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a POST request expecting a JSON response. + void PostBinaryAsyncExpectJson(const std::string& uri, + const std::string& body, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a POST request expecting a JSON response. + void PostJsonAsyncExpectJson(const std::string& uri, + const Json::Value& data, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a POST request and don't mind the response. + void PostJsonAsync(const std::string& uri, + const Json::Value& data); + + // schedule a POST request and don't expect any response. + void PostJsonAsync(const std::string& uri, + const Json::Value& data, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + + // schedule a POST request and don't mind the response. + void PostBinaryAsync(const std::string& uri, + const std::string& body); + + // schedule a POST request and don't expect any response. + void PostBinaryAsync(const std::string& uri, + const std::string& body, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + // schedule a DELETE request expecting an empty response. + void DeleteAsync(const std::string& uri, + OrthancStone::MessageHandler* successCallback, + OrthancStone::MessageHandler* failureCallback = NULL, + Orthanc::IDynamicObject* payload = NULL /* takes ownership */); + + void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); + + void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message); + + private: + void HandleFromCache(const std::string& uri, + const IWebService::HttpHeaders& headers, + Orthanc::IDynamicObject* payload /* takes ownership */); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,904 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "OrthancSlicesLoader.h" + +#include "../../Toolbox/MessagingToolbox.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +/** + * TODO This is a SLOW implementation of base64 decoding, because + * "Orthanc::Toolbox::DecodeBase64()" does not work properly with + * WASM. UNDERSTAND WHY. + * https://stackoverflow.com/a/34571089/881731 + **/ +static std::string base64_decode(const std::string &in) +{ + std::string out; + + std::vector T(256,-1); + for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; + + int val=0, valb=-8; + for (size_t i = 0; i < in.size(); i++) { + unsigned char c = in[i]; + if (T[c] == -1) break; + val = (val<<6) + T[c]; + valb += 6; + if (valb>=0) { + out.push_back(char((val>>valb)&0xFF)); + valb-=8; + } + } + return out; +} + + + +namespace Deprecated +{ + class OrthancSlicesLoader::Operation : public Orthanc::IDynamicObject + { + private: + Mode mode_; + unsigned int frame_; + unsigned int sliceIndex_; + const Slice* slice_; + std::string instanceId_; + OrthancStone::SliceImageQuality quality_; + + Operation(Mode mode) : + mode_(mode) + { + } + + public: + Mode GetMode() const + { + return mode_; + } + + OrthancStone::SliceImageQuality GetQuality() const + { + assert(mode_ == Mode_LoadImage || + mode_ == Mode_LoadRawImage); + return quality_; + } + + unsigned int GetSliceIndex() const + { + assert(mode_ == Mode_LoadImage || + mode_ == Mode_LoadRawImage); + return sliceIndex_; + } + + const Slice& GetSlice() const + { + assert(mode_ == Mode_LoadImage || + mode_ == Mode_LoadRawImage); + assert(slice_ != NULL); + return *slice_; + } + + unsigned int GetFrame() const + { + assert(mode_ == Mode_FrameGeometry); + return frame_; + } + + const std::string& GetInstanceId() const + { + assert(mode_ == Mode_FrameGeometry || + mode_ == Mode_InstanceGeometry); + return instanceId_; + } + + static Operation* DownloadInstanceGeometry(const std::string& instanceId) + { + std::auto_ptr operation(new Operation(Mode_InstanceGeometry)); + operation->instanceId_ = instanceId; + return operation.release(); + } + + static Operation* DownloadFrameGeometry(const std::string& instanceId, + unsigned int frame) + { + std::auto_ptr operation(new Operation(Mode_FrameGeometry)); + operation->instanceId_ = instanceId; + operation->frame_ = frame; + return operation.release(); + } + + static Operation* DownloadSliceImage(unsigned int sliceIndex, + const Slice& slice, + OrthancStone::SliceImageQuality quality) + { + std::auto_ptr tmp(new Operation(Mode_LoadImage)); + tmp->sliceIndex_ = sliceIndex; + tmp->slice_ = &slice; + tmp->quality_ = quality; + return tmp.release(); + } + + static Operation* DownloadSliceRawImage(unsigned int sliceIndex, + const Slice& slice) + { + std::auto_ptr tmp(new Operation(Mode_LoadRawImage)); + tmp->sliceIndex_ = sliceIndex; + tmp->slice_ = &slice; + tmp->quality_ = OrthancStone::SliceImageQuality_InternalRaw; + return tmp.release(); + } + + static Operation* DownloadDicomFile(const Slice& slice) + { + std::auto_ptr tmp(new Operation(Mode_LoadDicomFile)); + tmp->slice_ = &slice; + return tmp.release(); + } + + }; + + void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation, + const Orthanc::ImageAccessor& image) + { + OrthancSlicesLoader::SliceImageReadyMessage msg + (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality()); + BroadcastMessage(msg); + } + + + void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation) + { + OrthancSlicesLoader::SliceImageErrorMessage msg + (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality()); + BroadcastMessage(msg); + } + + + void OrthancSlicesLoader::SortAndFinalizeSlices() + { + bool ok = slices_.Sort(); + + state_ = State_GeometryReady; + + if (ok) + { + LOG(INFO) << "Loaded a series with " << slices_.GetSlicesCount() << " slice(s)"; + BroadcastMessage(SliceGeometryReadyMessage(*this)); + } + else + { + LOG(ERROR) << "This series is empty"; + BroadcastMessage(SliceGeometryErrorMessage(*this)); + } + } + + void OrthancSlicesLoader::OnGeometryError(const IWebService::HttpRequestErrorMessage& message) + { + BroadcastMessage(SliceGeometryErrorMessage(*this)); + state_ = State_Error; + } + + void OrthancSlicesLoader::OnSliceImageError(const IWebService::HttpRequestErrorMessage& message) + { + NotifySliceImageError(dynamic_cast(message.GetPayload())); + state_ = State_Error; + } + + void OrthancSlicesLoader::ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& series = message.GetJson(); + Json::Value::Members instances = series.getMemberNames(); + + slices_.Reserve(instances.size()); + + for (size_t i = 0; i < instances.size(); i++) + { + OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]); + + Orthanc::DicomMap dicom; + OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + + unsigned int frames; + if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frames = 1; + } + + for (unsigned int frame = 0; frame < frames; frame++) + { + std::auto_ptr slice(new Slice); + if (slice->ParseOrthancFrame(dicom, instances[i], frame)) + { + OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); + slices_.AddSlice(geometry, slice.release()); + } + else + { + LOG(WARNING) << "Skipping invalid frame " << frame << " within instance " << instances[i]; + } + } + } + + SortAndFinalizeSlices(); + } + + void OrthancSlicesLoader::ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& tags = message.GetJson(); + const std::string& instanceId = dynamic_cast(message.GetPayload()).GetInstanceId(); + + OrthancPlugins::FullOrthancDataset dataset(tags); + + Orthanc::DicomMap dicom; + OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + + unsigned int frames; + if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frames = 1; + } + + LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)"; + + for (unsigned int frame = 0; frame < frames; frame++) + { + std::auto_ptr slice(new Slice); + if (slice->ParseOrthancFrame(dicom, instanceId, frame)) + { + OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); + slices_.AddSlice(geometry, slice.release()); + } + else + { + LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; + BroadcastMessage(SliceGeometryErrorMessage(*this)); + return; + } + } + + SortAndFinalizeSlices(); + } + + + void OrthancSlicesLoader::ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& tags = message.GetJson(); + const std::string& instanceId = dynamic_cast(message.GetPayload()).GetInstanceId(); + unsigned int frame = dynamic_cast(message.GetPayload()).GetFrame(); + + OrthancPlugins::FullOrthancDataset dataset(tags); + + state_ = State_GeometryReady; + + Orthanc::DicomMap dicom; + OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); + + std::auto_ptr slice(new Slice); + if (slice->ParseOrthancFrame(dicom, instanceId, frame)) + { + LOG(INFO) << "Loaded instance geometry " << instanceId; + + OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); + slices_.AddSlice(geometry, slice.release()); + + BroadcastMessage(SliceGeometryReadyMessage(*this)); + } + else + { + LOG(WARNING) << "Skipping invalid instance " << instanceId; + BroadcastMessage(SliceGeometryErrorMessage(*this)); + } + } + + + void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message) + { + const Operation& operation = dynamic_cast(message.GetPayload()); + std::auto_ptr image; + + try + { + image.reset(new Orthanc::PngReader); + dynamic_cast(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize()); + } + catch (Orthanc::OrthancException&) + { + NotifySliceImageError(operation); + return; + } + + if (image->GetWidth() != operation.GetSlice().GetWidth() || + image->GetHeight() != operation.GetSlice().GetHeight()) + { + NotifySliceImageError(operation); + return; + } + + if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() == + Orthanc::PixelFormat_SignedGrayscale16) + { + if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) + { + image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + } + else + { + NotifySliceImageError(operation); + return; + } + } + + NotifySliceImageSuccess(operation, *image); + } + + void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message) + { + const Operation& operation = dynamic_cast(message.GetPayload()); + std::auto_ptr image; + + try + { + image.reset(new Orthanc::PamReader); + dynamic_cast(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize()); + } + catch (Orthanc::OrthancException&) + { + NotifySliceImageError(operation); + return; + } + + if (image->GetWidth() != operation.GetSlice().GetWidth() || + image->GetHeight() != operation.GetSlice().GetHeight()) + { + NotifySliceImageError(operation); + return; + } + + if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() == + Orthanc::PixelFormat_SignedGrayscale16) + { + if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) + { + image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); + } + else + { + NotifySliceImageError(operation); + return; + } + } + + NotifySliceImageSuccess(operation, *image); + } + + + void OrthancSlicesLoader::ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Operation& operation = dynamic_cast(message.GetPayload()); + + const Json::Value& encoded = message.GetJson(); + if (encoded.type() != Json::objectValue || + !encoded.isMember("Orthanc") || + encoded["Orthanc"].type() != Json::objectValue) + { + NotifySliceImageError(operation); + return; + } + + const Json::Value& info = encoded["Orthanc"]; + if (!info.isMember("PixelData") || + !info.isMember("Stretched") || + !info.isMember("Compression") || + info["Compression"].type() != Json::stringValue || + info["PixelData"].type() != Json::stringValue || + info["Stretched"].type() != Json::booleanValue || + info["Compression"].asString() != "Jpeg") + { + NotifySliceImageError(operation); + return; + } + + bool isSigned = false; + bool isStretched = info["Stretched"].asBool(); + + if (info.isMember("IsSigned")) + { + if (info["IsSigned"].type() != Json::booleanValue) + { + NotifySliceImageError(operation); + return; + } + else + { + isSigned = info["IsSigned"].asBool(); + } + } + + std::auto_ptr reader; + + { + std::string jpeg; + //Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString()); + jpeg = base64_decode(info["PixelData"].asString()); + + try + { + reader.reset(new Orthanc::JpegReader); + dynamic_cast(*reader).ReadFromMemory(jpeg); + } + catch (Orthanc::OrthancException&) + { + NotifySliceImageError(operation); + return; + } + } + + Orthanc::PixelFormat expectedFormat = + operation.GetSlice().GetConverter().GetExpectedPixelFormat(); + + if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image + { + if (expectedFormat != Orthanc::PixelFormat_RGB24) + { + NotifySliceImageError(operation); + return; + } + + if (isSigned || isStretched) + { + NotifySliceImageError(operation); + return; + } + else + { + NotifySliceImageSuccess(operation, *reader); + return; + } + } + + if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8) + { + NotifySliceImageError(operation); + return; + } + + if (!isStretched) + { + if (expectedFormat != reader->GetFormat()) + { + NotifySliceImageError(operation); + return; + } + else + { + NotifySliceImageSuccess(operation, *reader); + return; + } + } + + int32_t stretchLow = 0; + int32_t stretchHigh = 0; + + if (!info.isMember("StretchLow") || + !info.isMember("StretchHigh") || + info["StretchLow"].type() != Json::intValue || + info["StretchHigh"].type() != Json::intValue) + { + NotifySliceImageError(operation); + return; + } + + stretchLow = info["StretchLow"].asInt(); + stretchHigh = info["StretchHigh"].asInt(); + + if (stretchLow < -32768 || + stretchHigh > 65535 || + (stretchLow < 0 && stretchHigh > 32767)) + { + // This range cannot be represented with a uint16_t or an int16_t + NotifySliceImageError(operation); + return; + } + + // Decode a grayscale JPEG 8bpp image coming from the Web viewer + std::auto_ptr image + (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false)); + + Orthanc::ImageProcessing::Convert(*image, *reader); + reader.reset(); + + float scaling = static_cast(stretchHigh - stretchLow) / 255.0f; + + if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling)) + { + float offset = static_cast(stretchLow) / scaling; + Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); + } + + NotifySliceImageSuccess(operation, *image); + } + + + class StringImage : public Orthanc::ImageAccessor + { + private: + std::string buffer_; + + public: + StringImage(Orthanc::PixelFormat format, + unsigned int width, + unsigned int height, + std::string& buffer) + { + if (buffer.size() != Orthanc::GetBytesPerPixel(format) * width * height) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); + } + + buffer_.swap(buffer); // The source buffer is now empty + + void* data = (buffer_.empty() ? NULL : &buffer_[0]); + + AssignWritable(format, width, height, + Orthanc::GetBytesPerPixel(format) * width, data); + } + }; + + void OrthancSlicesLoader::ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message) + { + const Operation& operation = dynamic_cast(message.GetPayload()); + Orthanc::GzipCompressor compressor; + + std::string raw; + compressor.Uncompress(raw, message.GetAnswer(), message.GetAnswerSize()); + + const Orthanc::DicomImageInformation& info = operation.GetSlice().GetImageInformation(); + + if (info.GetBitsAllocated() == 32 && + info.GetBitsStored() == 32 && + info.GetHighBit() == 31 && + info.GetChannelCount() == 1 && + !info.IsSigned() && + info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && + raw.size() == info.GetWidth() * info.GetHeight() * 4) + { + // This is the case of RT-DOSE (uint32_t values) + + std::auto_ptr image + (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(), + info.GetHeight(), raw)); + + // TODO - Only for big endian + for (unsigned int y = 0; y < image->GetHeight(); y++) + { + uint32_t *p = reinterpret_cast(image->GetRow(y)); + for (unsigned int x = 0; x < image->GetWidth(); x++, p++) + { + *p = le32toh(*p); + } + } + + NotifySliceImageSuccess(operation, *image); + } + else if (info.GetBitsAllocated() == 16 && + info.GetBitsStored() == 16 && + info.GetHighBit() == 15 && + info.GetChannelCount() == 1 && + !info.IsSigned() && + info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && + raw.size() == info.GetWidth() * info.GetHeight() * 2) + { + std::auto_ptr image + (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(), + info.GetHeight(), raw)); + + // TODO - Big endian ? + + NotifySliceImageSuccess(operation, *image); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + + } + + + OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc) : + OrthancStone::IObservable(broker), + OrthancStone::IObserver(broker), + orthanc_(orthanc), + state_(State_Initialization) + { + } + + + void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId) + { + if (state_ != State_Initialization) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + state_ = State_LoadingGeometry; + orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags", + new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseSeriesGeometry), + new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), + NULL); + } + } + + void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId) + { + if (state_ != State_Initialization) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + state_ = State_LoadingGeometry; + + // Tag "3004-000c" is "Grid Frame Offset Vector", which is + // mandatory to read RT DOSE, but is too long to be returned by default + orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c", + new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseInstanceGeometry), + new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), + Operation::DownloadInstanceGeometry(instanceId)); + } + } + + + void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId, + unsigned int frame) + { + if (state_ != State_Initialization) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + state_ = State_LoadingGeometry; + + orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags", + new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseFrameGeometry), + new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), + Operation::DownloadFrameGeometry(instanceId, frame)); + } + } + + + bool OrthancSlicesLoader::IsGeometryReady() const + { + return state_ == State_GeometryReady; + } + + + size_t OrthancSlicesLoader::GetSlicesCount() const + { + if (state_ != State_GeometryReady) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return slices_.GetSlicesCount(); + } + + + const Slice& OrthancSlicesLoader::GetSlice(size_t index) const + { + if (state_ != State_GeometryReady) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return dynamic_cast(slices_.GetSlicePayload(index)); + } + + + bool OrthancSlicesLoader::LookupSlice(size_t& index, + const OrthancStone::CoordinateSystem3D& plane) const + { + if (state_ != State_GeometryReady) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + double distance; + return (slices_.LookupClosestSlice(index, distance, plane) && + distance <= GetSlice(index).GetThickness() / 2.0); + } + + + void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice, + size_t index) + { + std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + + boost::lexical_cast(slice.GetFrame())); + + switch (slice.GetConverter().GetExpectedPixelFormat()) + { + case Orthanc::PixelFormat_RGB24: + uri += "/preview"; + break; + + case Orthanc::PixelFormat_Grayscale16: + uri += "/image-uint16"; + break; + + case Orthanc::PixelFormat_SignedGrayscale16: + uri += "/image-int16"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + orthanc_.GetBinaryAsync(uri, "image/png", + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::ParseSliceImagePng), + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast(index), slice, OrthancStone::SliceImageQuality_FullPng)); +} + + void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice, + size_t index) + { + std::string uri = + ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + + boost::lexical_cast(slice.GetFrame())); + + switch (slice.GetConverter().GetExpectedPixelFormat()) + { + case Orthanc::PixelFormat_RGB24: + uri += "/preview"; + break; + + case Orthanc::PixelFormat_Grayscale16: + uri += "/image-uint16"; + break; + + case Orthanc::PixelFormat_SignedGrayscale16: + uri += "/image-int16"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap", + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::ParseSliceImagePam), + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage(static_cast(index), + slice, OrthancStone::SliceImageQuality_FullPam)); + } + + + + void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice, + size_t index, + OrthancStone::SliceImageQuality quality) + { + unsigned int value; + + switch (quality) + { + case OrthancStone::SliceImageQuality_Jpeg50: + value = 50; + break; + + case OrthancStone::SliceImageQuality_Jpeg90: + value = 90; + break; + + case OrthancStone::SliceImageQuality_Jpeg95: + value = 95; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + // This requires the official Web viewer plugin to be installed! + std::string uri = ("/web-viewer/instances/jpeg" + + boost::lexical_cast(value) + + "-" + slice.GetOrthancInstanceId() + "_" + + boost::lexical_cast(slice.GetFrame())); + + orthanc_.GetJsonAsync(uri, + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::ParseSliceImageJpeg), + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceImage( + static_cast(index), slice, quality)); + } + + + + void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index, + OrthancStone::SliceImageQuality quality) + { + if (state_ != State_GeometryReady) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + const Slice& slice = GetSlice(index); + + if (slice.HasOrthancDecoding()) + { + switch (quality) + { + case OrthancStone::SliceImageQuality_FullPng: + ScheduleSliceImagePng(slice, index); + break; + case OrthancStone::SliceImageQuality_FullPam: + ScheduleSliceImagePam(slice, index); + break; + default: + ScheduleSliceImageJpeg(slice, index, quality); + } + } + else + { + std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + + boost::lexical_cast(slice.GetFrame()) + "/raw.gz"); + orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(), + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::ParseSliceRawImage), + new OrthancStone::Callable + (*this, &OrthancSlicesLoader::OnSliceImageError), + Operation::DownloadSliceRawImage( + static_cast(index), slice)); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/OrthancSlicesLoader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/OrthancSlicesLoader.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,209 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Messages/IObservable.h" +#include "../../StoneEnumerations.h" +#include "IWebService.h" +#include "OrthancApiClient.h" +#include "../../Toolbox/SlicesSorter.h" +#include "Slice.h" + +#include + + +namespace Deprecated +{ + class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryErrorMessage, OrthancSlicesLoader); + + + class SliceImageReadyMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + unsigned int sliceIndex_; + const Slice& slice_; + const Orthanc::ImageAccessor& image_; + OrthancStone::SliceImageQuality effectiveQuality_; + + public: + SliceImageReadyMessage(const OrthancSlicesLoader& origin, + unsigned int sliceIndex, + const Slice& slice, + const Orthanc::ImageAccessor& image, + OrthancStone::SliceImageQuality effectiveQuality) : + OriginMessage(origin), + sliceIndex_(sliceIndex), + slice_(slice), + image_(image), + effectiveQuality_(effectiveQuality) + { + } + + unsigned int GetSliceIndex() const + { + return sliceIndex_; + } + + const Slice& GetSlice() const + { + return slice_; + } + + const Orthanc::ImageAccessor& GetImage() const + { + return image_; + } + + OrthancStone::SliceImageQuality GetEffectiveQuality() const + { + return effectiveQuality_; + } + }; + + + class SliceImageErrorMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const Slice& slice_; + unsigned int sliceIndex_; + OrthancStone::SliceImageQuality effectiveQuality_; + + public: + SliceImageErrorMessage(const OrthancSlicesLoader& origin, + unsigned int sliceIndex, + const Slice& slice, + OrthancStone::SliceImageQuality effectiveQuality) : + OriginMessage(origin), + slice_(slice), + sliceIndex_(sliceIndex), + effectiveQuality_(effectiveQuality) + { + } + unsigned int GetSliceIndex() const + { + return sliceIndex_; + } + + const Slice& GetSlice() const + { + return slice_; + } + + OrthancStone::SliceImageQuality GetEffectiveQuality() const + { + return effectiveQuality_; + } + }; + + private: + enum State + { + State_Error, + State_Initialization, + State_LoadingGeometry, + State_GeometryReady + }; + + enum Mode + { + Mode_SeriesGeometry, + Mode_InstanceGeometry, + Mode_FrameGeometry, + Mode_LoadImage, + Mode_LoadRawImage, + Mode_LoadDicomFile + }; + + class Operation; + + OrthancApiClient& orthanc_; + State state_; + OrthancStone::SlicesSorter slices_; + + void NotifySliceImageSuccess(const Operation& operation, + const Orthanc::ImageAccessor& image); + + void NotifySliceImageError(const Operation& operation); + + void OnGeometryError(const IWebService::HttpRequestErrorMessage& message); + + void OnSliceImageError(const IWebService::HttpRequestErrorMessage& message); + + void ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); + + void ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); + + void ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); + + void ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message); + + void ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message); + + void ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message); + + void ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message); + + void ScheduleSliceImagePng(const Slice& slice, + size_t index); + + void ScheduleSliceImagePam(const Slice& slice, + size_t index); + + void ScheduleSliceImageJpeg(const Slice& slice, + size_t index, + OrthancStone::SliceImageQuality quality); + + void SortAndFinalizeSlices(); + + public: + OrthancSlicesLoader(OrthancStone::MessageBroker& broker, + //ISliceLoaderObserver& callback, + OrthancApiClient& orthancApi); + + void ScheduleLoadSeries(const std::string& seriesId); + + void ScheduleLoadInstance(const std::string& instanceId); + + void ScheduleLoadFrame(const std::string& instanceId, + unsigned int frame); + + bool IsGeometryReady() const; + + size_t GetSlicesCount() const; + + const Slice& GetSlice(size_t index) const; + + bool LookupSlice(size_t& index, + const OrthancStone::CoordinateSystem3D& plane) const; + + void ScheduleLoadSliceImage(size_t index, + OrthancStone::SliceImageQuality requestedQuality); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/Slice.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/Slice.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,367 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "Slice.h" + +#include "../../StoneEnumerations.h" +#include "../../Toolbox/GeometryToolbox.h" + +#include +#include +#include + +#include + +namespace Deprecated +{ + static bool ParseDouble(double& target, + const std::string& source) + { + try + { + target = boost::lexical_cast(source); + return true; + } + catch (boost::bad_lexical_cast&) + { + return false; + } + } + + Slice* Slice::Clone() const + { + std::auto_ptr target(new Slice()); + + target->type_ = type_; + target->orthancInstanceId_ = orthancInstanceId_; + target->sopClassUid_ = sopClassUid_; + target->frame_ = frame_; + target->frameCount_ = frameCount_; + target->geometry_ = geometry_; + target->pixelSpacingX_ = pixelSpacingX_; + target->pixelSpacingY_ = pixelSpacingY_; + target->thickness_ = thickness_; + target->width_ = width_; + target->height_ = height_; + target->converter_ = converter_; + if (imageInformation_.get() != NULL) + target->imageInformation_.reset(imageInformation_->Clone()); + + return target.release(); + } + + bool Slice::ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset, + unsigned int frame) + { + // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html + + { + std::string increment; + + if (dataset.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false)) + { + Orthanc::Toolbox::ToUpperCase(increment); + if (increment != "3004,000C") // This is the "Grid Frame Offset Vector" tag + { + LOG(ERROR) << "Bad value for the \"FrameIncrementPointer\" tag"; + return false; + } + } + } + + std::string offsetTag; + + if (!dataset.CopyToString(offsetTag, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, false) || + offsetTag.empty()) + { + LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1"; + return false; + } + + std::vector offsets; + Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\'); + + if (frameCount_ <= 1 || + offsets.size() < frameCount_ || + offsets.size() < 2 || + frame >= frameCount_) + { + LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE"; + return false; + } + + double offset0, offset1, z; + + if (!ParseDouble(offset0, offsets[0]) || + !ParseDouble(offset1, offsets[1]) || + !ParseDouble(z, offsets[frame])) + { + LOG(ERROR) << "Invalid syntax"; + return false; + } + + if (!OrthancStone::LinearAlgebra::IsCloseToZero(offset0)) + { + LOG(ERROR) << "Invalid syntax"; + return false; + } + + geometry_ = OrthancStone::CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(), + //+ 650 * geometry_.GetAxisX(), + geometry_.GetAxisX(), + geometry_.GetAxisY()); + + thickness_ = offset1 - offset0; + if (thickness_ < 0) + { + thickness_ = -thickness_; + } + + return true; + } + + + bool Slice::ParseOrthancFrame(const Orthanc::DicomMap& dataset, + const std::string& instanceId, + unsigned int frame) + { + orthancInstanceId_ = instanceId; + frame_ = frame; + type_ = Type_OrthancDecodableFrame; + imageInformation_.reset(new Orthanc::DicomImageInformation(dataset)); + + if (!dataset.CopyToString(sopClassUid_, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) || + sopClassUid_.empty()) + { + LOG(ERROR) << "Instance without a SOP class UID"; + return false; + } + + if (!dataset.ParseUnsignedInteger32(frameCount_, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) + { + frameCount_ = 1; // Assume instance with one frame + } + + if (frame >= frameCount_) + { + return false; + } + + if (!dataset.ParseUnsignedInteger32(width_, Orthanc::DICOM_TAG_COLUMNS) || + !dataset.ParseUnsignedInteger32(height_, Orthanc::DICOM_TAG_ROWS)) + { + return false; + } + + thickness_ = 100.0 * std::numeric_limits::epsilon(); + + std::string tmp; + if (dataset.CopyToString(tmp, Orthanc::DICOM_TAG_SLICE_THICKNESS, false)) + { + if (!tmp.empty() && + !ParseDouble(thickness_, tmp)) + { + return false; // Syntax error + } + } + + converter_.ReadParameters(dataset); + + OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset); + + std::string position, orientation; + if (dataset.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) && + dataset.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false)) + { + geometry_ = OrthancStone::CoordinateSystem3D(position, orientation); + + bool ok = true; + + switch (OrthancStone::StringToSopClassUid(sopClassUid_)) + { + case OrthancStone::SopClassUid_RTDose: + type_ = Type_OrthancRawFrame; + ok = ComputeRTDoseGeometry(dataset, frame); + break; + + default: + break; + } + + if (!ok) + { + LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame + << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_; + return false; + } + } + + return true; + } + + + const std::string Slice::GetOrthancInstanceId() const + { + if (type_ == Type_OrthancDecodableFrame || + type_ == Type_OrthancRawFrame) + { + return orthancInstanceId_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + + unsigned int Slice::GetFrame() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return frame_; + } + + + const OrthancStone::CoordinateSystem3D& Slice::GetGeometry() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return geometry_; + } + + + double Slice::GetThickness() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return thickness_; + } + + + double Slice::GetPixelSpacingX() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return pixelSpacingX_; + } + + + double Slice::GetPixelSpacingY() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return pixelSpacingY_; + } + + + unsigned int Slice::GetWidth() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return width_; + } + + + unsigned int Slice::GetHeight() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return height_; + } + + + const DicomFrameConverter& Slice::GetConverter() const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + return converter_; + } + + + bool Slice::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const + { + if (type_ == Type_Invalid) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + bool opposite; + return (OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, + GetGeometry().GetNormal(), + plane.GetNormal()) && + OrthancStone::LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()), + GetGeometry().ProjectAlongNormal(plane.GetOrigin()), + thickness_ / 2.0)); + } + + + void Slice::GetExtent(std::vector& points) const + { + double sx = GetPixelSpacingX(); + double sy = GetPixelSpacingY(); + double w = static_cast(GetWidth()); + double h = static_cast(GetHeight()); + + points.clear(); + points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5 * sx, -0.5 * sy)); + points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, -0.5 * sy)); + points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5 * sx, (h - 0.5) * sy)); + points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, (h - 0.5) * sy)); + } + + + const Orthanc::DicomImageInformation& Slice::GetImageInformation() const + { + if (imageInformation_.get() == NULL) + { + // Only available if constructing the "Slice" object with a DICOM map + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return *imageInformation_; + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/Slice.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/Slice.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,155 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Toolbox/CoordinateSystem3D.h" +#include "DicomFrameConverter.h" + +#include +#include + +namespace Deprecated +{ + // TODO - Remove this class + class Slice : + public Orthanc::IDynamicObject /* to be used as a payload of SlicesSorter */ + { + private: + enum Type + { + Type_Invalid, + Type_Standalone, + Type_OrthancDecodableFrame, + Type_OrthancRawFrame + // TODO A slice could come from some DICOM file (URL) + }; + + bool ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset, + unsigned int frame); + + Type type_; + std::string orthancInstanceId_; + std::string sopClassUid_; + unsigned int frame_; + unsigned int frameCount_; // TODO : Redundant with "imageInformation_" + OrthancStone::CoordinateSystem3D geometry_; + double pixelSpacingX_; + double pixelSpacingY_; + double thickness_; + unsigned int width_; // TODO : Redundant with "imageInformation_" + unsigned int height_; // TODO : Redundant with "imageInformation_" + DicomFrameConverter converter_; // TODO : Partially redundant with "imageInformation_" + + std::auto_ptr imageInformation_; + + public: + Slice() : + type_(Type_Invalid) + { + } + + + // this constructor is used to reference, i.e, a slice that is being loaded + Slice(const std::string& orthancInstanceId, + unsigned int frame) : + type_(Type_Invalid), + orthancInstanceId_(orthancInstanceId), + frame_(frame) + { + } + + // TODO Is this constructor the best way to go to tackle missing + // layers within SliceViewerWidget? + Slice(const OrthancStone::CoordinateSystem3D& plane, + double thickness) : + type_(Type_Standalone), + frame_(0), + frameCount_(0), + geometry_(plane), + pixelSpacingX_(1), + pixelSpacingY_(1), + thickness_(thickness), + width_(0), + height_(0) + { + } + + Slice(const OrthancStone::CoordinateSystem3D& plane, + double pixelSpacingX, + double pixelSpacingY, + double thickness, + unsigned int width, + unsigned int height, + const DicomFrameConverter& converter) : + type_(Type_Standalone), + frameCount_(1), + geometry_(plane), + pixelSpacingX_(pixelSpacingX), + pixelSpacingY_(pixelSpacingY), + thickness_(thickness), + width_(width), + height_(height), + converter_(converter) + { + } + + bool IsValid() const + { + return type_ != Type_Invalid; + } + + bool ParseOrthancFrame(const Orthanc::DicomMap& dataset, + const std::string& instanceId, + unsigned int frame); + + bool HasOrthancDecoding() const + { + return type_ == Type_OrthancDecodableFrame; + } + + const std::string GetOrthancInstanceId() const; + + unsigned int GetFrame() const; + + const OrthancStone::CoordinateSystem3D& GetGeometry() const; + + double GetThickness() const; + + double GetPixelSpacingX() const; + + double GetPixelSpacingY() const; + + unsigned int GetWidth() const; + + unsigned int GetHeight() const; + + const DicomFrameConverter& GetConverter() const; + + bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const; + + void GetExtent(std::vector& points) const; + + const Orthanc::DicomImageInformation& GetImageInformation() const; + + Slice* Clone() const; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/ViewportGeometry.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/ViewportGeometry.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,217 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "ViewportGeometry.h" + +#include +#include + +#include + +namespace Deprecated +{ + void ViewportGeometry::ComputeTransform() + { + // The following lines must be read in reverse order! + cairo_matrix_t tmp; + + // Bring the center of the scene to the center of the view + cairo_matrix_init_translate(&transform_, + panX_ + static_cast(width_) / 2.0, + panY_ + static_cast(height_) / 2.0); + + // Apply the zoom around (0,0) + cairo_matrix_init_scale(&tmp, zoom_, zoom_); + cairo_matrix_multiply(&transform_, &tmp, &transform_); + + // Bring the center of the scene to (0,0) + cairo_matrix_init_translate(&tmp, + -(sceneExtent_.GetX1() + sceneExtent_.GetX2()) / 2.0, + -(sceneExtent_.GetY1() + sceneExtent_.GetY2()) / 2.0); + cairo_matrix_multiply(&transform_, &tmp, &transform_); + } + + + ViewportGeometry::ViewportGeometry() + { + width_ = 0; + height_ = 0; + + zoom_ = 1; + panX_ = 0; + panY_ = 0; + + ComputeTransform(); + } + + + void ViewportGeometry::SetDisplaySize(unsigned int width, + unsigned int height) + { + if (width_ != width || + height_ != height) + { + LOG(INFO) << "New display size: " << width << "x" << height; + + width_ = width; + height_ = height; + + ComputeTransform(); + } + } + + + void ViewportGeometry::SetSceneExtent(const OrthancStone::Extent2D& extent) + { + LOG(INFO) << "New scene extent: (" + << extent.GetX1() << "," << extent.GetY1() << ") => (" + << extent.GetX2() << "," << extent.GetY2() << ")"; + + sceneExtent_ = extent; + ComputeTransform(); + } + + + void ViewportGeometry::MapDisplayToScene(double& sceneX /* out */, + double& sceneY /* out */, + double x, + double y) const + { + cairo_matrix_t transform = transform_; + + if (cairo_matrix_invert(&transform) != CAIRO_STATUS_SUCCESS) + { + LOG(ERROR) << "Cannot invert singular matrix"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + sceneX = x; + sceneY = y; + cairo_matrix_transform_point(&transform, &sceneX, &sceneY); + } + + + void ViewportGeometry::MapSceneToDisplay(int& displayX /* out */, + int& displayY /* out */, + double x, + double y) const + { + cairo_matrix_transform_point(&transform_, &x, &y); + + displayX = static_cast(boost::math::iround(x)); + displayY = static_cast(boost::math::iround(y)); + } + + + void ViewportGeometry::MapPixelCenterToScene(std::vector& sceneTouches /* out */, + const std::vector& displayTouches) const + { + double sceneX, sceneY; + sceneTouches.clear(); + for (size_t t = 0; t < displayTouches.size(); t++) + { + MapPixelCenterToScene( + sceneX, + sceneY, + static_cast(displayTouches[t].x), + static_cast(displayTouches[t].y)); + + sceneTouches.push_back(Touch((float)sceneX, (float)sceneY)); + } + } + + void ViewportGeometry::MapPixelCenterToScene(double& sceneX, + double& sceneY, + int x, + int y) const + { + // Take the center of the pixel + MapDisplayToScene(sceneX, sceneY, + static_cast(x) + 0.5, + static_cast(y) + 0.5); + } + + + void ViewportGeometry::FitContent() + { + if (width_ > 0 && + height_ > 0 && + !sceneExtent_.IsEmpty()) + { + double zoomX = static_cast(width_) / (sceneExtent_.GetX2() - sceneExtent_.GetX1()); + double zoomY = static_cast(height_) / (sceneExtent_.GetY2() - sceneExtent_.GetY1()); + zoom_ = zoomX < zoomY ? zoomX : zoomY; + + panX_ = 0; + panY_ = 0; + + ComputeTransform(); + } + } + + + void ViewportGeometry::ApplyTransform(OrthancStone::CairoContext& context) const + { + cairo_set_matrix(context.GetObject(), &transform_); + } + + + void ViewportGeometry::GetPan(double& x, + double& y) const + { + x = panX_; + y = panY_; + } + + + void ViewportGeometry::SetPan(double x, + double y) + { + panX_ = x; + panY_ = y; + ComputeTransform(); + } + + + void ViewportGeometry::SetZoom(double zoom) + { + zoom_ = zoom; + ComputeTransform(); + } + + + OrthancStone::Matrix ViewportGeometry::GetMatrix() const + { + OrthancStone::Matrix m(3, 3); + + m(0, 0) = transform_.xx; + m(0, 1) = transform_.xy; + m(0, 2) = transform_.x0; + m(1, 0) = transform_.yx; + m(1, 1) = transform_.yy; + m(1, 2) = transform_.y0; + m(2, 0) = 0; + m(2, 1) = 0; + m(2, 2) = 1; + + return m; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Toolbox/ViewportGeometry.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Toolbox/ViewportGeometry.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,110 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Viewport/CairoContext.h" +#include "../../Toolbox/Extent2D.h" +#include "../../Toolbox/LinearAlgebra.h" +#include "../Viewport/IMouseTracker.h" // to include "Touch" definition + +namespace Deprecated +{ + class ViewportGeometry + { + private: + // Extent of the scene (in world units) + OrthancStone::Extent2D sceneExtent_; + + // Size of the display (in pixels) + unsigned int width_; + unsigned int height_; + + // Zoom/pan + double zoom_; + double panX_; // In pixels (display units) + double panY_; + + cairo_matrix_t transform_; // Scene-to-display transformation + + void ComputeTransform(); + + public: + ViewportGeometry(); + + void SetDisplaySize(unsigned int width, + unsigned int height); + + void SetSceneExtent(const OrthancStone::Extent2D& extent); + + const OrthancStone::Extent2D& GetSceneExtent() const + { + return sceneExtent_; + } + + void MapDisplayToScene(double& sceneX /* out */, + double& sceneY /* out */, + double x, + double y) const; + + void MapPixelCenterToScene(double& sceneX /* out */, + double& sceneY /* out */, + int x, + int y) const; + + void MapPixelCenterToScene(std::vector& sceneTouches /* out */, + const std::vector& displayTouches) const; + + void MapSceneToDisplay(int& displayX /* out */, + int& displayY /* out */, + double x, + double y) const; + + unsigned int GetDisplayWidth() const + { + return width_; + } + + unsigned int GetDisplayHeight() const + { + return height_; + } + + double GetZoom() const + { + return zoom_; + } + + void FitContent(); + + void ApplyTransform(OrthancStone::CairoContext& context) const; + + void GetPan(double& x, + double& y) const; + + void SetPan(double x, + double y); + + void SetZoom(double zoom); + + OrthancStone::Matrix GetMatrix() const; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Viewport/IMouseTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Viewport/IMouseTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,66 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Viewport/CairoSurface.h" +#include + +namespace Deprecated +{ + struct Touch + { + float x; + float y; + + Touch(float x, float y) + : x(x), + y(y) + { + } + Touch() + : x(0.0f), + y(0.0f) + { + } + }; + + + // this is tracking a mouse in screen coordinates/pixels unlike + // the IWorldSceneMouseTracker that is tracking a mouse + // in scene coordinates/mm. + class IMouseTracker : public boost::noncopyable + { + public: + virtual ~IMouseTracker() + { + } + + virtual void Render(Orthanc::ImageAccessor& surface) = 0; + + virtual void MouseUp() = 0; + + // Returns "true" iff. the background scene must be repainted + virtual void MouseMove(int x, + int y, + const std::vector& displayTouches) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Viewport/IStatusBar.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Viewport/IStatusBar.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,40 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include +#include + +namespace Deprecated +{ + class IStatusBar : public boost::noncopyable + { + public: + virtual ~IStatusBar() + { + } + + virtual void ClearMessage() = 0; + + virtual void SetMessage(const std::string& message) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Viewport/IViewport.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Viewport/IViewport.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,95 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IStatusBar.h" +#include "../../StoneEnumerations.h" +#include "../../Messages/IObservable.h" + +#include +#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition + +namespace Deprecated +{ + class IWidget; // Forward declaration + + class IViewport : public OrthancStone::IObservable + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport); + + IViewport(OrthancStone::MessageBroker& broker) : + IObservable(broker) + { + } + + virtual ~IViewport() + { + } + + virtual void FitContent() = 0; + + virtual void SetStatusBar(IStatusBar& statusBar) = 0; + + virtual void SetSize(unsigned int width, + unsigned int height) = 0; + + // The function returns "true" iff. a new frame was rendered + virtual bool Render(Orthanc::ImageAccessor& surface) = 0; + + virtual void MouseDown(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) = 0; + + virtual void MouseUp() = 0; + + virtual void MouseMove(int x, + int y, + const std::vector& displayTouches) = 0; + + virtual void MouseEnter() = 0; + + virtual void MouseLeave() = 0; + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) = 0; + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) = 0; + + virtual bool HasAnimation() = 0; + + virtual void DoAnimation() = 0; + + // Should only be called from IWidget + // TODO Why should this be virtual? + virtual void NotifyContentChanged() + { + BroadcastMessage(ViewportChangedMessage(*this)); + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Viewport/WidgetViewport.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Viewport/WidgetViewport.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,289 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "WidgetViewport.h" + +#include +#include + +namespace Deprecated +{ + WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) : + IViewport(broker), + statusBar_(NULL), + isMouseOver_(false), + lastMouseX_(0), + lastMouseY_(0), + backgroundChanged_(false) + { + } + + + void WidgetViewport::FitContent() + { + if (centralWidget_.get() != NULL) + { + centralWidget_->FitContent(); + } + } + + + void WidgetViewport::SetStatusBar(IStatusBar& statusBar) + { + statusBar_ = &statusBar; + + if (centralWidget_.get() != NULL) + { + centralWidget_->SetStatusBar(statusBar); + } + } + + + IWidget& WidgetViewport::SetCentralWidget(IWidget* widget) + { + if (widget == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + mouseTracker_.reset(NULL); + + centralWidget_.reset(widget); + centralWidget_->SetViewport(*this); + + if (statusBar_ != NULL) + { + centralWidget_->SetStatusBar(*statusBar_); + } + + NotifyBackgroundChanged(); + + return *widget; + } + + + void WidgetViewport::NotifyBackgroundChanged() + { + backgroundChanged_ = true; + NotifyContentChanged(); + } + + + void WidgetViewport::SetSize(unsigned int width, + unsigned int height) + { + background_.SetSize(width, height, false /* no alpha */); + + if (centralWidget_.get() != NULL) + { + centralWidget_->SetSize(width, height); + } + + NotifyBackgroundChanged(); + } + + + bool WidgetViewport::Render(Orthanc::ImageAccessor& surface) + { + if (centralWidget_.get() == NULL) + { + return false; + } + + Orthanc::ImageAccessor background; + background_.GetWriteableAccessor(background); + + if (backgroundChanged_ && + !centralWidget_->Render(background)) + { + return false; + } + + if (background.GetWidth() != surface.GetWidth() || + background.GetHeight() != surface.GetHeight()) + { + return false; + } + + Orthanc::ImageProcessing::Convert(surface, background); + + if (mouseTracker_.get() != NULL) + { + mouseTracker_->Render(surface); + } + else if (isMouseOver_) + { + centralWidget_->RenderMouseOver(surface, lastMouseX_, lastMouseY_); + } + + return true; + } + + void WidgetViewport::TouchStart(const std::vector& displayTouches) + { + MouseDown(OrthancStone::MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, OrthancStone::KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates + } + + void WidgetViewport::TouchMove(const std::vector& displayTouches) + { + MouseMove((int)displayTouches[0].x, (int)displayTouches[0].y, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates + } + + void WidgetViewport::TouchEnd(const std::vector& displayTouches) + { + // note: TouchEnd is not triggered when a single touch gesture ends (it is only triggered when + // going from 2 touches to 1 touch, ...) + MouseUp(); + } + + void WidgetViewport::MouseDown(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& displayTouches + ) + { + lastMouseX_ = x; + lastMouseY_ = y; + + if (centralWidget_.get() != NULL) + { + mouseTracker_.reset(centralWidget_->CreateMouseTracker(button, x, y, modifiers, displayTouches)); + } + else + { + mouseTracker_.reset(NULL); + } + + NotifyContentChanged(); + } + + + void WidgetViewport::MouseUp() + { + if (mouseTracker_.get() != NULL) + { + mouseTracker_->MouseUp(); + mouseTracker_.reset(NULL); + NotifyContentChanged(); + } + } + + + void WidgetViewport::MouseMove(int x, + int y, + const std::vector& displayTouches) + { + if (centralWidget_.get() == NULL) + { + return; + } + + lastMouseX_ = x; + lastMouseY_ = y; + + bool repaint = false; + + if (mouseTracker_.get() != NULL) + { + mouseTracker_->MouseMove(x, y, displayTouches); + repaint = true; + } + else + { + repaint = centralWidget_->HasRenderMouseOver(); + } + + if (repaint) + { + // The scene must be repainted, notify the observers + NotifyContentChanged(); + } + } + + + void WidgetViewport::MouseEnter() + { + isMouseOver_ = true; + NotifyContentChanged(); + } + + + void WidgetViewport::MouseLeave() + { + isMouseOver_ = false; + + if (mouseTracker_.get() != NULL) + { + mouseTracker_->MouseUp(); + mouseTracker_.reset(NULL); + } + + NotifyContentChanged(); + } + + + void WidgetViewport::MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + if (centralWidget_.get() != NULL && + mouseTracker_.get() == NULL) + { + centralWidget_->MouseWheel(direction, x, y, modifiers); + } + } + + + void WidgetViewport::KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) + { + if (centralWidget_.get() != NULL && + mouseTracker_.get() == NULL) + { + centralWidget_->KeyPressed(key, keyChar, modifiers); + } + } + + + bool WidgetViewport::HasAnimation() + { + if (centralWidget_.get() != NULL) + { + return centralWidget_->HasAnimation(); + } + else + { + return false; + } + } + + + void WidgetViewport::DoAnimation() + { + if (centralWidget_.get() != NULL) + { + centralWidget_->DoAnimation(); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Viewport/WidgetViewport.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Viewport/WidgetViewport.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,94 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IViewport.h" +#include "../Widgets/IWidget.h" + +#include + +namespace Deprecated +{ + class WidgetViewport : public IViewport + { + private: + std::auto_ptr centralWidget_; + IStatusBar* statusBar_; + std::auto_ptr mouseTracker_; + bool isMouseOver_; + int lastMouseX_; + int lastMouseY_; + OrthancStone::CairoSurface background_; + bool backgroundChanged_; + + public: + WidgetViewport(OrthancStone::MessageBroker& broker); + + virtual void FitContent(); + + virtual void SetStatusBar(IStatusBar& statusBar); + + IWidget& SetCentralWidget(IWidget* widget); // Takes ownership + + virtual void NotifyBackgroundChanged(); + + virtual void SetSize(unsigned int width, + unsigned int height); + + virtual bool Render(Orthanc::ImageAccessor& surface); + + virtual void MouseDown(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& displayTouches); + + virtual void MouseUp(); + + virtual void MouseMove(int x, + int y, + const std::vector& displayTouches); + + virtual void MouseEnter(); + + virtual void MouseLeave(); + + virtual void TouchStart(const std::vector& touches); + + virtual void TouchMove(const std::vector& touches); + + virtual void TouchEnd(const std::vector& touches); + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers); + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers); + + virtual bool HasAnimation(); + + virtual void DoAnimation(); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Volumes/ISlicedVolume.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Volumes/ISlicedVolume.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,77 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Messages/IObservable.h" +#include "../Toolbox/Slice.h" + +namespace Deprecated +{ + class ISlicedVolume : public OrthancStone::IObservable + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, ISlicedVolume); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, ISlicedVolume); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, ISlicedVolume); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeReadyMessage, ISlicedVolume); + + + class SliceContentChangedMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + size_t sliceIndex_; + const Slice& slice_; + + public: + SliceContentChangedMessage(ISlicedVolume& origin, + size_t sliceIndex, + const Slice& slice) : + OriginMessage(origin), + sliceIndex_(sliceIndex), + slice_(slice) + { + } + + size_t GetSliceIndex() const + { + return sliceIndex_; + } + + const Slice& GetSlice() const + { + return slice_; + } + }; + + + ISlicedVolume(OrthancStone::MessageBroker& broker) : + IObservable(broker) + { + } + + virtual size_t GetSliceCount() const = 0; + + virtual const Slice& GetSlice(size_t slice) const = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Volumes/IVolumeLoader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Volumes/IVolumeLoader.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,40 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Messages/IObservable.h" + +namespace Deprecated +{ + class IVolumeLoader : public OrthancStone::IObservable + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader); + + IVolumeLoader(OrthancStone::MessageBroker& broker) : + IObservable(broker) + { + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Volumes/StructureSetLoader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,116 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "StructureSetLoader.h" + +#include "../../Toolbox/MessagingToolbox.h" + +#include + +namespace Deprecated +{ + StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc) : + IVolumeLoader(broker), + IObserver(broker), + orthanc_(orthanc) + { + } + + + void StructureSetLoader::OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message) + { + OrthancPlugins::FullOrthancDataset dataset(message.GetJson()); + + Orthanc::DicomMap slice; + OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset); + structureSet_->AddReferencedSlice(slice); + + BroadcastMessage(ContentChangedMessage(*this)); + } + + + void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message) + { + OrthancPlugins::FullOrthancDataset dataset(message.GetJson()); + structureSet_.reset(new OrthancStone::DicomStructureSet(dataset)); + + std::set instances; + structureSet_->GetReferencedInstances(instances); + + for (std::set::const_iterator it = instances.begin(); + it != instances.end(); ++it) + { + orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it, + new OrthancStone::Callable(*this, &StructureSetLoader::OnLookupCompleted)); + } + + BroadcastMessage(GeometryReadyMessage(*this)); + } + + + void StructureSetLoader::OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& lookup = message.GetJson(); + + if (lookup.type() != Json::arrayValue || + lookup.size() != 1 || + !lookup[0].isMember("Type") || + !lookup[0].isMember("Path") || + lookup[0]["Type"].type() != Json::stringValue || + lookup[0]["ID"].type() != Json::stringValue || + lookup[0]["Type"].asString() != "Instance") + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + + const std::string& instance = lookup[0]["ID"].asString(); + orthanc_.GetJsonAsync("/instances/" + instance + "/tags", + new OrthancStone::Callable(*this, &StructureSetLoader::OnReferencedSliceLoaded)); + } + + + void StructureSetLoader::ScheduleLoadInstance(const std::string& instance) + { + if (structureSet_.get() != NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050", + new OrthancStone::Callable(*this, &StructureSetLoader::OnStructureSetLoaded)); + } + } + + + OrthancStone::DicomStructureSet& StructureSetLoader::GetStructureSet() + { + if (structureSet_.get() == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return *structureSet_; + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Volumes/StructureSetLoader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Volumes/StructureSetLoader.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,57 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Toolbox/DicomStructureSet.h" +#include "../Toolbox/OrthancApiClient.h" +#include "IVolumeLoader.h" + +namespace Deprecated +{ + class StructureSetLoader : + public IVolumeLoader, + public OrthancStone::IObserver + { + private: + OrthancApiClient& orthanc_; + std::auto_ptr structureSet_; + + void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message); + + void OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message); + + void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message); + + public: + StructureSetLoader(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc); + + void ScheduleLoadInstance(const std::string& instance); + + bool HasStructureSet() const + { + return structureSet_.get() != NULL; + } + + OrthancStone::DicomStructureSet& GetStructureSet(); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/CairoWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/CairoWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,101 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "CairoWidget.h" + +#include +#include + +namespace Deprecated +{ + static bool IsAligned(const Orthanc::ImageAccessor& target) + { + // TODO + return true; + } + + CairoWidget::CairoWidget(const std::string& name) : + WidgetBase(name) + { + } + + void CairoWidget::SetSize(unsigned int width, + unsigned int height) + { + surface_.SetSize(width, height, false /* no alpha */); + } + + + bool CairoWidget::Render(Orthanc::ImageAccessor& target) + { + // Don't call the base class here, as + // "ClearBackgroundCairo()" is a faster alternative + + if (IsAligned(target)) + { + OrthancStone::CairoSurface surface(target, false /* no alpha */); + OrthancStone::CairoContext context(surface); + ClearBackgroundCairo(context); + return RenderCairo(context); + } + else + { + OrthancStone::CairoContext context(surface_); + ClearBackgroundCairo(context); + + if (RenderCairo(context)) + { + Orthanc::ImageAccessor surface; + surface_.GetReadOnlyAccessor(surface); + Orthanc::ImageProcessing::Copy(target, surface); + return true; + } + else + { + return false; + } + } + } + + + void CairoWidget::RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y) + { + if (IsAligned(target)) + { + OrthancStone::CairoSurface surface(target, false /* no alpha */); + OrthancStone::CairoContext context(surface); + RenderMouseOverCairo(context, x, y); + } + else + { + Orthanc::ImageAccessor accessor; + surface_.GetWriteableAccessor(accessor); + Orthanc::ImageProcessing::Copy(accessor, target); + + OrthancStone::CairoContext context(surface_); + RenderMouseOverCairo(context, x, y); + + Orthanc::ImageProcessing::Copy(target, accessor); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/CairoWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/CairoWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,52 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WidgetBase.h" + +namespace Deprecated +{ + class CairoWidget : public WidgetBase + { + private: + OrthancStone::CairoSurface surface_; + + protected: + virtual bool RenderCairo(OrthancStone::CairoContext& context) = 0; + + virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, + int x, + int y) = 0; + + public: + CairoWidget(const std::string& name); + + virtual void SetSize(unsigned int width, + unsigned int height); + + virtual bool Render(Orthanc::ImageAccessor& target); + + virtual void RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/EmptyWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/EmptyWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,41 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "EmptyWidget.h" + +#include +#include + +namespace Deprecated +{ + bool EmptyWidget::Render(Orthanc::ImageAccessor& surface) + { + // Note: This call is slow + Orthanc::ImageProcessing::Set(surface, red_, green_, blue_, 255); + return true; + } + + + void EmptyWidget::DoAnimation() + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/EmptyWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/EmptyWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,116 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IWidget.h" + +namespace Deprecated +{ + /** + * This is a test widget that simply fills its surface with an + * uniform color. + **/ + class EmptyWidget : public IWidget + { + private: + uint8_t red_; + uint8_t green_; + uint8_t blue_; + + public: + EmptyWidget(uint8_t red, + uint8_t green, + uint8_t blue) : + red_(red), + green_(green), + blue_(blue) + { + } + + virtual void FitContent() + { + } + + virtual void SetParent(IWidget& widget) + { + } + + virtual void SetViewport(WidgetViewport& viewport) + { + } + + virtual void NotifyContentChanged() + { + } + + virtual void SetStatusBar(IStatusBar& statusBar) + { + } + + virtual void SetSize(unsigned int width, + unsigned int height) + { + } + + virtual bool Render(Orthanc::ImageAccessor& surface); + + virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) + { + return NULL; + } + + virtual void RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y) + { + } + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + } + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) + { + } + + virtual bool HasAnimation() const + { + return false; + } + + virtual void DoAnimation(); + + virtual bool HasRenderMouseOver() + { + return false; + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/IWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/IWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,81 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../StoneEnumerations.h" +#include "../Viewport/IMouseTracker.h" +#include "../Viewport/IStatusBar.h" + +namespace Deprecated +{ + class WidgetViewport; // Forward declaration + + class IWidget : public boost::noncopyable + { + public: + virtual ~IWidget() + { + } + + virtual void FitContent() = 0; + + virtual void SetParent(IWidget& parent) = 0; + + virtual void SetViewport(WidgetViewport& viewport) = 0; + + virtual void SetStatusBar(IStatusBar& statusBar) = 0; + + virtual void SetSize(unsigned int width, + unsigned int height) = 0; + + virtual bool Render(Orthanc::ImageAccessor& surface) = 0; + + virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) = 0; + + virtual void RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y) = 0; + + virtual bool HasRenderMouseOver() = 0; + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) = 0; + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) = 0; + + virtual bool HasAnimation() const = 0; + + virtual void DoAnimation() = 0; + + // Subclasses can call this method to signal the display of the + // widget must be refreshed + virtual void NotifyContentChanged() = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/IWorldSceneInteractor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/IWorldSceneInteractor.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,70 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IWorldSceneMouseTracker.h" + +#include "../Toolbox/ViewportGeometry.h" +#include "../../StoneEnumerations.h" +#include "../Viewport/IStatusBar.h" + +namespace Deprecated +{ + class WorldSceneWidget; + + class IWorldSceneInteractor : public boost::noncopyable + { + public: + virtual ~IWorldSceneInteractor() + { + } + + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + OrthancStone::MouseButton button, + OrthancStone::KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector& touches) = 0; + + virtual void MouseOver(OrthancStone::CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) = 0; + + virtual void MouseWheel(WorldSceneWidget& widget, + OrthancStone::MouseWheelDirection direction, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) = 0; + + virtual void KeyPressed(WorldSceneWidget& widget, + OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,54 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "../../Viewport/CairoContext.h" +#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition + +namespace Deprecated +{ + + // this is tracking a mouse in scene coordinates/mm unlike + // the IMouseTracker that is tracking a mouse + // in screen coordinates/pixels. + class IWorldSceneMouseTracker : public boost::noncopyable + { + public: + virtual ~IWorldSceneMouseTracker() + { + } + + virtual bool HasRender() const = 0; + + virtual void Render(OrthancStone::CairoContext& context, + double zoom) = 0; + + virtual void MouseUp() = 0; + + virtual void MouseMove(int displayX, + int displayY, + double sceneX, + double sceneY, + const std::vector& displayTouches, + const std::vector& sceneTouches) = 0; + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/LayoutWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/LayoutWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,503 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "LayoutWidget.h" + +#include +#include + +#include + +namespace Deprecated +{ + class LayoutWidget::LayoutMouseTracker : public IMouseTracker + { + private: + std::auto_ptr tracker_; + int left_; + int top_; + unsigned int width_; + unsigned int height_; + + public: + LayoutMouseTracker(IMouseTracker* tracker, + int left, + int top, + unsigned int width, + unsigned int height) : + tracker_(tracker), + left_(left), + top_(top), + width_(width), + height_(height) + { + if (tracker == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + virtual void Render(Orthanc::ImageAccessor& surface) + { + Orthanc::ImageAccessor accessor; + surface.GetRegion(accessor, left_, top_, width_, height_); + tracker_->Render(accessor); + } + + virtual void MouseUp() + { + tracker_->MouseUp(); + } + + virtual void MouseMove(int x, + int y, + const std::vector& displayTouches) + { + std::vector relativeTouches; + for (size_t t = 0; t < displayTouches.size(); t++) + { + relativeTouches.push_back(Touch(displayTouches[t].x - left_, displayTouches[t].y - top_)); + } + + tracker_->MouseMove(x - left_, y - top_, relativeTouches); + } + }; + + + class LayoutWidget::ChildWidget : public boost::noncopyable + { + private: + std::auto_ptr widget_; + int left_; + int top_; + unsigned int width_; + unsigned int height_; + + public: + ChildWidget(IWidget* widget) : + widget_(widget) + { + assert(widget != NULL); + SetEmpty(); + } + + void DoAnimation() + { + if (widget_->HasAnimation()) + { + widget_->DoAnimation(); + } + } + + IWidget& GetWidget() const + { + return *widget_; + } + + void SetRectangle(unsigned int left, + unsigned int top, + unsigned int width, + unsigned int height) + { + left_ = left; + top_ = top; + width_ = width; + height_ = height; + + widget_->SetSize(width, height); + } + + void SetEmpty() + { + SetRectangle(0, 0, 0, 0); + } + + bool Contains(int x, + int y) const + { + return (x >= left_ && + y >= top_ && + x < left_ + static_cast(width_) && + y < top_ + static_cast(height_)); + } + + bool Render(Orthanc::ImageAccessor& target) + { + if (width_ == 0 || + height_ == 0) + { + return true; + } + else + { + Orthanc::ImageAccessor accessor; + target.GetRegion(accessor, left_, top_, width_, height_); + return widget_->Render(accessor); + } + } + + IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) + { + if (Contains(x, y)) + { + IMouseTracker* tracker = widget_->CreateMouseTracker(button, + x - left_, + y - top_, + modifiers, + touches); + if (tracker) + { + return new LayoutMouseTracker(tracker, left_, top_, width_, height_); + } + } + + return NULL; + } + + void RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y) + { + if (Contains(x, y)) + { + Orthanc::ImageAccessor accessor; + target.GetRegion(accessor, left_, top_, width_, height_); + + widget_->RenderMouseOver(accessor, x - left_, y - top_); + } + } + + void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + if (Contains(x, y)) + { + widget_->MouseWheel(direction, x - left_, y - top_, modifiers); + } + } + + bool HasRenderMouseOver() + { + return widget_->HasRenderMouseOver(); + } + }; + + + void LayoutWidget::ComputeChildrenExtents() + { + if (children_.size() == 0) + { + return; + } + + float internal = static_cast(paddingInternal_); + + if (width_ <= paddingLeft_ + paddingRight_ || + height_ <= paddingTop_ + paddingBottom_) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->SetEmpty(); + } + } + else if (isHorizontal_) + { + unsigned int padding = paddingLeft_ + paddingRight_ + (static_cast(children_.size()) - 1) * paddingInternal_; + float childWidth = ((static_cast(width_) - static_cast(padding)) / + static_cast(children_.size())); + + for (size_t i = 0; i < children_.size(); i++) + { + float left = static_cast(paddingLeft_) + static_cast(i) * (childWidth + internal); + float right = left + childWidth; + + if (left >= right) + { + children_[i]->SetEmpty(); + } + else + { + children_[i]->SetRectangle(static_cast(left), + paddingTop_, + boost::math::iround(right - left), + height_ - paddingTop_ - paddingBottom_); + } + } + } + else + { + unsigned int padding = paddingTop_ + paddingBottom_ + (static_cast(children_.size()) - 1) * paddingInternal_; + float childHeight = ((static_cast(height_) - static_cast(padding)) / + static_cast(children_.size())); + + for (size_t i = 0; i < children_.size(); i++) + { + float top = static_cast(paddingTop_) + static_cast(i) * (childHeight + internal); + float bottom = top + childHeight; + + if (top >= bottom) + { + children_[i]->SetEmpty(); + } + else + { + children_[i]->SetRectangle(paddingTop_, + static_cast(top), + width_ - paddingLeft_ - paddingRight_, + boost::math::iround(bottom - top)); + } + } + } + + NotifyContentChanged(*this); + } + + + LayoutWidget::LayoutWidget(const std::string& name) : + WidgetBase(name), + isHorizontal_(true), + width_(0), + height_(0), + paddingLeft_(0), + paddingTop_(0), + paddingRight_(0), + paddingBottom_(0), + paddingInternal_(0) + { + } + + + LayoutWidget::~LayoutWidget() + { + for (size_t i = 0; i < children_.size(); i++) + { + delete children_[i]; + } + } + + + void LayoutWidget::FitContent() + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->GetWidget().FitContent(); + } + } + + + void LayoutWidget::NotifyContentChanged(const IWidget& widget) + { + // One of the children has changed + WidgetBase::NotifyContentChanged(); + } + + + void LayoutWidget::SetHorizontal() + { + isHorizontal_ = true; + ComputeChildrenExtents(); + } + + + void LayoutWidget::SetVertical() + { + isHorizontal_ = false; + ComputeChildrenExtents(); + } + + + void LayoutWidget::SetPadding(unsigned int left, + unsigned int top, + unsigned int right, + unsigned int bottom, + unsigned int spacing) + { + paddingLeft_ = left; + paddingTop_ = top; + paddingRight_ = right; + paddingBottom_ = bottom; + paddingInternal_ = spacing; + } + + + void LayoutWidget::SetPadding(unsigned int padding) + { + paddingLeft_ = padding; + paddingTop_ = padding; + paddingRight_ = padding; + paddingBottom_ = padding; + paddingInternal_ = padding; + } + + + IWidget& LayoutWidget::AddWidget(IWidget* widget) // Takes ownership + { + if (widget == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + if (GetStatusBar() != NULL) + { + widget->SetStatusBar(*GetStatusBar()); + } + + children_.push_back(new ChildWidget(widget)); + widget->SetParent(*this); + + ComputeChildrenExtents(); + + if (widget->HasAnimation()) + { + hasAnimation_ = true; + } + + return *widget; + } + + + void LayoutWidget::SetStatusBar(IStatusBar& statusBar) + { + WidgetBase::SetStatusBar(statusBar); + + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->GetWidget().SetStatusBar(statusBar); + } + } + + + void LayoutWidget::SetSize(unsigned int width, + unsigned int height) + { + width_ = width; + height_ = height; + ComputeChildrenExtents(); + } + + + bool LayoutWidget::Render(Orthanc::ImageAccessor& surface) + { + if (!WidgetBase::Render(surface)) + { + return false; + } + + for (size_t i = 0; i < children_.size(); i++) + { + if (!children_[i]->Render(surface)) + { + return false; + } + } + + return true; + } + + + IMouseTracker* LayoutWidget::CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) + { + for (size_t i = 0; i < children_.size(); i++) + { + IMouseTracker* tracker = children_[i]->CreateMouseTracker(button, x, y, modifiers, touches); + if (tracker != NULL) + { + return tracker; + } + } + + return NULL; + } + + + void LayoutWidget::RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->RenderMouseOver(target, x, y); + } + } + + + void LayoutWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->MouseWheel(direction, x, y, modifiers); + } + } + + + void LayoutWidget::KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->GetWidget().KeyPressed(key, keyChar, modifiers); + } + } + + + void LayoutWidget::DoAnimation() + { + if (hasAnimation_) + { + for (size_t i = 0; i < children_.size(); i++) + { + children_[i]->DoAnimation(); + } + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + bool LayoutWidget::HasRenderMouseOver() + { + for (size_t i = 0; i < children_.size(); i++) + { + if (children_[i]->HasRenderMouseOver()) + { + return true; + } + } + + return false; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/LayoutWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/LayoutWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,134 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WidgetBase.h" + +#include +#include + +namespace Deprecated +{ + class LayoutWidget : public WidgetBase + { + private: + class LayoutMouseTracker; + class ChildWidget; + + std::vector children_; + bool isHorizontal_; + unsigned int width_; + unsigned int height_; + std::auto_ptr mouseTracker_; + unsigned int paddingLeft_; + unsigned int paddingTop_; + unsigned int paddingRight_; + unsigned int paddingBottom_; + unsigned int paddingInternal_; + bool hasAnimation_; + + void ComputeChildrenExtents(); + + public: + LayoutWidget(const std::string& name); + + virtual ~LayoutWidget(); + + virtual void FitContent(); + + virtual void NotifyContentChanged(const IWidget& widget); + + void SetHorizontal(); + + void SetVertical(); + + void SetPadding(unsigned int left, + unsigned int top, + unsigned int right, + unsigned int bottom, + unsigned int spacing); + + void SetPadding(unsigned int padding); + + unsigned int GetPaddingLeft() const + { + return paddingLeft_; + } + + unsigned int GetPaddingTop() const + { + return paddingTop_; + } + + unsigned int GetPaddingRight() const + { + return paddingRight_; + } + + unsigned int GetPaddingBottom() const + { + return paddingBottom_; + } + + unsigned int GetPaddingInternal() const + { + return paddingInternal_; + } + + IWidget& AddWidget(IWidget* widget); // Takes ownership + + virtual void SetStatusBar(IStatusBar& statusBar); + + virtual void SetSize(unsigned int width, + unsigned int height); + + virtual bool Render(Orthanc::ImageAccessor& surface); + + virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches); + + virtual void RenderMouseOver(Orthanc::ImageAccessor& target, + int x, + int y); + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers); + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers); + + virtual bool HasAnimation() const + { + return hasAnimation_; + } + + virtual void DoAnimation(); + + virtual bool HasRenderMouseOver(); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/PanMouseTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/PanMouseTracker.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,58 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "PanMouseTracker.h" + +#include +#include + +namespace Deprecated +{ + PanMouseTracker::PanMouseTracker(WorldSceneWidget& that, + int x, + int y) : + that_(that) + { + that.GetView().GetPan(originalPanX_, originalPanY_); + that.GetView().MapPixelCenterToScene(downX_, downY_, x, y); + } + + + void PanMouseTracker::Render(OrthancStone::CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void PanMouseTracker::MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches) + { + ViewportGeometry view = that_.GetView(); + view.SetPan(originalPanX_ + (x - downX_) * view.GetZoom(), + originalPanY_ + (y - downY_) * view.GetZoom()); + that_.SetView(view); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/PanMouseTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/PanMouseTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,61 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WorldSceneWidget.h" + +namespace Deprecated +{ + class PanMouseTracker : public IWorldSceneMouseTracker + { + private: + WorldSceneWidget& that_; + double originalPanX_; + double originalPanY_; + double downX_; + double downY_; + + public: + PanMouseTracker(WorldSceneWidget& that, + int x, + int y); + + virtual bool HasRender() const + { + return false; + } + + virtual void MouseUp() + { + } + + virtual void Render(OrthancStone::CairoContext& context, + double zoom); + + virtual void MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,137 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "PanZoomMouseTracker.h" + +#include +#include +#include + +namespace Deprecated +{ + Touch GetCenter(const std::vector& touches) + { + return Touch((touches[0].x + touches[1].x) / 2.0f, (touches[0].y + touches[1].y) / 2.0f); + } + + double GetDistance(const std::vector& touches) + { + float dx = touches[0].x - touches[1].x; + float dy = touches[0].y - touches[1].y; + return sqrt((double)(dx * dx) + (double)(dy * dy)); + } + + + PanZoomMouseTracker::PanZoomMouseTracker(WorldSceneWidget& that, + const std::vector& startTouches) + : that_(that), + originalZoom_(that.GetView().GetZoom()) + { + that.GetView().GetPan(originalPanX_, originalPanY_); + that.GetView().MapPixelCenterToScene(originalSceneTouches_, startTouches); + + originalDisplayCenter_ = GetCenter(startTouches); + originalSceneCenter_ = GetCenter(originalSceneTouches_); + originalDisplayDistanceBetweenTouches_ = GetDistance(startTouches); + +// printf("original Pan %f %f\n", originalPanX_, originalPanY_); +// printf("original Zoom %f \n", originalZoom_); +// printf("original distance %f \n", (float)originalDisplayDistanceBetweenTouches_); +// printf("original display touches 0 %f %f\n", startTouches[0].x, startTouches[0].y); +// printf("original display touches 1 %f %f\n", startTouches[1].x, startTouches[1].y); +// printf("original Scene center %f %f\n", originalSceneCenter_.x, originalSceneCenter_.y); + + unsigned int height = that.GetView().GetDisplayHeight(); + + if (height <= 3) + { + idle_ = true; + LOG(WARNING) << "image is too small to zoom (current height = " << height << ")"; + } + else + { + idle_ = false; + normalization_ = 1.0 / static_cast(height - 1); + } + + } + + + void PanZoomMouseTracker::Render(OrthancStone::CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void PanZoomMouseTracker::MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches) + { + ViewportGeometry view = that_.GetView(); + +// printf("Display touches 0 %f %f\n", displayTouches[0].x, displayTouches[0].y); +// printf("Display touches 1 %f %f\n", displayTouches[1].x, displayTouches[1].y); +// printf("Scene touches 0 %f %f\n", sceneTouches[0].x, sceneTouches[0].y); +// printf("Scene touches 1 %f %f\n", sceneTouches[1].x, sceneTouches[1].y); + +// printf("zoom = %f\n", view.GetZoom()); + Touch currentSceneCenter = GetCenter(sceneTouches); + double panX = originalPanX_ + (currentSceneCenter.x - originalSceneCenter_.x) * view.GetZoom(); + double panY = originalPanY_ + (currentSceneCenter.y - originalSceneCenter_.y) * view.GetZoom(); + + view.SetPan(panX, panY); + + static const double MIN_ZOOM = -4; + static const double MAX_ZOOM = 4; + + if (!idle_) + { + double currentDistanceBetweenTouches = GetDistance(displayTouches); + + double dy = static_cast(currentDistanceBetweenTouches - originalDisplayDistanceBetweenTouches_) * normalization_; // In the range [-1,1] + double z; + + // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] + if (dy < -1.0) + { + z = MIN_ZOOM; + } + else if (dy > 1.0) + { + z = MAX_ZOOM; + } + else + { + z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; + } + + z = pow(2.0, z); + + view.SetZoom(z * originalZoom_); + } + + that_.SetView(view); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/PanZoomMouseTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/PanZoomMouseTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,65 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WorldSceneWidget.h" + +namespace Deprecated +{ + class PanZoomMouseTracker : public IWorldSceneMouseTracker + { + private: + WorldSceneWidget& that_; + std::vector originalSceneTouches_; + Touch originalSceneCenter_; + Touch originalDisplayCenter_; + double originalPanX_; + double originalPanY_; + double originalZoom_; + double originalDisplayDistanceBetweenTouches_; + bool idle_; + double normalization_; + + public: + PanZoomMouseTracker(WorldSceneWidget& that, + const std::vector& startTouches); + + virtual bool HasRender() const + { + return false; + } + + virtual void MouseUp() + { + } + + virtual void Render(OrthancStone::CairoContext& context, + double zoom); + + virtual void MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/SliceViewerWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/SliceViewerWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,654 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "SliceViewerWidget.h" + +#include "../Layers/SliceOutlineRenderer.h" +#include "../../Toolbox/GeometryToolbox.h" +#include "../Layers/FrameRenderer.h" + +#include +#include + +#include + + +static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits::epsilon(); + +namespace Deprecated +{ + class SliceViewerWidget::Scene : public boost::noncopyable + { + private: + OrthancStone::CoordinateSystem3D plane_; + double thickness_; + size_t countMissing_; + std::vector renderers_; + + public: + void DeleteLayer(size_t index) + { + if (index >= renderers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + assert(countMissing_ <= renderers_.size()); + + if (renderers_[index] != NULL) + { + assert(countMissing_ < renderers_.size()); + delete renderers_[index]; + renderers_[index] = NULL; + countMissing_++; + } + } + + Scene(const OrthancStone::CoordinateSystem3D& plane, + double thickness, + size_t countLayers) : + plane_(plane), + thickness_(thickness), + countMissing_(countLayers), + renderers_(countLayers, NULL) + { + if (thickness <= 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + } + + ~Scene() + { + for (size_t i = 0; i < renderers_.size(); i++) + { + DeleteLayer(i); + } + } + + void SetLayer(size_t index, + ILayerRenderer* renderer) // Takes ownership + { + if (renderer == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + DeleteLayer(index); + + renderers_[index] = renderer; + countMissing_--; + } + + const OrthancStone::CoordinateSystem3D& GetPlane() const + { + return plane_; + } + + bool HasRenderer(size_t index) + { + return renderers_[index] != NULL; + } + + bool IsComplete() const + { + return countMissing_ == 0; + } + + unsigned int GetCountMissing() const + { + return static_cast(countMissing_); + } + + bool RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view, + const OrthancStone::CoordinateSystem3D& viewportPlane) + { + bool fullQuality = true; + cairo_t *cr = context.GetObject(); + + for (size_t i = 0; i < renderers_.size(); i++) + { + if (renderers_[i] != NULL) + { + const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane(); + + double x0, y0, x1, y1, x2, y2; + viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin()); + viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX()); + viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY()); + + /** + * Now we solve the system of linear equations Ax + b = x', given: + * A [0 ; 0] + b = [x0 ; y0] + * A [1 ; 0] + b = [x1 ; y1] + * A [0 ; 1] + b = [x2 ; y2] + * <=> + * b = [x0 ; y0] + * A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0] + * A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0] + * <=> + * b = [x0 ; y0] + * [a11 ; a21] = [x1 - x0 ; y1 - y0] + * [a12 ; a22] = [x2 - x0 ; y2 - y0] + **/ + + cairo_matrix_t transform; + cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0); + + cairo_save(cr); + cairo_transform(cr, &transform); + + if (!renderers_[i]->RenderLayer(context, view)) + { + cairo_restore(cr); + return false; + } + + cairo_restore(cr); + } + + if (renderers_[i] != NULL && + !renderers_[i]->IsFullQuality()) + { + fullQuality = false; + } + } + + if (!fullQuality) + { + double x, y; + view.MapDisplayToScene(x, y, static_cast(view.GetDisplayWidth()) / 2.0, 10); + + cairo_translate(cr, x, y); + +#if 1 + double s = 5.0 / view.GetZoom(); + cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s); +#else + // TODO Drawing filled circles makes WebAssembly crash! + cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi()); +#endif + + cairo_set_line_width(cr, 2.0 / view.GetZoom()); + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_stroke_preserve(cr); + cairo_set_source_rgb(cr, 1, 0, 0); + cairo_fill(cr); + } + + return true; + } + + void SetLayerStyle(size_t index, + const RenderStyle& style) + { + if (renderers_[index] != NULL) + { + renderers_[index]->SetLayerStyle(style); + } + } + + bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const + { + bool isOpposite; + if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, + plane.GetNormal(), + plane_.GetNormal())) + { + return false; + } + else + { + double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) - + plane_.ProjectAlongNormal(plane_.GetOrigin())); + + if (z < 0) + { + z = -z; + } + + return z <= thickness_; + } + } + + double GetThickness() const + { + return thickness_; + } + }; + + + bool SliceViewerWidget::LookupLayer(size_t& index /* out */, + const IVolumeSlicer& layer) const + { + LayersIndex::const_iterator found = layersIndex_.find(&layer); + + if (found == layersIndex_.end()) + { + return false; + } + else + { + index = found->second; + assert(index < layers_.size() && + layers_[index] == &layer); + return true; + } + } + + + void SliceViewerWidget::GetLayerExtent(OrthancStone::Extent2D& extent, + IVolumeSlicer& source) const + { + extent.Reset(); + + std::vector points; + if (source.GetExtent(points, plane_)) + { + for (size_t i = 0; i < points.size(); i++) + { + double x, y; + plane_.ProjectPoint(x, y, points[i]); + extent.AddPoint(x, y); + } + } + } + + + OrthancStone::Extent2D SliceViewerWidget::GetSceneExtent() + { + OrthancStone::Extent2D sceneExtent; + + for (size_t i = 0; i < layers_.size(); i++) + { + assert(layers_[i] != NULL); + OrthancStone::Extent2D layerExtent; + GetLayerExtent(layerExtent, *layers_[i]); + + sceneExtent.Union(layerExtent); + } + + return sceneExtent; + } + + + bool SliceViewerWidget::RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + if (currentScene_.get() != NULL) + { + return currentScene_->RenderScene(context, view, plane_); + } + else + { + return true; + } + } + + + void SliceViewerWidget::ResetPendingScene() + { + double thickness; + if (pendingScene_.get() == NULL) + { + thickness = 1.0; + } + else + { + thickness = pendingScene_->GetThickness(); + } + + pendingScene_.reset(new Scene(plane_, thickness, layers_.size())); + } + + + void SliceViewerWidget::UpdateLayer(size_t index, + ILayerRenderer* renderer, + const OrthancStone::CoordinateSystem3D& plane) + { + LOG(INFO) << "Updating layer " << index; + + std::auto_ptr tmp(renderer); + + if (renderer == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + if (index >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + assert(layers_.size() == styles_.size()); + renderer->SetLayerStyle(styles_[index]); + + if (currentScene_.get() != NULL && + currentScene_->ContainsPlane(plane)) + { + currentScene_->SetLayer(index, tmp.release()); + NotifyContentChanged(); + } + else if (pendingScene_.get() != NULL && + pendingScene_->ContainsPlane(plane)) + { + pendingScene_->SetLayer(index, tmp.release()); + + if (currentScene_.get() == NULL || + !currentScene_->IsComplete() || + pendingScene_->IsComplete()) + { + currentScene_ = pendingScene_; + NotifyContentChanged(); + } + } + } + + + SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, + const std::string& name) : + WorldSceneWidget(name), + IObserver(broker), + IObservable(broker), + started_(false) + { + SetBackgroundCleared(true); + } + + + SliceViewerWidget::~SliceViewerWidget() + { + for (size_t i = 0; i < layers_.size(); i++) + { + delete layers_[i]; + } + } + + void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer) + { + layer.RegisterObserverCallback(new OrthancStone::Callable + (*this, &SliceViewerWidget::OnGeometryReady)); + // currently ignore errors layer->RegisterObserverCallback(new Callable(*this, &SliceViewerWidget::...)); + layer.RegisterObserverCallback(new OrthancStone::Callable + (*this, &SliceViewerWidget::OnSliceChanged)); + layer.RegisterObserverCallback(new OrthancStone::Callable + (*this, &SliceViewerWidget::OnContentChanged)); + layer.RegisterObserverCallback(new OrthancStone::Callable + (*this, &SliceViewerWidget::OnLayerReady)); + layer.RegisterObserverCallback(new OrthancStone::Callable + (*this, &SliceViewerWidget::OnLayerError)); + } + + + size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer) // Takes ownership + { + if (layer == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + size_t index = layers_.size(); + layers_.push_back(layer); + styles_.push_back(RenderStyle()); + layersIndex_[layer] = index; + + ResetPendingScene(); + + ObserveLayer(*layer); + + ResetChangedLayers(); + + return index; + } + + + void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer) // Takes ownership + { + if (layer == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + if (index >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + delete layers_[index]; + layers_[index] = layer; + layersIndex_[layer] = index; + + ResetPendingScene(); + + ObserveLayer(*layer); + + InvalidateLayer(index); + } + + + void SliceViewerWidget::RemoveLayer(size_t index) + { + if (index >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + IVolumeSlicer* previousLayer = layers_[index]; + layersIndex_.erase(layersIndex_.find(previousLayer)); + layers_.erase(layers_.begin() + index); + changedLayers_.erase(changedLayers_.begin() + index); + styles_.erase(styles_.begin() + index); + + delete layers_[index]; + + currentScene_->DeleteLayer(index); + ResetPendingScene(); + + NotifyContentChanged(); + } + + + const RenderStyle& SliceViewerWidget::GetLayerStyle(size_t layer) const + { + if (layer >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + assert(layers_.size() == styles_.size()); + return styles_[layer]; + } + + + void SliceViewerWidget::SetLayerStyle(size_t layer, + const RenderStyle& style) + { + if (layer >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + assert(layers_.size() == styles_.size()); + styles_[layer] = style; + + if (currentScene_.get() != NULL) + { + currentScene_->SetLayerStyle(layer, style); + } + + if (pendingScene_.get() != NULL) + { + pendingScene_->SetLayerStyle(layer, style); + } + + NotifyContentChanged(); + } + + + void SliceViewerWidget::SetSlice(const OrthancStone::CoordinateSystem3D& plane) + { + LOG(INFO) << "Setting slice origin: (" << plane.GetOrigin()[0] + << "," << plane.GetOrigin()[1] + << "," << plane.GetOrigin()[2] << ")"; + + Deprecated::Slice displayedSlice(plane_, THIN_SLICE_THICKNESS); + + //if (!displayedSlice.ContainsPlane(slice)) + { + if (currentScene_.get() == NULL || + (pendingScene_.get() != NULL && + pendingScene_->IsComplete())) + { + currentScene_ = pendingScene_; + } + + plane_ = plane; + ResetPendingScene(); + + InvalidateAllLayers(); // TODO Removing this line avoid loading twice the image in WASM + } + + BroadcastMessage(DisplayedSliceMessage(*this, displayedSlice)); + } + + + void SliceViewerWidget::OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message) + { + size_t i; + if (LookupLayer(i, message.GetOrigin())) + { + LOG(INFO) << ": Geometry ready for layer " << i << " in " << GetName(); + + changedLayers_[i] = true; + //layers_[i]->ScheduleLayerCreation(plane_); + } + BroadcastMessage(GeometryChangedMessage(*this)); + } + + + void SliceViewerWidget::InvalidateAllLayers() + { + for (size_t i = 0; i < layers_.size(); i++) + { + assert(layers_[i] != NULL); + changedLayers_[i] = true; + + //layers_[i]->ScheduleLayerCreation(plane_); + } + } + + + void SliceViewerWidget::InvalidateLayer(size_t layer) + { + if (layer >= layers_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + assert(layers_[layer] != NULL); + changedLayers_[layer] = true; + + //layers_[layer]->ScheduleLayerCreation(plane_); + } + + + void SliceViewerWidget::OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message) + { + size_t index; + if (LookupLayer(index, message.GetOrigin())) + { + InvalidateLayer(index); + } + + BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); + } + + + void SliceViewerWidget::OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message) + { + if (message.GetSlice().ContainsPlane(plane_)) + { + size_t index; + if (LookupLayer(index, message.GetOrigin())) + { + InvalidateLayer(index); + } + } + + BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); + } + + + void SliceViewerWidget::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message) + { + size_t index; + if (LookupLayer(index, message.GetOrigin())) + { + LOG(INFO) << "Renderer ready for layer " << index; + UpdateLayer(index, message.CreateRenderer(), message.GetSlice()); + } + + BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); + } + + + void SliceViewerWidget::OnLayerError(const IVolumeSlicer::LayerErrorMessage& message) + { + size_t index; + if (LookupLayer(index, message.GetOrigin())) + { + LOG(ERROR) << "Using error renderer on layer " << index; + + // TODO + //UpdateLayer(index, new SliceOutlineRenderer(slice), slice); + + BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); + } + } + + + void SliceViewerWidget::ResetChangedLayers() + { + changedLayers_.resize(layers_.size()); + + for (size_t i = 0; i < changedLayers_.size(); i++) + { + changedLayers_[i] = false; + } + } + + + void SliceViewerWidget::DoAnimation() + { + assert(changedLayers_.size() <= layers_.size()); + + for (size_t i = 0; i < changedLayers_.size(); i++) + { + if (changedLayers_[i]) + { + layers_[i]->ScheduleLayerCreation(plane_); + } + } + + ResetChangedLayers(); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/SliceViewerWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/SliceViewerWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,155 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WorldSceneWidget.h" +#include "../Layers/IVolumeSlicer.h" +#include "../../Toolbox/Extent2D.h" +#include "../../Messages/IObserver.h" + +#include + +namespace Deprecated +{ + class SliceViewerWidget : + public WorldSceneWidget, + public OrthancStone::IObserver, + public OrthancStone::IObservable + { + public: + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryChangedMessage, SliceViewerWidget); + ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, SliceViewerWidget); + + + // TODO - Use this message in ReferenceLineSource + class DisplayedSliceMessage : public OrthancStone::OriginMessage + { + ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); + + private: + const Deprecated::Slice& slice_; + + public: + DisplayedSliceMessage(SliceViewerWidget& origin, + const Deprecated::Slice& slice) : + OriginMessage(origin), + slice_(slice) + { + } + + const Deprecated::Slice& GetSlice() const + { + return slice_; + } + }; + + private: + SliceViewerWidget(const SliceViewerWidget&); + SliceViewerWidget& operator=(const SliceViewerWidget&); + + class Scene; + + typedef std::map LayersIndex; + + bool started_; + LayersIndex layersIndex_; + std::vector layers_; + std::vector styles_; + OrthancStone::CoordinateSystem3D plane_; + std::auto_ptr currentScene_; + std::auto_ptr pendingScene_; + std::vector changedLayers_; + + bool LookupLayer(size_t& index /* out */, + const IVolumeSlicer& layer) const; + + void GetLayerExtent(OrthancStone::Extent2D& extent, + IVolumeSlicer& source) const; + + void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message); + + virtual void OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message); + + virtual void OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message); + + virtual void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message); + + virtual void OnLayerError(const IVolumeSlicer::LayerErrorMessage& message); + + void ObserveLayer(IVolumeSlicer& source); + + void ResetChangedLayers(); + + public: + SliceViewerWidget(OrthancStone::MessageBroker& broker, + const std::string& name); + + virtual OrthancStone::Extent2D GetSceneExtent(); + + protected: + virtual bool RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view); + + void ResetPendingScene(); + + void UpdateLayer(size_t index, + ILayerRenderer* renderer, + const OrthancStone::CoordinateSystem3D& plane); + + void InvalidateAllLayers(); + + void InvalidateLayer(size_t layer); + + public: + virtual ~SliceViewerWidget(); + + size_t AddLayer(IVolumeSlicer* layer); // Takes ownership + + void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership + + void RemoveLayer(size_t layerIndex); + + size_t GetLayerCount() const + { + return layers_.size(); + } + + const RenderStyle& GetLayerStyle(size_t layer) const; + + void SetLayerStyle(size_t layer, + const RenderStyle& style); + + void SetSlice(const OrthancStone::CoordinateSystem3D& plane); + + const OrthancStone::CoordinateSystem3D& GetSlice() const + { + return plane_; + } + + virtual bool HasAnimation() const + { + return true; + } + + virtual void DoAnimation(); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/TestCairoWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/TestCairoWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,126 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "TestCairoWidget.h" + +#include + + +namespace Deprecated +{ + namespace Samples + { + void TestCairoWidget::DoAnimation() + { + value_ -= 0.01f; + if (value_ < 0) + { + value_ = 1; + } + + NotifyContentChanged(); + } + + + bool TestCairoWidget::RenderCairo(OrthancStone::CairoContext& context) + { + cairo_t* cr = context.GetObject(); + + cairo_set_source_rgb (cr, .3, 0, 0); + cairo_paint(cr); + + cairo_set_source_rgb(cr, 0, 1, 0); + cairo_rectangle(cr, width_ / 4, height_ / 4, width_ / 2, height_ / 2); + cairo_set_line_width(cr, 1.0); + cairo_fill(cr); + + cairo_set_source_rgb(cr, 0, 1, value_); + cairo_rectangle(cr, width_ / 2 - 50, height_ / 2 - 50, 100, 100); + cairo_fill(cr); + + return true; + } + + + void TestCairoWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context, + int x, + int y) + { + cairo_t* cr = context.GetObject(); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle(cr, x - 5, y - 5, 10, 10); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); + + char buf[64]; + sprintf(buf, "(%d,%d)", x, y); + UpdateStatusBar(buf); + } + + + TestCairoWidget::TestCairoWidget(const std::string& name, bool animate) : + CairoWidget(name), + width_(0), + height_(0), + value_(1), + animate_(animate) + { + } + + + void TestCairoWidget::SetSize(unsigned int width, + unsigned int height) + { + CairoWidget::SetSize(width, height); + width_ = width; + height_ = height; + } + + + IMouseTracker* TestCairoWidget::CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) + { + UpdateStatusBar("Click"); + return NULL; + } + + + void TestCairoWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + UpdateStatusBar(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up"); + } + + + void TestCairoWidget::KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) + { + UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\""); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/TestCairoWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/TestCairoWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,79 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "CairoWidget.h" + +namespace Deprecated +{ + namespace Samples + { + class TestCairoWidget : public CairoWidget + { + private: + unsigned int width_; + unsigned int height_; + float value_; + bool animate_; + + protected: + virtual bool RenderCairo(OrthancStone::CairoContext& context); + + virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, + int x, + int y); + + public: + TestCairoWidget(const std::string& name, bool animate); + + virtual void SetSize(unsigned int width, + unsigned int height); + + virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches); + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers); + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers); + + virtual bool HasAnimation() const + { + return animate_; + } + + virtual void DoAnimation(); + + virtual bool HasRenderMouseOver() + { + return true; + } + }; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,149 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "TestWorldSceneWidget.h" + +#include + +#include +#include + +namespace Deprecated +{ + namespace Samples + { + class TestWorldSceneWidget::Interactor : public IWorldSceneInteractor + { + public: + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + OrthancStone::MouseButton button, + OrthancStone::KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector& touches) + { + if (statusBar) + { + char buf[64]; + sprintf(buf, "X = %0.2f, Y = %0.2f", x, y); + statusBar->SetMessage(buf); + } + + return NULL; + } + + virtual void MouseOver(OrthancStone::CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) + { + double S = 0.5; + + if (fabs(x) <= S && + fabs(y) <= S) + { + cairo_t* cr = context.GetObject(); + cairo_set_source_rgb(cr, 1, 0, 0); + cairo_rectangle(cr, -S, -S , 2.0 * S, 2.0 * S); + cairo_set_line_width(cr, 1.0 / view.GetZoom()); + cairo_stroke(cr); + } + } + + virtual void MouseWheel(WorldSceneWidget& widget, + OrthancStone::MouseWheelDirection direction, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + if (statusBar) + { + statusBar->SetMessage(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up"); + } + } + + virtual void KeyPressed(WorldSceneWidget& widget, + OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) + { + if (statusBar) + { + statusBar->SetMessage("Key pressed: \"" + std::string(1, keyChar) + "\""); + } + } + }; + + + bool TestWorldSceneWidget::RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view) + { + cairo_t* cr = context.GetObject(); + + // Clear background + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_paint(cr); + + float color = static_cast(count_ % 16) / 15.0f; + cairo_set_source_rgb(cr, 0, 1.0f - color, color); + cairo_rectangle(cr, -10, -.5, 20, 1); + cairo_fill(cr); + + return true; + } + + + TestWorldSceneWidget::TestWorldSceneWidget(const std::string& name, bool animate) : + WorldSceneWidget(name), + interactor_(new Interactor), + animate_(animate), + count_(0) + { + SetInteractor(*interactor_); + } + + + OrthancStone::Extent2D TestWorldSceneWidget::GetSceneExtent() + { + return OrthancStone::Extent2D(-10, -.5, 10, .5); + } + + + void TestWorldSceneWidget::DoAnimation() + { + if (animate_) + { + count_++; + NotifyContentChanged(); + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/TestWorldSceneWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/TestWorldSceneWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,63 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WorldSceneWidget.h" + +#include + +namespace Deprecated +{ + namespace Samples + { + class TestWorldSceneWidget : public WorldSceneWidget + { + private: + class Interactor; + + std::auto_ptr interactor_; + bool animate_; + unsigned int count_; + + protected: + virtual bool RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view); + + public: + TestWorldSceneWidget(const std::string& name, bool animate); + + virtual OrthancStone::Extent2D GetSceneExtent(); + + virtual bool HasAnimation() const + { + return animate_; + } + + virtual void DoAnimation(); + + virtual bool HasRenderMouseOver() + { + return true; + } + }; + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/WidgetBase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/WidgetBase.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,166 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "WidgetBase.h" + +#include +#include +#include + +namespace Deprecated +{ + void WidgetBase::NotifyContentChanged() + { + if (parent_ != NULL) + { + parent_->NotifyContentChanged(); + } + + if (viewport_ != NULL) + { + viewport_->NotifyBackgroundChanged(); + } + } + + + void WidgetBase::SetParent(IWidget& parent) + { + if (parent_ != NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + parent_ = &parent; + } + } + + + void WidgetBase::ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const + { + // Clear the background using Orthanc + + if (backgroundCleared_) + { + Orthanc::ImageProcessing::Set(target, + backgroundColor_[0], + backgroundColor_[1], + backgroundColor_[2], + 255 /* alpha */); + } + } + + + void WidgetBase::ClearBackgroundCairo(OrthancStone::CairoContext& context) const + { + // Clear the background using Cairo + + if (IsBackgroundCleared()) + { + uint8_t red, green, blue; + GetBackgroundColor(red, green, blue); + + context.SetSourceColor(red, green, blue); + cairo_paint(context.GetObject()); + } + } + + + void WidgetBase::ClearBackgroundCairo(Orthanc::ImageAccessor& target) const + { + OrthancStone::CairoSurface surface(target, false /* no alpha */); + OrthancStone::CairoContext context(surface); + ClearBackgroundCairo(context); + } + + + void WidgetBase::UpdateStatusBar(const std::string& message) + { + if (statusBar_ != NULL) + { + statusBar_->SetMessage(message); + } + } + + + WidgetBase::WidgetBase(const std::string& name) : + parent_(NULL), + viewport_(NULL), + statusBar_(NULL), + backgroundCleared_(false), + transmitMouseOver_(false), + name_(name) + { + backgroundColor_[0] = 0; + backgroundColor_[1] = 0; + backgroundColor_[2] = 0; + } + + + void WidgetBase::SetViewport(WidgetViewport& viewport) + { + if (viewport_ != NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + viewport_ = &viewport; + } + } + + + void WidgetBase::SetBackgroundColor(uint8_t red, + uint8_t green, + uint8_t blue) + { + backgroundColor_[0] = red; + backgroundColor_[1] = green; + backgroundColor_[2] = blue; + } + + void WidgetBase::GetBackgroundColor(uint8_t& red, + uint8_t& green, + uint8_t& blue) const + { + red = backgroundColor_[0]; + green = backgroundColor_[1]; + blue = backgroundColor_[2]; + } + + + bool WidgetBase::Render(Orthanc::ImageAccessor& surface) + { +#if 0 + ClearBackgroundOrthanc(surface); +#else + ClearBackgroundCairo(surface); // Faster than Orthanc +#endif + + return true; + } + + + void WidgetBase::DoAnimation() + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/WidgetBase.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/WidgetBase.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,117 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "IWidget.h" + +#include "../../Viewport/CairoContext.h" +#include "../Viewport/WidgetViewport.h" + +namespace Deprecated +{ + class WidgetBase : public IWidget + { + private: + IWidget* parent_; + WidgetViewport* viewport_; + IStatusBar* statusBar_; + bool backgroundCleared_; + uint8_t backgroundColor_[3]; + bool transmitMouseOver_; + std::string name_; + + protected: + void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const; + + void ClearBackgroundCairo(OrthancStone::CairoContext& context) const; + + void ClearBackgroundCairo(Orthanc::ImageAccessor& target) const; + + void UpdateStatusBar(const std::string& message); + + IStatusBar* GetStatusBar() const + { + return statusBar_; + } + + public: + WidgetBase(const std::string& name); + + virtual void FitContent() + { + } + + virtual void SetParent(IWidget& parent); + + virtual void SetViewport(WidgetViewport& viewport); + + void SetBackgroundCleared(bool clear) + { + backgroundCleared_ = clear; + } + + bool IsBackgroundCleared() const + { + return backgroundCleared_; + } + + void SetTransmitMouseOver(bool transmit) + { + transmitMouseOver_ = transmit; + } + + void SetBackgroundColor(uint8_t red, + uint8_t green, + uint8_t blue); + + void GetBackgroundColor(uint8_t& red, + uint8_t& green, + uint8_t& blue) const; + + virtual void SetStatusBar(IStatusBar& statusBar) + { + statusBar_ = &statusBar; + } + + virtual bool Render(Orthanc::ImageAccessor& surface); + + virtual bool HasAnimation() const + { + return false; + } + + virtual void DoAnimation(); + + virtual bool HasRenderMouseOver() + { + return transmitMouseOver_; + } + + virtual void NotifyContentChanged(); + + const std::string& GetName() const + { + return name_; + } + + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/WorldSceneWidget.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/WorldSceneWidget.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,231 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "WorldSceneWidget.h" + +#include "PanMouseTracker.h" +#include "ZoomMouseTracker.h" +#include "PanZoomMouseTracker.h" + +#include +#include + +#include +#include +#include + +namespace Deprecated +{ + // this is an adapter between a IWorldSceneMouseTracker + // that is tracking a mouse in scene coordinates/mm and + // an IMouseTracker that is tracking a mouse + // in screen coordinates/pixels. + class WorldSceneWidget::SceneMouseTracker : public IMouseTracker + { + private: + ViewportGeometry view_; + std::auto_ptr tracker_; + + public: + SceneMouseTracker(const ViewportGeometry& view, + IWorldSceneMouseTracker* tracker) : + view_(view), + tracker_(tracker) + { + if (tracker == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + } + + virtual void Render(Orthanc::ImageAccessor& target) + { + if (tracker_->HasRender()) + { + OrthancStone::CairoSurface surface(target, false /* no alpha */); + OrthancStone::CairoContext context(surface); + view_.ApplyTransform(context); + tracker_->Render(context, view_.GetZoom()); + } + } + + virtual void MouseUp() + { + tracker_->MouseUp(); + } + + virtual void MouseMove(int x, + int y, + const std::vector& displayTouches) + { + double sceneX, sceneY; + view_.MapPixelCenterToScene(sceneX, sceneY, x, y); + + std::vector sceneTouches; + for (size_t t = 0; t < displayTouches.size(); t++) + { + double sx, sy; + + view_.MapPixelCenterToScene( + sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y); + + sceneTouches.push_back( + Touch(static_cast(sx), static_cast(sy))); + } + tracker_->MouseMove(x, y, sceneX, sceneY, displayTouches, sceneTouches); + } + }; + + + bool WorldSceneWidget::RenderCairo(OrthancStone::CairoContext& context) + { + view_.ApplyTransform(context); + return RenderScene(context, view_); + } + + + void WorldSceneWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context, + int x, + int y) + { + ViewportGeometry view = GetView(); + view.ApplyTransform(context); + + double sceneX, sceneY; + view.MapPixelCenterToScene(sceneX, sceneY, x, y); + + if (interactor_) + { + interactor_->MouseOver(context, *this, view, sceneX, sceneY, GetStatusBar()); + } + } + + + void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) + { + view.SetSceneExtent(GetSceneExtent()); + } + + + void WorldSceneWidget::SetSize(unsigned int width, + unsigned int height) + { + CairoWidget::SetSize(width, height); + view_.SetDisplaySize(width, height); + } + + + void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) + { + interactor_ = &interactor; + } + + + void WorldSceneWidget::FitContent() + { + SetSceneExtent(view_); + view_.FitContent(); + + NotifyContentChanged(); + } + + + void WorldSceneWidget::SetView(const ViewportGeometry& view) + { + view_ = view; + + NotifyContentChanged(); + } + + + IMouseTracker* WorldSceneWidget::CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches) + { + double sceneX, sceneY; + view_.MapPixelCenterToScene(sceneX, sceneY, x, y); + + // asks the Widget Interactor to provide a mouse tracker + std::auto_ptr tracker; + + if (interactor_) + { + tracker.reset(interactor_->CreateMouseTracker(*this, view_, button, modifiers, x, y, sceneX, sceneY, GetStatusBar(), touches)); + } + + if (tracker.get() != NULL) + { + return new SceneMouseTracker(view_, tracker.release()); + } + else if (hasDefaultMouseEvents_) + { + printf("has default mouse events\n"); + if (touches.size() == 2) + { + printf("2 touches !\n"); + return new SceneMouseTracker(view_, new PanZoomMouseTracker(*this, touches)); + } + else + { + switch (button) + { + case OrthancStone::MouseButton_Middle: + return new SceneMouseTracker(view_, new PanMouseTracker(*this, x, y)); + + case OrthancStone::MouseButton_Right: + return new SceneMouseTracker(view_, new ZoomMouseTracker(*this, x, y)); + + default: + return NULL; + } + } + } + else + { + return NULL; + } + } + + + void WorldSceneWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers) + { + if (interactor_) + { + interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); + } + } + + + void WorldSceneWidget::KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers) + { + if (interactor_) + { + interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar()); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/WorldSceneWidget.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/WorldSceneWidget.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,103 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "CairoWidget.h" +#include "IWorldSceneInteractor.h" + +#include "../Toolbox/ViewportGeometry.h" + +namespace Deprecated +{ + class WorldSceneWidget : public CairoWidget + { + private: + class SceneMouseTracker; + + ViewportGeometry view_; + IWorldSceneInteractor* interactor_; + bool hasDefaultMouseEvents_; + + protected: + virtual OrthancStone::Extent2D GetSceneExtent() = 0; + + virtual bool RenderScene(OrthancStone::CairoContext& context, + const ViewportGeometry& view) = 0; + + // From CairoWidget + virtual bool RenderCairo(OrthancStone::CairoContext& context); + + // From CairoWidget + virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, + int x, + int y); + + void SetSceneExtent(ViewportGeometry& geometry); + + public: + WorldSceneWidget(const std::string& name) : + CairoWidget(name), + interactor_(NULL), + hasDefaultMouseEvents_(true) + { + } + + void SetDefaultMouseEvents(bool value) + { + hasDefaultMouseEvents_ = value; + } + + bool HasDefaultMouseEvents() const + { + return hasDefaultMouseEvents_; + } + + void SetInteractor(IWorldSceneInteractor& interactor); + + void SetView(const ViewportGeometry& view); + + const ViewportGeometry& GetView() const + { + return view_; + } + + virtual void SetSize(unsigned int width, + unsigned int height); + + virtual void FitContent(); + + virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers, + const std::vector& touches); + + virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, + int x, + int y, + OrthancStone::KeyboardModifiers modifiers); + + virtual void KeyPressed(OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/ZoomMouseTracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/ZoomMouseTracker.cpp Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,110 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#include "ZoomMouseTracker.h" + +#include +#include + +namespace Deprecated +{ + ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that, + int x, + int y) : + that_(that), + originalZoom_(that.GetView().GetZoom()), + downX_(x), + downY_(y) + { + that.GetView().MapPixelCenterToScene(centerX_, centerY_, x, y); + + unsigned int height = that.GetView().GetDisplayHeight(); + + if (height <= 3) + { + idle_ = true; + LOG(WARNING) << "image is too small to zoom (current height = " << height << ")"; + } + else + { + idle_ = false; + normalization_ = 1.0 / static_cast(height - 1); + } + } + + + void ZoomMouseTracker::Render(OrthancStone::CairoContext& context, + double zoom) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + + void ZoomMouseTracker::MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches) + { + static const double MIN_ZOOM = -4; + static const double MAX_ZOOM = 4; + + + if (!idle_) + { + double dy = static_cast(displayY - downY_) * normalization_; // In the range [-1,1] + double z; + + // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] + if (dy < -1.0) + { + z = MIN_ZOOM; + } + else if (dy > 1.0) + { + z = MAX_ZOOM; + } + else + { + z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; + } + + z = pow(2.0, z); + + ViewportGeometry view = that_.GetView(); + + view.SetZoom(z * originalZoom_); + + // Correct the pan so that the original click point is kept at + // the same location on the display + double panX, panY; + view.GetPan(panX, panY); + + int tx, ty; + view.MapSceneToDisplay(tx, ty, centerX_, centerY_); + view.SetPan(panX + static_cast(downX_ - tx), + panY + static_cast(downY_ - ty)); + + that_.SetView(view); + } + } +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/Widgets/ZoomMouseTracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/Widgets/ZoomMouseTracker.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,64 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "WorldSceneWidget.h" + +namespace Deprecated +{ + class ZoomMouseTracker : public IWorldSceneMouseTracker + { + private: + WorldSceneWidget& that_; + double originalZoom_; + int downX_; + int downY_; + double centerX_; + double centerY_; + bool idle_; + double normalization_; + + public: + ZoomMouseTracker(WorldSceneWidget& that, + int x, + int y); + + virtual bool HasRender() const + { + return false; + } + + virtual void MouseUp() + { + } + + virtual void Render(OrthancStone::CairoContext& context, + double zoom); + + virtual void MouseMove(int displayX, + int displayY, + double x, + double y, + const std::vector& displayTouches, + const std::vector& sceneTouches); + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Deprecated/dev.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Deprecated/dev.h Tue May 21 14:27:35 2019 +0200 @@ -0,0 +1,958 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 Osimis S.A., 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 . + **/ + + +#pragma once + +#include "Layers/FrameRenderer.h" +#include "Layers/LineLayerRenderer.h" +#include "Layers/SliceOutlineRenderer.h" +#include "Toolbox/DownloadStack.h" +#include "Toolbox/GeometryToolbox.h" +#include "Toolbox/OrthancSlicesLoader.h" +#include "Volumes/ImageBuffer3D.h" +#include "Volumes/ISlicedVolume.h" +#include "Widgets/SliceViewerWidget.h" + +#include +#include +#include + +#include + + +namespace Deprecated +{ + // TODO: Handle errors while loading + class OrthancVolumeImage : + public ISlicedVolume, + public OrthancStone::IObserver + { + private: + OrthancSlicesLoader loader_; + std::auto_ptr image_; + std::auto_ptr downloadStack_; + bool computeRange_; + size_t pendingSlices_; + + void ScheduleSliceDownload() + { + assert(downloadStack_.get() != NULL); + + unsigned int slice; + if (downloadStack_->Pop(slice)) + { + loader_.ScheduleLoadSliceImage(slice, OrthancStone::SliceImageQuality_Jpeg90); + } + } + + + static bool IsCompatible(const Slice& a, + const Slice& b) + { + if (!OrthancStone::GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), + b.GetGeometry().GetNormal())) + { + LOG(ERROR) << "A slice in the volume image is not parallel to the others."; + return false; + } + + if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat()) + { + LOG(ERROR) << "The pixel format changes across the slices of the volume image."; + return false; + } + + if (a.GetWidth() != b.GetWidth() || + a.GetHeight() != b.GetHeight()) + { + LOG(ERROR) << "The slices dimensions (width/height) are varying throughout the volume image"; + return false; + } + + if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || + !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) + { + LOG(ERROR) << "The pixel spacing of the slices change across the volume image"; + return false; + } + + return true; + } + + + static double GetDistance(const Slice& a, + const Slice& b) + { + return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - + a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin())); + } + + + void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) + { + assert(&message.GetOrigin() == &loader_); + + if (loader_.GetSlicesCount() == 0) + { + LOG(ERROR) << "Empty volume image"; + BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); + return; + } + + for (size_t i = 1; i < loader_.GetSlicesCount(); i++) + { + if (!IsCompatible(loader_.GetSlice(0), loader_.GetSlice(i))) + { + BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); + return; + } + } + + double spacingZ; + + if (loader_.GetSlicesCount() > 1) + { + spacingZ = GetDistance(loader_.GetSlice(0), loader_.GetSlice(1)); + } + else + { + // This is a volume with one single slice: Choose a dummy + // z-dimension for voxels + spacingZ = 1; + } + + for (size_t i = 1; i < loader_.GetSlicesCount(); i++) + { + if (!OrthancStone::LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)), + 0.001 /* this is expressed in mm */)) + { + LOG(ERROR) << "The distance between successive slices is not constant in a volume image"; + BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); + return; + } + } + + unsigned int width = loader_.GetSlice(0).GetWidth(); + unsigned int height = loader_.GetSlice(0).GetHeight(); + Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat(); + LOG(INFO) << "Creating a volume image of size " << width << "x" << height + << "x" << loader_.GetSlicesCount() << " in " << Orthanc::EnumerationToString(format); + + image_.reset(new OrthancStone::ImageBuffer3D(format, width, height, static_cast(loader_.GetSlicesCount()), computeRange_)); + image_->GetGeometry().SetAxialGeometry(loader_.GetSlice(0).GetGeometry()); + image_->GetGeometry().SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(), + loader_.GetSlice(0).GetPixelSpacingY(), spacingZ); + image_->Clear(); + + downloadStack_.reset(new DownloadStack(static_cast(loader_.GetSlicesCount()))); + pendingSlices_ = loader_.GetSlicesCount(); + + for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads + { + ScheduleSliceDownload(); + } + + // TODO Check the DicomFrameConverter are constant + + BroadcastMessage(ISlicedVolume::GeometryReadyMessage(*this)); + } + + + void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) + { + assert(&message.GetOrigin() == &loader_); + + LOG(ERROR) << "Unable to download a volume image"; + BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); + } + + + void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) + { + assert(&message.GetOrigin() == &loader_); + + { + OrthancStone::ImageBuffer3D::SliceWriter writer(*image_, OrthancStone::VolumeProjection_Axial, message.GetSliceIndex()); + Orthanc::ImageProcessing::Copy(writer.GetAccessor(), message.GetImage()); + } + + BroadcastMessage(ISlicedVolume::SliceContentChangedMessage + (*this, message.GetSliceIndex(), message.GetSlice())); + + if (pendingSlices_ == 1) + { + BroadcastMessage(ISlicedVolume::VolumeReadyMessage(*this)); + pendingSlices_ = 0; + } + else if (pendingSlices_ > 1) + { + pendingSlices_ -= 1; + } + + ScheduleSliceDownload(); + } + + + void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) + { + assert(&message.GetOrigin() == &loader_); + + LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image"; + ScheduleSliceDownload(); + } + + + public: + OrthancVolumeImage(OrthancStone::MessageBroker& broker, + OrthancApiClient& orthanc, + bool computeRange) : + ISlicedVolume(broker), + IObserver(broker), + loader_(broker, orthanc), + computeRange_(computeRange), + pendingSlices_(0) + { + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &OrthancVolumeImage::OnSliceGeometryReady)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &OrthancVolumeImage::OnSliceGeometryError)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &OrthancVolumeImage::OnSliceImageReady)); + + loader_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &OrthancVolumeImage::OnSliceImageError)); + } + + void ScheduleLoadSeries(const std::string& seriesId) + { + loader_.ScheduleLoadSeries(seriesId); + } + + void ScheduleLoadInstance(const std::string& instanceId) + { + loader_.ScheduleLoadInstance(instanceId); + } + + void ScheduleLoadFrame(const std::string& instanceId, + unsigned int frame) + { + loader_.ScheduleLoadFrame(instanceId, frame); + } + + virtual size_t GetSlicesCount() const + { + return loader_.GetSlicesCount(); + } + + virtual const Slice& GetSlice(size_t index) const + { + return loader_.GetSlice(index); + } + + OrthancStone::ImageBuffer3D& GetImage() const + { + if (image_.get() == NULL) + { + // The geometry is not ready yet + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return *image_; + } + } + + bool FitWindowingToRange(RenderStyle& style, + const DicomFrameConverter& converter) const + { + if (image_.get() == NULL) + { + return false; + } + else + { + return image_->FitWindowingToRange(style, converter); + } + } + }; + + + class VolumeImageGeometry + { + private: + unsigned int width_; + unsigned int height_; + size_t depth_; + double pixelSpacingX_; + double pixelSpacingY_; + double sliceThickness_; + OrthancStone::CoordinateSystem3D reference_; + DicomFrameConverter converter_; + + double ComputeAxialThickness(const OrthancVolumeImage& volume) const + { + double thickness; + + size_t n = volume.GetSlicesCount(); + if (n > 1) + { + const Slice& a = volume.GetSlice(0); + const Slice& b = volume.GetSlice(n - 1); + thickness = ((reference_.ProjectAlongNormal(b.GetGeometry().GetOrigin()) - + reference_.ProjectAlongNormal(a.GetGeometry().GetOrigin())) / + (static_cast(n) - 1.0)); + } + else + { + thickness = volume.GetSlice(0).GetThickness(); + } + + if (thickness <= 0) + { + // The slices should have been sorted with increasing Z + // (along the normal) by the OrthancSlicesLoader + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); + } + else + { + return thickness; + } + } + + void SetupAxial(const OrthancVolumeImage& volume) + { + const Slice& axial = volume.GetSlice(0); + + width_ = axial.GetWidth(); + height_ = axial.GetHeight(); + depth_ = volume.GetSlicesCount(); + + pixelSpacingX_ = axial.GetPixelSpacingX(); + pixelSpacingY_ = axial.GetPixelSpacingY(); + sliceThickness_ = ComputeAxialThickness(volume); + + reference_ = axial.GetGeometry(); + } + + void SetupCoronal(const OrthancVolumeImage& volume) + { + const Slice& axial = volume.GetSlice(0); + double axialThickness = ComputeAxialThickness(volume); + + width_ = axial.GetWidth(); + height_ = static_cast(volume.GetSlicesCount()); + depth_ = axial.GetHeight(); + + pixelSpacingX_ = axial.GetPixelSpacingX(); + pixelSpacingY_ = axialThickness; + sliceThickness_ = axial.GetPixelSpacingY(); + + OrthancStone::Vector origin = axial.GetGeometry().GetOrigin(); + origin += (static_cast(volume.GetSlicesCount() - 1) * + axialThickness * axial.GetGeometry().GetNormal()); + + reference_ = OrthancStone::CoordinateSystem3D(origin, + axial.GetGeometry().GetAxisX(), + - axial.GetGeometry().GetNormal()); + } + + void SetupSagittal(const OrthancVolumeImage& volume) + { + const Slice& axial = volume.GetSlice(0); + double axialThickness = ComputeAxialThickness(volume); + + width_ = axial.GetHeight(); + height_ = static_cast(volume.GetSlicesCount()); + depth_ = axial.GetWidth(); + + pixelSpacingX_ = axial.GetPixelSpacingY(); + pixelSpacingY_ = axialThickness; + sliceThickness_ = axial.GetPixelSpacingX(); + + OrthancStone::Vector origin = axial.GetGeometry().GetOrigin(); + origin += (static_cast(volume.GetSlicesCount() - 1) * + axialThickness * axial.GetGeometry().GetNormal()); + + reference_ = OrthancStone::CoordinateSystem3D(origin, + axial.GetGeometry().GetAxisY(), + axial.GetGeometry().GetNormal()); + } + + public: + VolumeImageGeometry(const OrthancVolumeImage& volume, + OrthancStone::VolumeProjection projection) + { + if (volume.GetSlicesCount() == 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + converter_ = volume.GetSlice(0).GetConverter(); + + switch (projection) + { + case OrthancStone::VolumeProjection_Axial: + SetupAxial(volume); + break; + + case OrthancStone::VolumeProjection_Coronal: + SetupCoronal(volume); + break; + + case OrthancStone::VolumeProjection_Sagittal: + SetupSagittal(volume); + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + } + + size_t GetSlicesCount() const + { + return depth_; + } + + const OrthancStone::Vector& GetNormal() const + { + return reference_.GetNormal(); + } + + bool LookupSlice(size_t& index, + const OrthancStone::CoordinateSystem3D& slice) const + { + bool opposite; + if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, + reference_.GetNormal(), + slice.GetNormal())) + { + return false; + } + + double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) - + reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_; + + int s = static_cast(boost::math::iround(z)); + + if (s < 0 || + s >= static_cast(depth_)) + { + return false; + } + else + { + index = static_cast(s); + return true; + } + } + + Slice* GetSlice(size_t slice) const + { + if (slice >= depth_) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else + { + OrthancStone::CoordinateSystem3D origin(reference_.GetOrigin() + + static_cast(slice) * sliceThickness_ * reference_.GetNormal(), + reference_.GetAxisX(), + reference_.GetAxisY()); + + return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_, + width_, height_, converter_); + } + } + }; + + + + class VolumeImageMPRSlicer : + public IVolumeSlicer, + public OrthancStone::IObserver + { + private: + class RendererFactory : public LayerReadyMessage::IRendererFactory + { + private: + const Orthanc::ImageAccessor& frame_; + const Slice& slice_; + bool isFullQuality_; + + public: + RendererFactory(const Orthanc::ImageAccessor& frame, + const Slice& slice, + bool isFullQuality) : + frame_(frame), + slice_(slice), + isFullQuality_(isFullQuality) + { + } + + virtual ILayerRenderer* CreateRenderer() const + { + return FrameRenderer::CreateRenderer(frame_, slice_, isFullQuality_); + } + }; + + + OrthancVolumeImage& volume_; + std::auto_ptr axialGeometry_; + std::auto_ptr coronalGeometry_; + std::auto_ptr sagittalGeometry_; + + + bool IsGeometryReady() const + { + return axialGeometry_.get() != NULL; + } + + void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) + { + assert(&message.GetOrigin() == &volume_); + + // These 3 values are only used to speed up the IVolumeSlicer + axialGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Axial)); + coronalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Coronal)); + sagittalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Sagittal)); + + BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); + } + + void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message) + { + assert(&message.GetOrigin() == &volume_); + + BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); + } + + void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message) + { + assert(&message.GetOrigin() == &volume_); + + BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); + } + + void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message) + { + assert(&message.GetOrigin() == &volume_); + + //IVolumeSlicer::OnSliceContentChange(slice); + + // TODO Improve this? + BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); + } + + const VolumeImageGeometry& GetProjectionGeometry(OrthancStone::VolumeProjection projection) + { + if (!IsGeometryReady()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + + switch (projection) + { + case OrthancStone::VolumeProjection_Axial: + return *axialGeometry_; + + case OrthancStone::VolumeProjection_Sagittal: + return *sagittalGeometry_; + + case OrthancStone::VolumeProjection_Coronal: + return *coronalGeometry_; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + bool DetectProjection(OrthancStone::VolumeProjection& projection, + const OrthancStone::CoordinateSystem3D& viewportSlice) + { + bool isOpposite; // Ignored + + if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, + viewportSlice.GetNormal(), + axialGeometry_->GetNormal())) + { + projection = OrthancStone::VolumeProjection_Axial; + return true; + } + else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, + viewportSlice.GetNormal(), + sagittalGeometry_->GetNormal())) + { + projection = OrthancStone::VolumeProjection_Sagittal; + return true; + } + else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, + viewportSlice.GetNormal(), + coronalGeometry_->GetNormal())) + { + projection = OrthancStone::VolumeProjection_Coronal; + return true; + } + else + { + return false; + } + } + + + public: + VolumeImageMPRSlicer(OrthancStone::MessageBroker& broker, + OrthancVolumeImage& volume) : + IVolumeSlicer(broker), + IObserver(broker), + volume_(volume) + { + volume_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &VolumeImageMPRSlicer::OnGeometryReady)); + + volume_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &VolumeImageMPRSlicer::OnGeometryError)); + + volume_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &VolumeImageMPRSlicer::OnContentChanged)); + + volume_.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &VolumeImageMPRSlicer::OnSliceContentChanged)); + } + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE + { + OrthancStone::VolumeProjection projection; + + if (!IsGeometryReady() || + !DetectProjection(projection, viewportSlice)) + { + return false; + } + else + { + // As the slices of the volumic image are arranged in a box, + // we only consider one single reference slice (the one with index 0). + std::auto_ptr slice(GetProjectionGeometry(projection).GetSlice(0)); + slice->GetExtent(points); + + return true; + } + } + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE + { + OrthancStone::VolumeProjection projection; + + if (IsGeometryReady() && + DetectProjection(projection, viewportSlice)) + { + const VolumeImageGeometry& geometry = GetProjectionGeometry(projection); + + size_t closest; + + if (geometry.LookupSlice(closest, viewportSlice)) + { + bool isFullQuality = true; // TODO + + std::auto_ptr frame; + + { + OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast(closest)); + + // TODO Transfer ownership if non-axial, to avoid memcpy + frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); + } + + std::auto_ptr slice(geometry.GetSlice(closest)); + + RendererFactory factory(*frame, *slice, isFullQuality); + + BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice->GetGeometry())); + return; + } + } + + // Error + OrthancStone::CoordinateSystem3D slice; + BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, slice)); + } + }; + + + class VolumeImageInteractor : + public IWorldSceneInteractor, + public OrthancStone::IObserver + { + private: + SliceViewerWidget& widget_; + OrthancStone::VolumeProjection projection_; + std::auto_ptr slices_; + size_t slice_; + + protected: + void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) + { + if (slices_.get() == NULL) + { + const OrthancVolumeImage& image = + dynamic_cast(message.GetOrigin()); + + slices_.reset(new VolumeImageGeometry(image, projection_)); + SetSlice(slices_->GetSlicesCount() / 2); + + widget_.FitContent(); + } + } + + virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, + const ViewportGeometry& view, + OrthancStone::MouseButton button, + OrthancStone::KeyboardModifiers modifiers, + int viewportX, + int viewportY, + double x, + double y, + IStatusBar* statusBar, + const std::vector& touches) ORTHANC_OVERRIDE + { + return NULL; + } + + virtual void MouseOver(OrthancStone::CairoContext& context, + WorldSceneWidget& widget, + const ViewportGeometry& view, + double x, + double y, + IStatusBar* statusBar) ORTHANC_OVERRIDE + { + } + + virtual void MouseWheel(WorldSceneWidget& widget, + OrthancStone::MouseWheelDirection direction, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) ORTHANC_OVERRIDE + { + int scale = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1); + + switch (direction) + { + case OrthancStone::MouseWheelDirection_Up: + OffsetSlice(-scale); + break; + + case OrthancStone::MouseWheelDirection_Down: + OffsetSlice(scale); + break; + + default: + break; + } + } + + virtual void KeyPressed(WorldSceneWidget& widget, + OrthancStone::KeyboardKeys key, + char keyChar, + OrthancStone::KeyboardModifiers modifiers, + IStatusBar* statusBar) ORTHANC_OVERRIDE + { + switch (keyChar) + { + case 's': + widget.FitContent(); + break; + + default: + break; + } + } + + public: + VolumeImageInteractor(OrthancStone::MessageBroker& broker, + OrthancVolumeImage& volume, + SliceViewerWidget& widget, + OrthancStone::VolumeProjection projection) : + IObserver(broker), + widget_(widget), + projection_(projection) + { + widget.SetInteractor(*this); + + volume.RegisterObserverCallback( + new OrthancStone::Callable + (*this, &VolumeImageInteractor::OnGeometryReady)); + } + + bool IsGeometryReady() const + { + return slices_.get() != NULL; + } + + size_t GetSlicesCount() const + { + if (slices_.get() == NULL) + { + return 0; + } + else + { + return slices_->GetSlicesCount(); + } + } + + void OffsetSlice(int offset) + { + if (slices_.get() != NULL) + { + int slice = static_cast(slice_) + offset; + + if (slice < 0) + { + slice = 0; + } + + if (slice >= static_cast(slices_->GetSlicesCount())) + { + slice = static_cast(slices_->GetSlicesCount()) - 1; + } + + if (slice != static_cast(slice_)) + { + SetSlice(slice); + } + } + } + + void SetSlice(size_t slice) + { + if (slices_.get() != NULL) + { + slice_ = slice; + + std::auto_ptr tmp(slices_->GetSlice(slice_)); + widget_.SetSlice(tmp->GetGeometry()); + } + } + }; + + + + class ReferenceLineSource : public IVolumeSlicer + { + private: + class RendererFactory : public LayerReadyMessage::IRendererFactory + { + private: + double x1_; + double y1_; + double x2_; + double y2_; + const OrthancStone::CoordinateSystem3D& slice_; + + public: + RendererFactory(double x1, + double y1, + double x2, + double y2, + const OrthancStone::CoordinateSystem3D& slice) : + x1_(x1), + y1_(y1), + x2_(x2), + y2_(y2), + slice_(slice) + { + } + + virtual ILayerRenderer* CreateRenderer() const + { + return new LineLayerRenderer(x1_, y1_, x2_, y2_, slice_); + } + }; + + SliceViewerWidget& otherPlane_; + + public: + ReferenceLineSource(OrthancStone::MessageBroker& broker, + SliceViewerWidget& otherPlane) : + IVolumeSlicer(broker), + otherPlane_(otherPlane) + { + BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); + } + + virtual bool GetExtent(std::vector& points, + const OrthancStone::CoordinateSystem3D& viewportSlice) + { + return false; + } + + virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) + { + Slice reference(viewportSlice, 0.001); + + OrthancStone::Vector p, d; + + const OrthancStone::CoordinateSystem3D& slice = otherPlane_.GetSlice(); + + // Compute the line of intersection between the two slices + if (!OrthancStone::GeometryToolbox::IntersectTwoPlanes(p, d, + slice.GetOrigin(), slice.GetNormal(), + viewportSlice.GetOrigin(), viewportSlice.GetNormal())) + { + // The two slice are parallel, don't try and display the intersection + BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); + } + else + { + double x1, y1, x2, y2; + viewportSlice.ProjectPoint(x1, y1, p); + viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); + + const OrthancStone::Extent2D extent = otherPlane_.GetSceneExtent(); + + if (OrthancStone::GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, + x1, y1, x2, y2, + extent.GetX1(), extent.GetY1(), + extent.GetX2(), extent.GetY2())) + { + RendererFactory factory(x1, y1, x2, y2, slice); + BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry())); + } + else + { + // Error: Parallel slices + BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); + } + } + } + }; +} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/CircleMeasureTracker.cpp --- a/Framework/Layers/CircleMeasureTracker.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "CircleMeasureTracker.h" - -#include -#include - -namespace Deprecated -{ - CircleMeasureTracker::CircleMeasureTracker(IStatusBar* statusBar, - const OrthancStone::CoordinateSystem3D& slice, - double x, - double y, - uint8_t red, - uint8_t green, - uint8_t blue, - const Orthanc::Font& font) : - statusBar_(statusBar), - slice_(slice), - x1_(x), - y1_(y), - x2_(x), - y2_(y), - font_(font) - { - color_[0] = red; - color_[1] = green; - color_[2] = blue; - } - - - void CircleMeasureTracker::Render(OrthancStone::CairoContext& context, - double zoom) - { - double x = (x1_ + x2_) / 2.0; - double y = (y1_ + y2_) / 2.0; - - OrthancStone::Vector tmp; - OrthancStone::LinearAlgebra::AssignVector(tmp, x2_ - x1_, y2_ - y1_); - double r = boost::numeric::ublas::norm_2(tmp) / 2.0; - - context.SetSourceColor(color_[0], color_[1], color_[2]); - - cairo_t* cr = context.GetObject(); - cairo_save(cr); - cairo_set_line_width(cr, 2.0 / zoom); - cairo_translate(cr, x, y); - cairo_arc(cr, 0, 0, r, 0, 2.0 * boost::math::constants::pi()); - cairo_stroke_preserve(cr); - cairo_stroke(cr); - cairo_restore(cr); - - context.DrawText(font_, FormatRadius(), x, y, OrthancStone::BitmapAnchor_Center); - } - - - double CircleMeasureTracker::GetRadius() const // In millimeters - { - OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_); - OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_); - return boost::numeric::ublas::norm_2(b - a) / 2.0; - } - - - std::string CircleMeasureTracker::FormatRadius() const - { - char buf[64]; - sprintf(buf, "%0.01f cm", GetRadius() / 10.0); - return buf; - } - - void CircleMeasureTracker::MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches) - { - x2_ = x; - y2_ = y; - - if (statusBar_ != NULL) - { - statusBar_->SetMessage("Circle radius: " + FormatRadius()); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/CircleMeasureTracker.h --- a/Framework/Layers/CircleMeasureTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Widgets/IWorldSceneMouseTracker.h" - -#include "../Viewport/IStatusBar.h" -#include "../Toolbox/CoordinateSystem3D.h" - -#include - -namespace Deprecated -{ - class CircleMeasureTracker : public IWorldSceneMouseTracker - { - private: - IStatusBar* statusBar_; - OrthancStone::CoordinateSystem3D slice_; - double x1_; - double y1_; - double x2_; - double y2_; - uint8_t color_[3]; - const Orthanc::Font& font_; - - public: - CircleMeasureTracker(IStatusBar* statusBar, - const OrthancStone::CoordinateSystem3D& slice, - double x, - double y, - uint8_t red, - uint8_t green, - uint8_t blue, - const Orthanc::Font& font); - - virtual bool HasRender() const - { - return true; - } - - virtual void Render(OrthancStone::CairoContext& context, - double zoom); - - double GetRadius() const; // In millimeters - - std::string FormatRadius() const; - - virtual void MouseUp() - { - // Possibly create a new landmark "volume" with the circle in subclasses - } - - virtual void MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/ColorFrameRenderer.cpp --- a/Framework/Layers/ColorFrameRenderer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "ColorFrameRenderer.h" - -#include -#include -#include - -namespace Deprecated -{ - OrthancStone::CairoSurface* ColorFrameRenderer::GenerateDisplay(const RenderStyle& style) - { - std::auto_ptr display - (new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */)); - - Orthanc::ImageAccessor target; - display->GetWriteableAccessor(target); - - Orthanc::ImageProcessing::Convert(target, *frame_); - - return display.release(); - } - - - ColorFrameRenderer::ColorFrameRenderer(const Orthanc::ImageAccessor& frame, - const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality) : - FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality), - frame_(Orthanc::Image::Clone(frame)) - { - if (frame_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - if (frame_->GetFormat() != Orthanc::PixelFormat_RGB24) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/ColorFrameRenderer.h --- a/Framework/Layers/ColorFrameRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "FrameRenderer.h" - -namespace Deprecated -{ - class ColorFrameRenderer : public FrameRenderer - { - private: - std::auto_ptr frame_; // In RGB24 - - protected: - virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style); - - public: - ColorFrameRenderer(const Orthanc::ImageAccessor& frame, - const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/DicomSeriesVolumeSlicer.cpp --- a/Framework/Layers/DicomSeriesVolumeSlicer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "DicomSeriesVolumeSlicer.h" - -#include "FrameRenderer.h" -#include "../Toolbox/DicomFrameConverter.h" - -#include -#include - -#include - -namespace Deprecated -{ - - void DicomSeriesVolumeSlicer::OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) - { - if (message.GetOrigin().GetSlicesCount() > 0) - { - BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); - } - else - { - BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); - } - } - - void DicomSeriesVolumeSlicer::OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) - { - BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); - } - - - class DicomSeriesVolumeSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory - { - private: - const OrthancSlicesLoader::SliceImageReadyMessage& message_; - - public: - RendererFactory(const OrthancSlicesLoader::SliceImageReadyMessage& message) : - message_(message) - { - } - - virtual ILayerRenderer* CreateRenderer() const - { - bool isFull = (message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPng || - message_.GetEffectiveQuality() == OrthancStone::SliceImageQuality_FullPam); - - return FrameRenderer::CreateRenderer(message_.GetImage(), message_.GetSlice(), isFull); - } - }; - - void DicomSeriesVolumeSlicer::OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) - { - // first notify that the pixel data of the frame is ready (targeted to, i.e: an image cache) - BroadcastMessage(FrameReadyMessage(*this, message.GetImage(), - message.GetEffectiveQuality(), message.GetSlice())); - - // then notify that the layer is ready for rendering - RendererFactory factory(message); - BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, message.GetSlice().GetGeometry())); - } - - void DicomSeriesVolumeSlicer::OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) - { - BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, message.GetSlice().GetGeometry())); - } - - - DicomSeriesVolumeSlicer::DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - IVolumeSlicer(broker), - IObserver(broker), - loader_(broker, orthanc), - quality_(OrthancStone::SliceImageQuality_FullPng) - { - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceGeometryError)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceImageReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomSeriesVolumeSlicer::OnSliceImageError)); - } - - - void DicomSeriesVolumeSlicer::LoadSeries(const std::string& seriesId) - { - loader_.ScheduleLoadSeries(seriesId); - } - - - void DicomSeriesVolumeSlicer::LoadInstance(const std::string& instanceId) - { - loader_.ScheduleLoadInstance(instanceId); - } - - - void DicomSeriesVolumeSlicer::LoadFrame(const std::string& instanceId, - unsigned int frame) - { - loader_.ScheduleLoadFrame(instanceId, frame); - } - - - bool DicomSeriesVolumeSlicer::GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice) - { - size_t index; - - if (loader_.IsGeometryReady() && - loader_.LookupSlice(index, viewportSlice)) - { - loader_.GetSlice(index).GetExtent(points); - return true; - } - else - { - return false; - } - } - - - void DicomSeriesVolumeSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) - { - size_t index; - - if (loader_.IsGeometryReady() && - loader_.LookupSlice(index, viewportSlice)) - { - loader_.ScheduleLoadSliceImage(index, quality_); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/DicomSeriesVolumeSlicer.h --- a/Framework/Layers/DicomSeriesVolumeSlicer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IVolumeSlicer.h" -#include "../Toolbox/IWebService.h" -#include "../Toolbox/OrthancSlicesLoader.h" -#include "../Toolbox/OrthancApiClient.h" - -namespace Deprecated -{ - // this class is in charge of loading a Frame. - // once it's been loaded (first the geometry and then the image), - // messages are sent to observers so they can use it - class DicomSeriesVolumeSlicer : - public IVolumeSlicer, - public OrthancStone::IObserver - //private OrthancSlicesLoader::ISliceLoaderObserver - { - public: - // TODO: Add "frame" and "instanceId" - class FrameReadyMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const Orthanc::ImageAccessor& frame_; - OrthancStone::SliceImageQuality imageQuality_; - const Slice& slice_; - - public: - FrameReadyMessage(DicomSeriesVolumeSlicer& origin, - const Orthanc::ImageAccessor& frame, - OrthancStone::SliceImageQuality imageQuality, - const Slice& slice) : - OriginMessage(origin), - frame_(frame), - imageQuality_(imageQuality), - slice_(slice) - { - } - - const Orthanc::ImageAccessor& GetFrame() const - { - return frame_; - } - - OrthancStone::SliceImageQuality GetImageQuality() const - { - return imageQuality_; - } - - const Slice& GetSlice() const - { - return slice_; - } - }; - - - private: - class RendererFactory; - - OrthancSlicesLoader loader_; - OrthancStone::SliceImageQuality quality_; - - public: - DicomSeriesVolumeSlicer(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc); - - void LoadSeries(const std::string& seriesId); - - void LoadInstance(const std::string& instanceId); - - void LoadFrame(const std::string& instanceId, - unsigned int frame); - - void SetImageQuality(OrthancStone::SliceImageQuality quality) - { - quality_ = quality; - } - - OrthancStone::SliceImageQuality GetImageQuality() const - { - return quality_; - } - - size_t GetSlicesCount() const - { - return loader_.GetSlicesCount(); - } - - const Slice& GetSlice(size_t slice) const - { - return loader_.GetSlice(slice); - } - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice); - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice); - -protected: - void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message); - void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message); - void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message); - void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/DicomStructureSetSlicer.cpp --- a/Framework/Layers/DicomStructureSetSlicer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "DicomStructureSetSlicer.h" - -namespace Deprecated -{ - class DicomStructureSetSlicer::Renderer : public ILayerRenderer - { - private: - class Structure - { - private: - bool visible_; - uint8_t red_; - uint8_t green_; - uint8_t blue_; - std::string name_; - std::vector< std::vector > polygons_; - - public: - Structure(OrthancStone::DicomStructureSet& structureSet, - const OrthancStone::CoordinateSystem3D& plane, - size_t index) : - name_(structureSet.GetStructureName(index)) - { - structureSet.GetStructureColor(red_, green_, blue_, index); - visible_ = structureSet.ProjectStructure(polygons_, index, plane); - } - - void Render(OrthancStone::CairoContext& context) - { - if (visible_) - { - cairo_t* cr = context.GetObject(); - - context.SetSourceColor(red_, green_, blue_); - - for (size_t i = 0; i < polygons_.size(); i++) - { - cairo_move_to(cr, polygons_[i][0].first, polygons_[i][0].second); - - for (size_t j = 1; j < polygons_[i].size(); j++) - { - cairo_line_to(cr, polygons_[i][j].first, polygons_[i][j].second); - } - - cairo_line_to(cr, polygons_[i][0].first, polygons_[i][0].second); - cairo_stroke(cr); - } - } - } - }; - - typedef std::list Structures; - - OrthancStone::CoordinateSystem3D plane_; - Structures structures_; - - public: - Renderer(OrthancStone::DicomStructureSet& structureSet, - const OrthancStone::CoordinateSystem3D& plane) : - plane_(plane) - { - for (size_t k = 0; k < structureSet.GetStructureCount(); k++) - { - structures_.push_back(new Structure(structureSet, plane, k)); - } - } - - virtual ~Renderer() - { - for (Structures::iterator it = structures_.begin(); - it != structures_.end(); ++it) - { - delete *it; - } - } - - virtual bool RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - cairo_set_line_width(context.GetObject(), 2.0f / view.GetZoom()); - - for (Structures::const_iterator it = structures_.begin(); - it != structures_.end(); ++it) - { - assert(*it != NULL); - (*it)->Render(context); - } - - return true; - } - - virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() - { - return plane_; - } - - virtual void SetLayerStyle(const RenderStyle& style) - { - } - - virtual bool IsFullQuality() - { - return true; - } - }; - - - class DicomStructureSetSlicer::RendererFactory : public LayerReadyMessage::IRendererFactory - { - private: - OrthancStone::DicomStructureSet& structureSet_; - const OrthancStone::CoordinateSystem3D& plane_; - - public: - RendererFactory(OrthancStone::DicomStructureSet& structureSet, - const OrthancStone::CoordinateSystem3D& plane) : - structureSet_(structureSet), - plane_(plane) - { - } - - virtual ILayerRenderer* CreateRenderer() const - { - return new Renderer(structureSet_, plane_); - } - }; - - - DicomStructureSetSlicer::DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, - StructureSetLoader& loader) : - IVolumeSlicer(broker), - IObserver(broker), - loader_(loader) - { - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &DicomStructureSetSlicer::OnStructureSetLoaded)); - } - - - void DicomStructureSetSlicer::ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane) - { - if (loader_.HasStructureSet()) - { - RendererFactory factory(loader_.GetStructureSet(), viewportPlane); - BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, viewportPlane)); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/DicomStructureSetSlicer.h --- a/Framework/Layers/DicomStructureSetSlicer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IVolumeSlicer.h" -#include "../Volumes/StructureSetLoader.h" - -namespace Deprecated -{ - class DicomStructureSetSlicer : - public IVolumeSlicer, - public OrthancStone::IObserver - { - private: - class Renderer; - class RendererFactory; - - StructureSetLoader& loader_; - - void OnStructureSetLoaded(const IVolumeLoader::ContentChangedMessage& message) - { - BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); - } - - public: - DicomStructureSetSlicer(OrthancStone::MessageBroker& broker, - StructureSetLoader& loader); - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportPlane) - { - return false; - } - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportPlane); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/FrameRenderer.cpp --- a/Framework/Layers/FrameRenderer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,140 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "FrameRenderer.h" - -#include "GrayscaleFrameRenderer.h" -#include "ColorFrameRenderer.h" - -#include - -namespace Deprecated -{ - FrameRenderer::FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality) : - framePlane_(framePlane), - pixelSpacingX_(pixelSpacingX), - pixelSpacingY_(pixelSpacingY), - isFullQuality_(isFullQuality) - { - } - - - bool FrameRenderer::RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - if (!style_.visible_) - { - return true; - } - - if (display_.get() == NULL) - { - display_.reset(GenerateDisplay(style_)); - } - - assert(display_.get() != NULL); - - cairo_t *cr = context.GetObject(); - - cairo_save(cr); - - cairo_matrix_t transform; - cairo_matrix_init_identity(&transform); - cairo_matrix_scale(&transform, pixelSpacingX_, pixelSpacingY_); - cairo_matrix_translate(&transform, -0.5, -0.5); - cairo_transform(cr, &transform); - - //cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_surface(cr, display_->GetObject(), 0, 0); - - switch (style_.interpolation_) - { - case OrthancStone::ImageInterpolation_Nearest: - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); - break; - - case OrthancStone::ImageInterpolation_Bilinear: - cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - cairo_paint_with_alpha(cr, style_.alpha_); - - if (style_.drawGrid_) - { - context.SetSourceColor(style_.drawColor_); - cairo_set_line_width(cr, 0.5 / view.GetZoom()); - - for (unsigned int x = 0; x <= display_->GetWidth(); x++) - { - cairo_move_to(cr, x, 0); - cairo_line_to(cr, x, display_->GetHeight()); - } - - for (unsigned int y = 0; y <= display_->GetHeight(); y++) - { - cairo_move_to(cr, 0, y); - cairo_line_to(cr, display_->GetWidth(), y); - } - - cairo_stroke(cr); - } - - cairo_restore(cr); - - return true; - } - - - void FrameRenderer::SetLayerStyle(const RenderStyle& style) - { - style_ = style; - display_.reset(NULL); - } - - - ILayerRenderer* FrameRenderer::CreateRenderer(const Orthanc::ImageAccessor& frame, - const Deprecated::Slice& framePlane, - bool isFullQuality) - { - if (frame.GetFormat() == Orthanc::PixelFormat_RGB24) - { - return new ColorFrameRenderer(frame, - framePlane.GetGeometry(), - framePlane.GetPixelSpacingX(), - framePlane.GetPixelSpacingY(), isFullQuality); - } - else - { - return new GrayscaleFrameRenderer(frame, - framePlane.GetConverter(), - framePlane.GetGeometry(), - framePlane.GetPixelSpacingX(), - framePlane.GetPixelSpacingY(), isFullQuality); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/FrameRenderer.h --- a/Framework/Layers/FrameRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRenderer.h" - -#include "../Toolbox/Slice.h" - -namespace Deprecated -{ - class FrameRenderer : public ILayerRenderer - { - private: - OrthancStone::CoordinateSystem3D framePlane_; - double pixelSpacingX_; - double pixelSpacingY_; - RenderStyle style_; - bool isFullQuality_; - std::auto_ptr display_; - - protected: - virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style) = 0; - - public: - FrameRenderer(const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality); - - virtual bool RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view); - - virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() - { - return framePlane_; - } - - virtual void SetLayerStyle(const RenderStyle& style); - - virtual bool IsFullQuality() - { - return isFullQuality_; - } - - // TODO: Avoid cloning the "frame" - static ILayerRenderer* CreateRenderer(const Orthanc::ImageAccessor& frame, - const Deprecated::Slice& framePlane, - bool isFullQuality); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/GrayscaleFrameRenderer.cpp --- a/Framework/Layers/GrayscaleFrameRenderer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,141 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "GrayscaleFrameRenderer.h" - -#include -#include - -namespace Deprecated -{ - OrthancStone::CairoSurface* GrayscaleFrameRenderer::GenerateDisplay(const RenderStyle& style) - { - assert(frame_->GetFormat() == Orthanc::PixelFormat_Float32); - - std::auto_ptr result; - - float windowCenter, windowWidth; - style.ComputeWindowing(windowCenter, windowWidth, - defaultWindowCenter_, defaultWindowWidth_); - - float x0 = windowCenter - windowWidth / 2.0f; - float x1 = windowCenter + windowWidth / 2.0f; - - //LOG(INFO) << "Window: " << x0 << " => " << x1; - - result.reset(new OrthancStone::CairoSurface(frame_->GetWidth(), frame_->GetHeight(), false /* no alpha */)); - - const uint8_t* lut = NULL; - if (style.applyLut_) - { - if (Orthanc::EmbeddedResources::GetFileResourceSize(style.lut_) != 3 * 256) - { - // Invalid colormap - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - lut = reinterpret_cast(Orthanc::EmbeddedResources::GetFileResourceBuffer(style.lut_)); - } - - Orthanc::ImageAccessor target; - result->GetWriteableAccessor(target); - - const unsigned int width = target.GetWidth(); - const unsigned int height = target.GetHeight(); - - for (unsigned int y = 0; y < height; y++) - { - const float* p = reinterpret_cast(frame_->GetConstRow(y)); - uint8_t* q = reinterpret_cast(target.GetRow(y)); - - for (unsigned int x = 0; x < width; x++, p++, q += 4) - { - uint8_t v = 0; - if (windowWidth >= 0.001f) // Avoid division by zero - { - if (*p >= x1) - { - v = 255; - } - else if (*p <= x0) - { - v = 0; - } - else - { - // https://en.wikipedia.org/wiki/Linear_interpolation - v = static_cast(255.0f * (*p - x0) / (x1 - x0)); - } - - if (style.reverse_ ^ (photometric_ == Orthanc::PhotometricInterpretation_Monochrome1)) - { - v = 255 - v; - } - } - - if (style.applyLut_) - { - assert(lut != NULL); - q[3] = 255; - q[2] = lut[3 * v]; - q[1] = lut[3 * v + 1]; - q[0] = lut[3 * v + 2]; - } - else - { - q[3] = 255; - q[2] = v; - q[1] = v; - q[0] = v; - } - } - } - - return result.release(); - } - - - GrayscaleFrameRenderer::GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame, - const Deprecated::DicomFrameConverter& converter, - const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality) : - FrameRenderer(framePlane, pixelSpacingX, pixelSpacingY, isFullQuality), - frame_(Orthanc::Image::Clone(frame)), - defaultWindowCenter_(static_cast(converter.GetDefaultWindowCenter())), - defaultWindowWidth_(static_cast(converter.GetDefaultWindowWidth())), - photometric_(converter.GetPhotometricInterpretation()) - { - if (frame_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - converter.ConvertFrameInplace(frame_); - assert(frame_.get() != NULL); - - if (frame_->GetFormat() != Orthanc::PixelFormat_Float32) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/GrayscaleFrameRenderer.h --- a/Framework/Layers/GrayscaleFrameRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "FrameRenderer.h" -#include "../Toolbox/DicomFrameConverter.h" - -namespace Deprecated -{ - class GrayscaleFrameRenderer : public FrameRenderer - { - private: - std::auto_ptr frame_; // In Float32 - float defaultWindowCenter_; - float defaultWindowWidth_; - Orthanc::PhotometricInterpretation photometric_; - - protected: - virtual OrthancStone::CairoSurface* GenerateDisplay(const RenderStyle& style); - - public: - GrayscaleFrameRenderer(const Orthanc::ImageAccessor& frame, - const Deprecated::DicomFrameConverter& converter, - const OrthancStone::CoordinateSystem3D& framePlane, - double pixelSpacingX, - double pixelSpacingY, - bool isFullQuality); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/ILayerRenderer.h --- a/Framework/Layers/ILayerRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Viewport/CairoContext.h" -#include "../Toolbox/CoordinateSystem3D.h" -#include "../Toolbox/ViewportGeometry.h" -#include "RenderStyle.h" - -namespace Deprecated -{ - class ILayerRenderer : public boost::noncopyable - { - public: - virtual ~ILayerRenderer() - { - } - - virtual bool RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view) = 0; - - virtual void SetLayerStyle(const RenderStyle& style) = 0; - - virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() = 0; - - virtual bool IsFullQuality() = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/IVolumeSlicer.h --- a/Framework/Layers/IVolumeSlicer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRenderer.h" -#include "../Toolbox/Slice.h" -#include "../../Framework/Messages/IObservable.h" -#include "../../Framework/Messages/IMessage.h" -#include "Core/Images/Image.h" -#include - -namespace Deprecated -{ - class IVolumeSlicer : public OrthancStone::IObservable - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeSlicer); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeSlicer); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeSlicer); - - class SliceContentChangedMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const Deprecated::Slice& slice_; - - public: - SliceContentChangedMessage(IVolumeSlicer& origin, - const Deprecated::Slice& slice) : - OriginMessage(origin), - slice_(slice) - { - } - - const Deprecated::Slice& GetSlice() const - { - return slice_; - } - }; - - - class LayerReadyMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - public: - class IRendererFactory : public boost::noncopyable - { - public: - virtual ~IRendererFactory() - { - } - - virtual ILayerRenderer* CreateRenderer() const = 0; - }; - - private: - const IRendererFactory& factory_; - const OrthancStone::CoordinateSystem3D& slice_; - - public: - LayerReadyMessage(IVolumeSlicer& origin, - const IRendererFactory& rendererFactory, - const OrthancStone::CoordinateSystem3D& slice) : - OriginMessage(origin), - factory_(rendererFactory), - slice_(slice) - { - } - - ILayerRenderer* CreateRenderer() const - { - return factory_.CreateRenderer(); - } - - const OrthancStone::CoordinateSystem3D& GetSlice() const - { - return slice_; - } - }; - - - class LayerErrorMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const OrthancStone::CoordinateSystem3D& slice_; - - public: - LayerErrorMessage(IVolumeSlicer& origin, - const OrthancStone::CoordinateSystem3D& slice) : - OriginMessage(origin), - slice_(slice) - { - } - - const OrthancStone::CoordinateSystem3D& GetSlice() const - { - return slice_; - } - }; - - - IVolumeSlicer(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - - virtual ~IVolumeSlicer() - { - } - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice) = 0; - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/LineLayerRenderer.cpp --- a/Framework/Layers/LineLayerRenderer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "LineLayerRenderer.h" - -namespace Deprecated -{ - LineLayerRenderer::LineLayerRenderer(double x1, - double y1, - double x2, - double y2, - const OrthancStone::CoordinateSystem3D& plane) : - x1_(x1), - y1_(y1), - x2_(x2), - y2_(y2), - plane_(plane) - { - RenderStyle style; - SetLayerStyle(style); - } - - - bool LineLayerRenderer::RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - if (visible_) - { - context.SetSourceColor(color_); - - cairo_t *cr = context.GetObject(); - cairo_set_line_width(cr, 1.0 / view.GetZoom()); - cairo_move_to(cr, x1_, y1_); - cairo_line_to(cr, x2_, y2_); - cairo_stroke(cr); - } - - return true; - } - - - void LineLayerRenderer::SetLayerStyle(const RenderStyle& style) - { - visible_ = style.visible_; - color_[0] = style.drawColor_[0]; - color_[1] = style.drawColor_[1]; - color_[2] = style.drawColor_[2]; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/LineLayerRenderer.h --- a/Framework/Layers/LineLayerRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRenderer.h" - -namespace Deprecated -{ - class LineLayerRenderer : public ILayerRenderer - { - private: - double x1_; - double y1_; - double x2_; - double y2_; - OrthancStone::CoordinateSystem3D plane_; - bool visible_; - uint8_t color_[3]; - - public: - LineLayerRenderer(double x1, - double y1, - double x2, - double y2, - const OrthancStone::CoordinateSystem3D& plane); - - virtual bool RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view); - - virtual void SetLayerStyle(const RenderStyle& style); - - virtual const OrthancStone::CoordinateSystem3D& GetLayerPlane() - { - return plane_; - } - - virtual bool IsFullQuality() - { - return true; - } - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/LineMeasureTracker.cpp --- a/Framework/Layers/LineMeasureTracker.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "LineMeasureTracker.h" - -#include - -namespace Deprecated -{ - LineMeasureTracker::LineMeasureTracker(IStatusBar* statusBar, - const OrthancStone::CoordinateSystem3D& slice, - double x, - double y, - uint8_t red, - uint8_t green, - uint8_t blue, - const Orthanc::Font& font) : - statusBar_(statusBar), - slice_(slice), - x1_(x), - y1_(y), - x2_(x), - y2_(y), - font_(font) - { - color_[0] = red; - color_[1] = green; - color_[2] = blue; - } - - - void LineMeasureTracker::Render(OrthancStone::CairoContext& context, - double zoom) - { - context.SetSourceColor(color_[0], color_[1], color_[2]); - - cairo_t* cr = context.GetObject(); - cairo_set_line_width(cr, 2.0 / zoom); - cairo_move_to(cr, x1_, y1_); - cairo_line_to(cr, x2_, y2_); - cairo_stroke(cr); - - if (y2_ - y1_ < 0) - { - context.DrawText(font_, FormatLength(), x2_, y2_ - 5, OrthancStone::BitmapAnchor_BottomCenter); - } - else - { - context.DrawText(font_, FormatLength(), x2_, y2_ + 5, OrthancStone::BitmapAnchor_TopCenter); - } - } - - - double LineMeasureTracker::GetLength() const // In millimeters - { - OrthancStone::Vector a = slice_.MapSliceToWorldCoordinates(x1_, y1_); - OrthancStone::Vector b = slice_.MapSliceToWorldCoordinates(x2_, y2_); - return boost::numeric::ublas::norm_2(b - a); - } - - - std::string LineMeasureTracker::FormatLength() const - { - char buf[64]; - sprintf(buf, "%0.01f cm", GetLength() / 10.0); - return buf; - } - - void LineMeasureTracker::MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches) - { - x2_ = x; - y2_ = y; - - if (statusBar_ != NULL) - { - statusBar_->SetMessage("Line length: " + FormatLength()); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/LineMeasureTracker.h --- a/Framework/Layers/LineMeasureTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Widgets/IWorldSceneMouseTracker.h" - -#include "../Viewport/IStatusBar.h" -#include "../Toolbox/CoordinateSystem3D.h" - -namespace Deprecated -{ - class LineMeasureTracker : public IWorldSceneMouseTracker - { - private: - IStatusBar* statusBar_; - OrthancStone::CoordinateSystem3D slice_; - double x1_; - double y1_; - double x2_; - double y2_; - uint8_t color_[3]; - unsigned int fontSize_; - const Orthanc::Font& font_; - - public: - LineMeasureTracker(IStatusBar* statusBar, - const OrthancStone::CoordinateSystem3D& slice, - double x, - double y, - uint8_t red, - uint8_t green, - uint8_t blue, - const Orthanc::Font& font); - - virtual bool HasRender() const - { - return true; - } - - virtual void Render(OrthancStone::CairoContext& context, - double zoom); - - double GetLength() const; // In millimeters - - std::string FormatLength() const; - - virtual void MouseUp() - { - // Possibly create a new landmark "volume" with the line in subclasses - } - - virtual void MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/RenderStyle.cpp --- a/Framework/Layers/RenderStyle.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "RenderStyle.h" - -#include - -namespace Deprecated -{ - RenderStyle::RenderStyle() - { - visible_ = true; - reverse_ = false; - windowing_ = OrthancStone::ImageWindowing_Custom; - alpha_ = 1; - applyLut_ = false; - lut_ = Orthanc::EmbeddedResources::COLORMAP_HOT; - drawGrid_ = false; - drawColor_[0] = 255; - drawColor_[1] = 255; - drawColor_[2] = 255; - customWindowCenter_ = 128; - customWindowWidth_ = 256; - interpolation_ = OrthancStone::ImageInterpolation_Nearest; - fontSize_ = 14; - } - - - void RenderStyle::ComputeWindowing(float& targetCenter, - float& targetWidth, - float defaultCenter, - float defaultWidth) const - { - if (windowing_ == OrthancStone::ImageWindowing_Custom) - { - targetCenter = customWindowCenter_; - targetWidth = customWindowWidth_; - } - else - { - return ::OrthancStone::ComputeWindowing - (targetCenter, targetWidth, windowing_, defaultCenter, defaultWidth); - } - } - - - void RenderStyle::SetColor(uint8_t red, - uint8_t green, - uint8_t blue) - { - drawColor_[0] = red; - drawColor_[1] = green; - drawColor_[2] = blue; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/RenderStyle.h --- a/Framework/Layers/RenderStyle.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../StoneEnumerations.h" - -#include - -#include - -namespace Deprecated -{ - struct RenderStyle - { - bool visible_; - bool reverse_; - OrthancStone::ImageWindowing windowing_; - float alpha_; // In [0,1] - bool applyLut_; - Orthanc::EmbeddedResources::FileResourceId lut_; - bool drawGrid_; - uint8_t drawColor_[3]; - float customWindowCenter_; - float customWindowWidth_; - OrthancStone::ImageInterpolation interpolation_; - unsigned int fontSize_; - - RenderStyle(); - - void ComputeWindowing(float& targetCenter, - float& targetWidth, - float defaultCenter, - float defaultWidth) const; - - void SetColor(uint8_t red, - uint8_t green, - uint8_t blue); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SeriesFrameRendererFactory.cpp --- a/Framework/Layers/SeriesFrameRendererFactory.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "SeriesFrameRendererFactory.h" - -#include "FrameRenderer.h" - -#include -#include -#include -#include -#include - - -namespace Deprecated -{ - void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame) - { - if (currentDataset_.get() != NULL && - (fast_ || currentFrame_ == frame)) - { - // The frame has not changed since the previous call, no need to - // update the DICOM dataset - return; - } - - currentDataset_.reset(loader_->DownloadDicom(frame)); - currentFrame_ = frame; - - if (currentDataset_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - void SeriesFrameRendererFactory::GetCurrentPixelSpacing(double& spacingX, - double& spacingY) const - { - if (currentDataset_.get() == NULL) - { - // There was no previous call "ReadCurrentFrameDataset()" - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_); - } - - - double SeriesFrameRendererFactory::GetCurrentSliceThickness() const - { - if (currentDataset_.get() == NULL) - { - // There was no previous call "ReadCurrentFrameDataset()" - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - try - { - OrthancPlugins::DicomDatasetReader reader(*currentDataset_); - - double thickness; - if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) - { - return thickness; - } - } - catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) - { - } - - // Some arbitrary large slice thickness - return std::numeric_limits::infinity(); - } - - - SeriesFrameRendererFactory::SeriesFrameRendererFactory(ISeriesLoader* loader, // Takes ownership - bool fast) : - loader_(loader), - currentFrame_(0), - fast_(fast) - { - if (loader == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - bool SeriesFrameRendererFactory::GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice) - { - if (currentDataset_.get() == NULL) - { - // There has been no previous call to - // "CreateLayerRenderer". Read some arbitrary DICOM frame, the - // one at the middle of the series. - unsigned int depth = loader_->GetGeometry().GetSliceCount(); - ReadCurrentFrameDataset(depth / 2); - } - - double spacingX, spacingY; - GetCurrentPixelSpacing(spacingX, spacingY); - - return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2, - viewportSlice, - loader_->GetGeometry().GetSlice(0), - loader_->GetWidth(), - loader_->GetHeight(), - spacingX, spacingY); - } - - - ILayerRenderer* SeriesFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) - { - size_t closest; - double distance; - - bool isOpposite; - if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, loader_->GetGeometry().GetNormal(), viewportSlice.GetNormal()) || - !loader_->GetGeometry().ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin())) - { - // Unable to compute the slice in the series that is the - // closest to the slice displayed by the viewport - return NULL; - } - - ReadCurrentFrameDataset(closest); - assert(currentDataset_.get() != NULL); - - double spacingX, spacingY; - GetCurrentPixelSpacing(spacingX, spacingY); - - if (distance <= GetCurrentSliceThickness() / 2.0) - { - SliceGeometry frameSlice(*currentDataset_); - return FrameRenderer::CreateRenderer(loader_->DownloadFrame(closest), - frameSlice, - *currentDataset_, - spacingX, spacingY, - true); - } - else - { - // The closest slice of the series is too far away from the - // slice displayed by the viewport - return NULL; - } - } - - - ISliceableVolume& SeriesFrameRendererFactory::GetSourceVolume() const - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SeriesFrameRendererFactory.h --- a/Framework/Layers/SeriesFrameRendererFactory.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRendererFactory.h" - -#include "../Toolbox/ISeriesLoader.h" - -namespace Deprecated -{ - class SeriesFrameRendererFactory : public ILayerRendererFactory - { - private: - std::auto_ptr loader_; - size_t currentFrame_; - bool fast_; - - std::auto_ptr currentDataset_; - - void ReadCurrentFrameDataset(size_t frame); - - void GetCurrentPixelSpacing(double& spacingX, - double& spacingY) const; - - double GetCurrentSliceThickness() const; - - public: - SeriesFrameRendererFactory(ISeriesLoader* loader, // Takes ownership - bool fast); - - virtual bool GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice); - - virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice); - - virtual bool HasSourceVolume() const - { - return false; - } - - virtual ISliceableVolume& GetSourceVolume() const; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SingleFrameRendererFactory.cpp --- a/Framework/Layers/SingleFrameRendererFactory.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "SingleFrameRendererFactory.h" - -#include "FrameRenderer.h" -#include "../Toolbox/MessagingToolbox.h" -#include "../Toolbox/DicomFrameConverter.h" - -#include -#include -#include - -namespace Deprecated -{ - SingleFrameRendererFactory::SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instanceId, - unsigned int frame) : - orthanc_(orthanc), - instance_(instanceId), - frame_(frame) - { - dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags")); - - DicomFrameConverter converter; - converter.ReadParameters(*dicom_); - format_ = converter.GetExpectedPixelFormat(); - } - - - bool SingleFrameRendererFactory::GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice) - { - // Assume that PixelSpacingX == PixelSpacingY == 1 - - OrthancPlugins::DicomDatasetReader reader(*dicom_); - - unsigned int width, height; - - if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) || - !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS)) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - x1 = 0; - y1 = 0; - x2 = static_cast(width); - y2 = static_cast(height); - - return true; - } - - - ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) - { - SliceGeometry frameSlice(*dicom_); - return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), - frameSlice, *dicom_, 1, 1, true); - } - - - ISliceableVolume& SingleFrameRendererFactory::GetSourceVolume() const - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SingleFrameRendererFactory.h --- a/Framework/Layers/SingleFrameRendererFactory.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRendererFactory.h" -#include - -namespace Deprecated -{ - class SingleFrameRendererFactory : public ILayerRendererFactory - { - private: - OrthancPlugins::IOrthancConnection& orthanc_; - std::auto_ptr dicom_; - - std::string instance_; - unsigned int frame_; - Orthanc::PixelFormat format_; - - public: - SingleFrameRendererFactory(OrthancPlugins::IOrthancConnection& orthanc, - const std::string& instanceId, - unsigned int frame); - - const OrthancPlugins::IDicomDataset& GetDataset() const - { - return *dicom_; - } - - SliceGeometry GetSliceGeometry() - { - return SliceGeometry(*dicom_); - } - - virtual bool GetExtent(double& x1, - double& y1, - double& x2, - double& y2, - const SliceGeometry& viewportSlice); - - virtual ILayerRenderer* CreateLayerRenderer(const SliceGeometry& viewportSlice); - - virtual bool HasSourceVolume() const - { - return false; - } - - virtual ISliceableVolume& GetSourceVolume() const; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SliceOutlineRenderer.cpp --- a/Framework/Layers/SliceOutlineRenderer.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "SliceOutlineRenderer.h" - -namespace Deprecated -{ - bool SliceOutlineRenderer::RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - if (style_.visible_) - { - cairo_t *cr = context.GetObject(); - cairo_save(cr); - - context.SetSourceColor(style_.drawColor_); - - double x1 = -0.5 * pixelSpacingX_; - double y1 = -0.5 * pixelSpacingY_; - - cairo_set_line_width(cr, 1.0 / view.GetZoom()); - cairo_rectangle(cr, x1, y1, - static_cast(width_) * pixelSpacingX_, - static_cast(height_) * pixelSpacingY_); - - double handleSize = 10.0f / view.GetZoom(); - cairo_move_to(cr, x1 + handleSize, y1); - cairo_line_to(cr, x1, y1 + handleSize); - - cairo_stroke(cr); - cairo_restore(cr); - } - - return true; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Layers/SliceOutlineRenderer.h --- a/Framework/Layers/SliceOutlineRenderer.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "ILayerRenderer.h" -#include "../Toolbox/Slice.h" - -namespace Deprecated -{ - class SliceOutlineRenderer : public ILayerRenderer - { - private: - OrthancStone::CoordinateSystem3D geometry_; - double pixelSpacingX_; - double pixelSpacingY_; - unsigned int width_; - unsigned int height_; - RenderStyle style_; - - public: - SliceOutlineRenderer(const Slice& slice) : - geometry_(slice.GetGeometry()), - pixelSpacingX_(slice.GetPixelSpacingX()), - pixelSpacingY_(slice.GetPixelSpacingY()), - width_(slice.GetWidth()), - height_(slice.GetHeight()) - { - } - - virtual bool RenderLayer(OrthancStone::CairoContext& context, - const ViewportGeometry& view); - - virtual void SetLayerStyle(const RenderStyle& style) - { - style_ = style; - } - - virtual const OrthancStone::CoordinateSystem3D& GetLayerSlice() - { - return geometry_; - } - - virtual bool IsFullQuality() - { - return true; - } - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyDicomLayer.cpp --- a/Framework/Radiography/RadiographyDicomLayer.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyDicomLayer.cpp Tue May 21 14:27:35 2019 +0200 @@ -22,7 +22,7 @@ #include "RadiographyDicomLayer.h" #include "RadiographyScene.h" -#include "../Toolbox/DicomFrameConverter.h" +#include "../Deprecated/Toolbox/DicomFrameConverter.h" #include #include diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyDicomLayer.h --- a/Framework/Radiography/RadiographyDicomLayer.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyDicomLayer.h Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #pragma once -#include "../Toolbox/DicomFrameConverter.h" +#include "../Deprecated/Toolbox/DicomFrameConverter.h" #include "RadiographyLayer.h" #include diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyLayerCropTracker.h --- a/Framework/Radiography/RadiographyLayerCropTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyLayerCropTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,8 +22,8 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Toolbox/ViewportGeometry.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Toolbox/ViewportGeometry.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" namespace OrthancStone diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyLayerMaskTracker.h --- a/Framework/Radiography/RadiographyLayerMaskTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyLayerMaskTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,8 +22,8 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Toolbox/ViewportGeometry.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Toolbox/ViewportGeometry.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" namespace OrthancStone diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyLayerMoveTracker.h --- a/Framework/Radiography/RadiographyLayerMoveTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyLayerMoveTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,7 +22,7 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" namespace OrthancStone diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyLayerResizeTracker.h --- a/Framework/Radiography/RadiographyLayerResizeTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyLayerResizeTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,7 +22,7 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" namespace OrthancStone diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyLayerRotateTracker.h --- a/Framework/Radiography/RadiographyLayerRotateTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyLayerRotateTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,8 +22,8 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Toolbox/ViewportGeometry.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Toolbox/ViewportGeometry.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyScene.cpp --- a/Framework/Radiography/RadiographyScene.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyScene.cpp Tue May 21 14:27:35 2019 +0200 @@ -25,7 +25,7 @@ #include "RadiographyDicomLayer.h" #include "RadiographyTextLayer.h" #include "RadiographyMaskLayer.h" -#include "../Toolbox/DicomFrameConverter.h" +#include "../Deprecated/Toolbox/DicomFrameConverter.h" #include #include diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyScene.h --- a/Framework/Radiography/RadiographyScene.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyScene.h Tue May 21 14:27:35 2019 +0200 @@ -22,9 +22,9 @@ #pragma once #include "RadiographyLayer.h" -#include "../Toolbox/DicomFrameConverter.h" -#include "../Toolbox/OrthancApiClient.h" -#include "Framework/StoneEnumerations.h" +#include "../Deprecated/Toolbox/DicomFrameConverter.h" +#include "../Deprecated/Toolbox/OrthancApiClient.h" +#include "../StoneEnumerations.h" #include "Core/Images/Image.h" #include "Core/Images/ImageProcessing.h" diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographySceneReader.cpp --- a/Framework/Radiography/RadiographySceneReader.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographySceneReader.cpp Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #include "RadiographySceneReader.h" -#include +#include "../Deprecated/Toolbox/DicomFrameConverter.h" #include #include diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographySceneReader.h --- a/Framework/Radiography/RadiographySceneReader.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographySceneReader.h Tue May 21 14:27:35 2019 +0200 @@ -26,7 +26,7 @@ #include "RadiographyDicomLayer.h" #include "RadiographyMaskLayer.h" #include "RadiographyTextLayer.h" -#include "../Toolbox/OrthancApiClient.h" +#include "../Deprecated/Toolbox/OrthancApiClient.h" #include #include diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyWidget.h --- a/Framework/Radiography/RadiographyWidget.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyWidget.h Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #pragma once -#include "../Widgets/WorldSceneWidget.h" +#include "../Deprecated/Widgets/WorldSceneWidget.h" #include "RadiographyScene.h" diff -r 529189f399ec -r c35e98d22764 Framework/Radiography/RadiographyWindowingTracker.h --- a/Framework/Radiography/RadiographyWindowingTracker.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Radiography/RadiographyWindowingTracker.h Tue May 21 14:27:35 2019 +0200 @@ -22,7 +22,7 @@ #pragma once #include "../Toolbox/UndoRedoStack.h" -#include "../Widgets/IWorldSceneMouseTracker.h" +#include "../Deprecated/Widgets/IWorldSceneMouseTracker.h" #include "RadiographyScene.h" namespace OrthancStone diff -r 529189f399ec -r c35e98d22764 Framework/SmartLoader.cpp --- a/Framework/SmartLoader.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,291 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "SmartLoader.h" -#include "Layers/DicomSeriesVolumeSlicer.h" -#include "Messages/MessageForwarder.h" -#include "Core/Images/Image.h" -#include "Framework/Widgets/SliceViewerWidget.h" -#include "Framework/StoneException.h" -#include "Framework/Layers/FrameRenderer.h" -#include "Core/Logging.h" - -namespace Deprecated -{ - enum CachedSliceStatus - { - CachedSliceStatus_ScheduledToLoad, - CachedSliceStatus_GeometryLoaded, - CachedSliceStatus_ImageLoaded - }; - - class SmartLoader::CachedSlice : public IVolumeSlicer - { - public: - class RendererFactory : public LayerReadyMessage::IRendererFactory - { - private: - const CachedSlice& that_; - - public: - RendererFactory(const CachedSlice& that) : - that_(that) - { - } - - virtual ILayerRenderer* CreateRenderer() const - { - bool isFull = (that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPng || - that_.effectiveQuality_ == OrthancStone::SliceImageQuality_FullPam); - - return FrameRenderer::CreateRenderer(*that_.image_, *that_.slice_, isFull); - } - }; - - unsigned int sliceIndex_; - std::auto_ptr slice_; - boost::shared_ptr image_; - OrthancStone::SliceImageQuality effectiveQuality_; - CachedSliceStatus status_; - - public: - CachedSlice(OrthancStone::MessageBroker& broker) : - IVolumeSlicer(broker) - { - } - - virtual ~CachedSlice() - { - } - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice) - { - // TODO: viewportSlice is not used !!!! - slice_->GetExtent(points); - return true; - } - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) - { - // TODO: viewportSlice is not used !!!! - - // it has already been loaded -> trigger the "layer ready" message immediately otherwise, do nothing now. The LayerReady will be triggered - // once the VolumeSlicer is ready - if (status_ == CachedSliceStatus_ImageLoaded) - { - LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is loaded): " << slice_->GetOrthancInstanceId(); - - RendererFactory factory(*this); - BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice_->GetGeometry())); - } - else - { - LOG(WARNING) << "ScheduleLayerCreation for CachedSlice (image is not loaded yet): " << slice_->GetOrthancInstanceId(); - } - } - - CachedSlice* Clone() const - { - CachedSlice* output = new CachedSlice(GetBroker()); - output->sliceIndex_ = sliceIndex_; - output->slice_.reset(slice_->Clone()); - output->image_ = image_; - output->effectiveQuality_ = effectiveQuality_; - output->status_ = status_; - - return output; - } - - }; - - - SmartLoader::SmartLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthancApiClient) : - IObservable(broker), - IObserver(broker), - imageQuality_(OrthancStone::SliceImageQuality_FullPam), - orthancApiClient_(orthancApiClient) - { - } - - void SmartLoader::SetFrameInWidget(SliceViewerWidget& sliceViewer, - size_t layerIndex, - const std::string& instanceId, - unsigned int frame) - { - // TODO: check if this frame has already been loaded or is already being loaded. - // - if already loaded: create a "clone" that will emit the GeometryReady/ImageReady messages "immediately" - // (it can not be immediate because Observers needs to register first and this is done after this method returns) - // - if currently loading, we need to return an object that will observe the existing VolumeSlicer and forward - // the messages to its observables - // in both cases, we must be carefull about objects lifecycle !!! - - std::auto_ptr layerSource; - std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); - SmartLoader::CachedSlice* cachedSlice = NULL; - - if (cachedSlices_.find(sliceKeyId) != cachedSlices_.end()) // && cachedSlices_[sliceKeyId]->status_ == CachedSliceStatus_Loaded) - { - layerSource.reset(cachedSlices_[sliceKeyId]->Clone()); - cachedSlice = dynamic_cast(layerSource.get()); - } - else - { - layerSource.reset(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); - dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); - dynamic_cast(layerSource.get())->LoadFrame(instanceId, frame); - } - - // make sure that the widget registers the events before we trigger them - if (sliceViewer.GetLayerCount() == layerIndex) - { - sliceViewer.AddLayer(layerSource.release()); - } - else if (sliceViewer.GetLayerCount() > layerIndex) - { - sliceViewer.ReplaceLayer(layerIndex, layerSource.release()); - } - else - { - throw OrthancStone::StoneException(OrthancStone::ErrorCode_CanOnlyAddOneLayerAtATime); - } - - if (cachedSlice != NULL) - { - BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*cachedSlice)); - } - - } - - void SmartLoader::PreloadSlice(const std::string instanceId, - unsigned int frame) - { - // TODO: reactivate -> need to be able to ScheduleLayerLoading in IVolumeSlicer without calling ScheduleLayerCreation - return; - // TODO: check if it is already in the cache - - - - // create the slice in the cache with "empty" data - boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); - cachedSlice->slice_.reset(new Slice(instanceId, frame)); - cachedSlice->status_ = CachedSliceStatus_ScheduledToLoad; - std::string sliceKeyId = instanceId + ":" + boost::lexical_cast(frame); - - LOG(WARNING) << "Will preload: " << sliceKeyId; - - cachedSlices_[sliceKeyId] = boost::shared_ptr(cachedSlice); - - std::auto_ptr layerSource(new DicomSeriesVolumeSlicer(IObserver::GetBroker(), orthancApiClient_)); - - dynamic_cast(layerSource.get())->SetImageQuality(imageQuality_); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerGeometryReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnFrameReady)); - layerSource->RegisterObserverCallback(new OrthancStone::Callable(*this, &SmartLoader::OnLayerReady)); - dynamic_cast(layerSource.get())->LoadFrame(instanceId, frame); - - // keep a ref to the VolumeSlicer until the slice is fully loaded and saved to cache - preloadingInstances_[sliceKeyId] = boost::shared_ptr(layerSource.release()); - } - - -// void PreloadStudy(const std::string studyId) -// { -// /* TODO */ -// } - -// void PreloadSeries(const std::string seriesId) -// { -// /* TODO */ -// } - - - void SmartLoader::OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message) - { - const DicomSeriesVolumeSlicer& source = - dynamic_cast(message.GetOrigin()); - - // save/replace the slice in cache - const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() - std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + - boost::lexical_cast(slice.GetFrame())); - - LOG(WARNING) << "Geometry ready: " << sliceKeyId; - - boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); - cachedSlice->slice_.reset(slice.Clone()); - cachedSlice->effectiveQuality_ = source.GetImageQuality(); - cachedSlice->status_ = CachedSliceStatus_GeometryLoaded; - - cachedSlices_[sliceKeyId] = boost::shared_ptr(cachedSlice); - - // re-emit original Layer message to observers - BroadcastMessage(message); - } - - - void SmartLoader::OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message) - { - // save/replace the slice in cache - const Slice& slice = message.GetSlice(); - std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + - boost::lexical_cast(slice.GetFrame())); - - LOG(WARNING) << "Image ready: " << sliceKeyId; - - boost::shared_ptr cachedSlice(new CachedSlice(IObserver::GetBroker())); - cachedSlice->image_.reset(Orthanc::Image::Clone(message.GetFrame())); - cachedSlice->effectiveQuality_ = message.GetImageQuality(); - cachedSlice->slice_.reset(message.GetSlice().Clone()); - cachedSlice->status_ = CachedSliceStatus_ImageLoaded; - - cachedSlices_[sliceKeyId] = cachedSlice; - - // re-emit original Layer message to observers - BroadcastMessage(message); - } - - - void SmartLoader::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message) - { - const DicomSeriesVolumeSlicer& source = - dynamic_cast(message.GetOrigin()); - - const Slice& slice = source.GetSlice(0); // TODO handle GetSliceCount() ? - std::string sliceKeyId = (slice.GetOrthancInstanceId() + ":" + - boost::lexical_cast(slice.GetFrame())); - - LOG(WARNING) << "Layer ready: " << sliceKeyId; - - // remove the slice from the preloading slices now that it has been fully loaded and it is referenced in the cache - if (preloadingInstances_.find(sliceKeyId) != preloadingInstances_.end()) - { - preloadingInstances_.erase(sliceKeyId); - } - - // re-emit original Layer message to observers - BroadcastMessage(message); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/SmartLoader.h --- a/Framework/SmartLoader.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once -#include - -#include "Layers/DicomSeriesVolumeSlicer.h" -#include "Messages/IObservable.h" -#include "Toolbox/OrthancApiClient.h" - -namespace Deprecated -{ - class SliceViewerWidget; - - class SmartLoader : public OrthancStone::IObservable, public OrthancStone::IObserver - { - class CachedSlice; - - protected: - typedef std::map > CachedSlices; - CachedSlices cachedSlices_; - - typedef std::map > PreloadingInstances; - PreloadingInstances preloadingInstances_; - - OrthancStone::SliceImageQuality imageQuality_; - OrthancApiClient& orthancApiClient_; - - public: - SmartLoader(OrthancStone::MessageBroker& broker, OrthancApiClient& orthancApiClient); // TODO: add maxPreloadStorageSizeInBytes - -// void PreloadStudy(const std::string studyId); -// void PreloadSeries(const std::string seriesId); - void PreloadSlice(const std::string instanceId, unsigned int frame); - - void SetImageQuality(OrthancStone::SliceImageQuality imageQuality) { imageQuality_ = imageQuality; } - - void SetFrameInWidget(SliceViewerWidget& sliceViewer, size_t layerIndex, const std::string& instanceId, unsigned int frame); - - void GetFirstInstanceIdForSeries(std::string& output, const std::string& seriesId); - - private: - void OnLayerGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message); - void OnFrameReady(const DicomSeriesVolumeSlicer::FrameReadyMessage& message); - void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message); - - }; - -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/BaseWebService.cpp --- a/Framework/Toolbox/BaseWebService.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 . - **/ - - -#include "BaseWebService.h" - -#include -#include "Framework/Messages/IObservable.h" -#include "Platforms/Generic/IOracleCommand.h" -#include - -namespace Deprecated -{ - - - class BaseWebService::BaseWebServicePayload : public Orthanc::IDynamicObject - { - private: - std::auto_ptr< OrthancStone::MessageHandler > userSuccessHandler_; - std::auto_ptr< OrthancStone::MessageHandler > userFailureHandler_; - std::auto_ptr< Orthanc::IDynamicObject> userPayload_; - - public: - BaseWebServicePayload(OrthancStone::MessageHandler* userSuccessHandler, - OrthancStone::MessageHandler* userFailureHandler, - Orthanc::IDynamicObject* userPayload) : - userSuccessHandler_(userSuccessHandler), - userFailureHandler_(userFailureHandler), - userPayload_(userPayload) - { - } - - void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const - { - if (userSuccessHandler_.get() != NULL) - { - // recreate a success message with the user payload - IWebService::HttpRequestSuccessMessage successMessage(message.GetUri(), - message.GetAnswer(), - message.GetAnswerSize(), - message.GetAnswerHttpHeaders(), - userPayload_.get()); - userSuccessHandler_->Apply(successMessage); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const - { - if (userFailureHandler_.get() != NULL) - { - // recreate a failure message with the user payload - IWebService::HttpRequestErrorMessage failureMessage(message.GetUri(), - userPayload_.get()); - - userFailureHandler_->Apply(failureMessage); - } - } - - }; - - - void BaseWebService::GetAsync(const std::string& uri, - const HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - unsigned int timeoutInSeconds) - { - if (cache_.find(uri) == cache_.end()) - { - GetAsyncInternal(uri, headers, - new BaseWebService::BaseWebServicePayload(successCallback, failureCallback, payload), // ownership is transfered - new OrthancStone::Callable - (*this, &BaseWebService::CacheAndNotifyHttpSuccess), - new OrthancStone::Callable - (*this, &BaseWebService::NotifyHttpError), - timeoutInSeconds); - } - else - { - // create a command and "post" it to the Oracle so it is executed and commited "later" - NotifyHttpSuccessLater(cache_[uri], payload, successCallback); - } - - } - - - - void BaseWebService::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) - { - if (message.HasPayload()) - { - dynamic_cast(message.GetPayload()).HandleSuccess(message); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - void BaseWebService::CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) - { - cache_[message.GetUri()] = boost::shared_ptr(new CachedHttpRequestSuccessMessage(message)); - NotifyHttpSuccess(message); - } - - void BaseWebService::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message) - { - if (message.HasPayload()) - { - dynamic_cast(message.GetPayload()).HandleFailure(message); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - - -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/BaseWebService.h --- a/Framework/Toolbox/BaseWebService.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IWebService.h" - -#include -#include - -namespace Deprecated -{ - // This is an intermediate of IWebService that implements some caching on - // the HTTP GET requests - class BaseWebService : public IWebService, public OrthancStone::IObserver - { - public: - class CachedHttpRequestSuccessMessage - { - protected: - std::string uri_; - void* answer_; - size_t answerSize_; - IWebService::HttpHeaders answerHeaders_; - - public: - CachedHttpRequestSuccessMessage(const IWebService::HttpRequestSuccessMessage& message) : - uri_(message.GetUri()), - answerSize_(message.GetAnswerSize()), - answerHeaders_(message.GetAnswerHttpHeaders()) - { - answer_ = malloc(answerSize_); - memcpy(answer_, message.GetAnswer(), answerSize_); - } - - ~CachedHttpRequestSuccessMessage() - { - free(answer_); - } - - const std::string& GetUri() const - { - return uri_; - } - - const void* GetAnswer() const - { - return answer_; - } - - size_t GetAnswerSize() const - { - return answerSize_; - } - - const IWebService::HttpHeaders& GetAnswerHttpHeaders() const - { - return answerHeaders_; - } - - }; - protected: - class BaseWebServicePayload; - - bool cacheEnabled_; - std::map > cache_; // TODO: this is currently an infinite cache ! - - public: - - BaseWebService(OrthancStone::MessageBroker& broker) : - IWebService(broker), - IObserver(broker), - cacheEnabled_(true) - { - } - - virtual ~BaseWebService() - { - } - - virtual void EnableCache(bool enable) - { - cacheEnabled_ = enable; - } - - virtual void GetAsync(const std::string& uri, - const HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - unsigned int timeoutInSeconds = 60); - - protected: - virtual void GetAsyncInternal(const std::string& uri, - const HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - unsigned int timeoutInSeconds = 60) = 0; - - virtual void NotifyHttpSuccessLater(boost::shared_ptr cachedHttpMessage, - Orthanc::IDynamicObject* payload, // takes ownership - OrthancStone::MessageHandler* successCallback) = 0; - - private: - void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); - - void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message); - - void CacheAndNotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); - - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/DicomFrameConverter.cpp --- a/Framework/Toolbox/DicomFrameConverter.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,282 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "DicomFrameConverter.h" - -#include "LinearAlgebra.h" - -#include -#include -#include -#include - -namespace Deprecated -{ - static const Orthanc::DicomTag IMAGE_TAGS[] = - { - Orthanc::DICOM_TAG_BITS_STORED, - Orthanc::DICOM_TAG_DOSE_GRID_SCALING, - Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, - Orthanc::DICOM_TAG_PIXEL_REPRESENTATION, - Orthanc::DICOM_TAG_RESCALE_INTERCEPT, - Orthanc::DICOM_TAG_RESCALE_SLOPE, - Orthanc::DICOM_TAG_WINDOW_CENTER, - Orthanc::DICOM_TAG_WINDOW_WIDTH - }; - - - void DicomFrameConverter::SetDefaultParameters() - { - isSigned_ = true; - isColor_ = false; - hasRescale_ = false; - rescaleIntercept_ = 0; - rescaleSlope_ = 1; - hasDefaultWindow_ = false; - defaultWindowCenter_ = 128; - defaultWindowWidth_ = 256; - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; - } - - - void DicomFrameConverter::ReadParameters(const Orthanc::DicomMap& dicom) - { - SetDefaultParameters(); - - OrthancStone::Vector c, w; - if (OrthancStone::LinearAlgebra::ParseVector(c, dicom, Orthanc::DICOM_TAG_WINDOW_CENTER) && - OrthancStone::LinearAlgebra::ParseVector(w, dicom, Orthanc::DICOM_TAG_WINDOW_WIDTH) && - c.size() > 0 && - w.size() > 0) - { - hasDefaultWindow_ = true; - defaultWindowCenter_ = static_cast(c[0]); - defaultWindowWidth_ = static_cast(w[0]); - } - - int32_t tmp; - if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_PIXEL_REPRESENTATION)) - { - // Type 1 tag, must be present - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - isSigned_ = (tmp == 1); - - double doseGridScaling; - bool isRTDose = false; - - if (dicom.ParseDouble(rescaleIntercept_, Orthanc::DICOM_TAG_RESCALE_INTERCEPT) && - dicom.ParseDouble(rescaleSlope_, Orthanc::DICOM_TAG_RESCALE_SLOPE)) - { - hasRescale_ = true; - } - else if (dicom.ParseDouble(doseGridScaling, Orthanc::DICOM_TAG_DOSE_GRID_SCALING)) - { - // This is for RT-DOSE - hasRescale_ = true; - isRTDose = true; - rescaleIntercept_ = 0; - rescaleSlope_ = doseGridScaling; - - if (!dicom.ParseInteger32(tmp, Orthanc::DICOM_TAG_BITS_STORED)) - { - // Type 1 tag, must be present - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - switch (tmp) - { - case 16: - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; - break; - - case 32: - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale32; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - } - - std::string photometric; - if (dicom.CopyToString(photometric, Orthanc::DICOM_TAG_PHOTOMETRIC_INTERPRETATION, false)) - { - photometric = Orthanc::Toolbox::StripSpaces(photometric); - } - else - { - // Type 1 tag, must be present - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - photometric_ = Orthanc::StringToPhotometricInterpretation(photometric.c_str()); - - isColor_ = (photometric != "MONOCHROME1" && - photometric != "MONOCHROME2"); - - // TODO Add more checks, e.g. on the number of bytes per value - // (cf. DicomImageInformation.h in Orthanc) - - if (!isRTDose) - { - if (isColor_) - { - expectedPixelFormat_ = Orthanc::PixelFormat_RGB24; - } - else if (isSigned_) - { - expectedPixelFormat_ = Orthanc::PixelFormat_SignedGrayscale16; - } - else - { - expectedPixelFormat_ = Orthanc::PixelFormat_Grayscale16; - } - } - } - - - void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom) - { - Orthanc::DicomMap converted; - - for (size_t i = 0; i < sizeof(IMAGE_TAGS) / sizeof(Orthanc::DicomTag); i++) - { - OrthancPlugins::DicomTag tag(IMAGE_TAGS[i].GetGroup(), IMAGE_TAGS[i].GetElement()); - - std::string value; - if (dicom.GetStringValue(value, tag)) - { - converted.SetValue(IMAGE_TAGS[i], value, false); - } - } - - ReadParameters(converted); - } - - - void DicomFrameConverter::ConvertFrameInplace(std::auto_ptr& source) const - { - assert(sizeof(float) == 4); - - if (source.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - if (source->GetFormat() == GetExpectedPixelFormat() && - source->GetFormat() == Orthanc::PixelFormat_RGB24) - { - // No conversion has to be done, check out (*) - return; - } - else - { - source.reset(ConvertFrame(*source)); - } - } - - - Orthanc::ImageAccessor* DicomFrameConverter::ConvertFrame(const Orthanc::ImageAccessor& source) const - { - assert(sizeof(float) == 4); - - Orthanc::PixelFormat sourceFormat = source.GetFormat(); - - if (sourceFormat != GetExpectedPixelFormat()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - - if (sourceFormat == Orthanc::PixelFormat_RGB24) - { - // This is the case of a color image. No conversion has to be done (*) - std::auto_ptr converted(new Orthanc::Image(Orthanc::PixelFormat_RGB24, - source.GetWidth(), - source.GetHeight(), - false)); - Orthanc::ImageProcessing::Copy(*converted, source); - return converted.release(); - } - else - { - assert(sourceFormat == Orthanc::PixelFormat_Grayscale16 || - sourceFormat == Orthanc::PixelFormat_Grayscale32 || - sourceFormat == Orthanc::PixelFormat_SignedGrayscale16); - - // This is the case of a grayscale frame. Convert it to Float32. - std::auto_ptr converted(new Orthanc::Image(Orthanc::PixelFormat_Float32, - source.GetWidth(), - source.GetHeight(), - false)); - Orthanc::ImageProcessing::Convert(*converted, source); - - // Correct rescale slope/intercept if need be - ApplyRescale(*converted, sourceFormat != Orthanc::PixelFormat_Grayscale32); - - return converted.release(); - } - } - - - void DicomFrameConverter::ApplyRescale(Orthanc::ImageAccessor& image, - bool useDouble) const - { - if (image.GetFormat() != Orthanc::PixelFormat_Float32) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - - if (hasRescale_) - { - for (unsigned int y = 0; y < image.GetHeight(); y++) - { - float* p = reinterpret_cast(image.GetRow(y)); - - if (useDouble) - { - // Slower, accurate implementation using double - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - double value = static_cast(*p); - *p = static_cast(value * rescaleSlope_ + rescaleIntercept_); - } - } - else - { - // Fast, approximate implementation using float - for (unsigned int x = 0; x < image.GetWidth(); x++, p++) - { - *p = (*p) * static_cast(rescaleSlope_) + static_cast(rescaleIntercept_); - } - } - } - } - } - - - double DicomFrameConverter::Apply(double x) const - { - return x * rescaleSlope_ + rescaleIntercept_; - } - -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/DicomFrameConverter.h --- a/Framework/Toolbox/DicomFrameConverter.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include -#include -#include - -#include - -namespace Deprecated -{ - /** - * This class is responsible for converting the pixel format of a - * DICOM frame coming from Orthanc, into a pixel format that is - * suitable for Stone, given the relevant DICOM tags: - * - Color frames will stay in the RGB24 format. - * - Grayscale frames will be converted to the Float32 format. - **/ - class DicomFrameConverter - { - private: - bool isSigned_; - bool isColor_; - bool hasRescale_; - double rescaleIntercept_; - double rescaleSlope_; - bool hasDefaultWindow_; - double defaultWindowCenter_; - double defaultWindowWidth_; - - Orthanc::PhotometricInterpretation photometric_; - Orthanc::PixelFormat expectedPixelFormat_; - - void SetDefaultParameters(); - - public: - DicomFrameConverter() - { - SetDefaultParameters(); - } - - ~DicomFrameConverter() - { - // TODO: check whether this dtor is called or not - // An MSVC warning explains that declaring an - // std::auto_ptr with a forward-declared type - // prevents its dtor from being called. Does not - // seem an issue here (only POD types inside), but - // definitely something to keep an eye on. - (void)0; - } - - // AM: this is required to serialize/deserialize it - DicomFrameConverter( - bool isSigned, - bool isColor, - bool hasRescale, - double rescaleIntercept, - double rescaleSlope, - bool hasDefaultWindow, - double defaultWindowCenter, - double defaultWindowWidth, - Orthanc::PhotometricInterpretation photometric, - Orthanc::PixelFormat expectedPixelFormat - ): - isSigned_(isSigned), - isColor_(isColor), - hasRescale_(hasRescale), - rescaleIntercept_(rescaleIntercept), - rescaleSlope_(rescaleSlope), - hasDefaultWindow_(hasDefaultWindow), - defaultWindowCenter_(defaultWindowCenter), - defaultWindowWidth_(defaultWindowWidth), - photometric_(photometric), - expectedPixelFormat_(expectedPixelFormat) - {} - - void GetParameters(bool& isSigned, - bool& isColor, - bool& hasRescale, - double& rescaleIntercept, - double& rescaleSlope, - bool& hasDefaultWindow, - double& defaultWindowCenter, - double& defaultWindowWidth, - Orthanc::PhotometricInterpretation& photometric, - Orthanc::PixelFormat& expectedPixelFormat) const - { - isSigned = isSigned_; - isColor = isColor_; - hasRescale = hasRescale_; - rescaleIntercept = rescaleIntercept_; - rescaleSlope = rescaleSlope_; - hasDefaultWindow = hasDefaultWindow_; - defaultWindowCenter = defaultWindowCenter_; - defaultWindowWidth = defaultWindowWidth_; - photometric = photometric_; - expectedPixelFormat = expectedPixelFormat_; - } - - Orthanc::PixelFormat GetExpectedPixelFormat() const - { - return expectedPixelFormat_; - } - - Orthanc::PhotometricInterpretation GetPhotometricInterpretation() const - { - return photometric_; - } - - void ReadParameters(const Orthanc::DicomMap& dicom); - - void ReadParameters(const OrthancPlugins::IDicomDataset& dicom); - - bool HasDefaultWindow() const - { - return hasDefaultWindow_; - } - - double GetDefaultWindowCenter() const - { - return defaultWindowCenter_; - } - - double GetDefaultWindowWidth() const - { - return defaultWindowWidth_; - } - - double GetRescaleIntercept() const - { - return rescaleIntercept_; - } - - double GetRescaleSlope() const - { - return rescaleSlope_; - } - - void ConvertFrameInplace(std::auto_ptr& source) const; - - Orthanc::ImageAccessor* ConvertFrame(const Orthanc::ImageAccessor& source) const; - - void ApplyRescale(Orthanc::ImageAccessor& image, - bool useDouble) const; - - double Apply(double x) const; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/DownloadStack.cpp --- a/Framework/Toolbox/DownloadStack.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,196 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "DownloadStack.h" - -#include - -#include - -namespace Deprecated -{ - bool DownloadStack::CheckInvariants() const - { - std::vector dequeued(nodes_.size(), true); - - int i = firstNode_; - while (i != NIL) - { - const Node& node = nodes_[i]; - - dequeued[i] = false; - - if (node.next_ != NIL && - nodes_[node.next_].prev_ != i) - { - return false; - } - - if (node.prev_ != NIL && - nodes_[node.prev_].next_ != i) - { - return false; - } - - i = nodes_[i].next_; - } - - for (size_t i = 0; i < nodes_.size(); i++) - { - if (nodes_[i].dequeued_ != dequeued[i]) - { - return false; - } - } - - return true; - } - - - DownloadStack::DownloadStack(unsigned int size) - { - nodes_.resize(size); - - if (size == 0) - { - firstNode_ = NIL; - } - else - { - for (size_t i = 0; i < size; i++) - { - nodes_[i].prev_ = static_cast(i - 1); - nodes_[i].next_ = static_cast(i + 1); - nodes_[i].dequeued_ = false; - } - - nodes_.front().prev_ = NIL; - nodes_.back().next_ = NIL; - firstNode_ = 0; - } - - assert(CheckInvariants()); - } - - - DownloadStack::~DownloadStack() - { - assert(CheckInvariants()); - } - - - bool DownloadStack::Pop(unsigned int& value) - { - assert(CheckInvariants()); - - if (firstNode_ == NIL) - { - for (size_t i = 0; i < nodes_.size(); i++) - { - assert(nodes_[i].dequeued_); - } - - return false; - } - else - { - assert(firstNode_ >= 0 && firstNode_ < static_cast(nodes_.size())); - value = firstNode_; - - Node& node = nodes_[firstNode_]; - assert(node.prev_ == NIL); - assert(!node.dequeued_); - - node.dequeued_ = true; - firstNode_ = node.next_; - - if (firstNode_ != NIL) - { - nodes_[firstNode_].prev_ = NIL; - } - - return true; - } - } - - - void DownloadStack::SetTopNodeInternal(unsigned int value) - { - assert(CheckInvariants()); - - Node& node = nodes_[value]; - - if (node.dequeued_) - { - // This node has already been processed by the download thread, nothing to do - return; - } - - // Remove the node from the list - if (node.prev_ == NIL) - { - assert(firstNode_ == static_cast(value)); - - // This is already the top node in the list, nothing to do - return; - } - - nodes_[node.prev_].next_ = node.next_; - - if (node.next_ != NIL) - { - nodes_[node.next_].prev_ = node.prev_; - } - - // Add back the node at the top of the list - assert(firstNode_ != NIL); - - Node& old = nodes_[firstNode_]; - assert(old.prev_ == NIL); - assert(!old.dequeued_); - node.prev_ = NIL; - node.next_ = firstNode_; - old.prev_ = value; - - firstNode_ = value; - } - - - void DownloadStack::SetTopNode(unsigned int value) - { - if (value >= nodes_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - SetTopNodeInternal(value); - } - - - void DownloadStack::SetTopNodePermissive(int value) - { - if (value >= 0 && - value < static_cast(nodes_.size())) - { - SetTopNodeInternal(value); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/DownloadStack.h --- a/Framework/Toolbox/DownloadStack.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include -#include - -namespace Deprecated -{ - class DownloadStack : public boost::noncopyable - { - private: - static const int NIL = -1; - - // This is a doubly-linked list - struct Node - { - int next_; - int prev_; - bool dequeued_; - }; - - std::vector nodes_; - int firstNode_; - - bool CheckInvariants() const; - - void SetTopNodeInternal(unsigned int value); - - public: - DownloadStack(unsigned int size); - - ~DownloadStack(); - - bool Pop(unsigned int& value); - - void SetTopNode(unsigned int value); - - void SetTopNodePermissive(int value); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/IDelayedCallExecutor.h --- a/Framework/Toolbox/IDelayedCallExecutor.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2018 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../../Framework/Messages/IObserver.h" -#include "../../Framework/Messages/ICallable.h" - -#include -#include - -#include -#include - -namespace Deprecated -{ - // The IDelayedCall executes a callback after a delay (equivalent to timeout() function in javascript). - class IDelayedCallExecutor : public boost::noncopyable - { - protected: - OrthancStone::MessageBroker& broker_; - - public: - ORTHANC_STONE_DEFINE_EMPTY_MESSAGE(__FILE__, __LINE__, TimeoutMessage); - - IDelayedCallExecutor(OrthancStone::MessageBroker& broker) : - broker_(broker) - { - } - - - virtual ~IDelayedCallExecutor() - { - } - - - virtual void Schedule(OrthancStone::MessageHandler* callback, - unsigned int timeoutInMs = 1000) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/IWebService.cpp --- a/Framework/Toolbox/IWebService.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "IWebService.h" - -#include - - -namespace Deprecated -{ - const Orthanc::IDynamicObject& - IWebService::HttpRequestSuccessMessage::GetPayload() const - { - if (HasPayload()) - { - return *payload_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - - const Orthanc::IDynamicObject& - IWebService::HttpRequestErrorMessage::GetPayload() const - { - if (HasPayload()) - { - return *payload_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/IWebService.h --- a/Framework/Toolbox/IWebService.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../../Framework/Messages/IObserver.h" -#include "../../Framework/Messages/ICallable.h" - -#include -#include - -#include -#include - -namespace Deprecated -{ - // The IWebService performs HTTP requests. - // Since applications can run in native or WASM environment and, since - // in a WASM environment, the WebService is asynchronous, the IWebservice - // also implements an asynchronous interface: you must schedule a request - // and you'll be notified when the response/error is ready. - class IWebService : public boost::noncopyable - { - protected: - OrthancStone::MessageBroker& broker_; - - public: - typedef std::map HttpHeaders; - - class HttpRequestSuccessMessage : public OrthancStone::IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const std::string& uri_; - const void* answer_; - size_t answerSize_; - const HttpHeaders& answerHeaders_; - const Orthanc::IDynamicObject* payload_; - - public: - HttpRequestSuccessMessage(const std::string& uri, - const void* answer, - size_t answerSize, - const HttpHeaders& answerHeaders, - const Orthanc::IDynamicObject* payload) : - uri_(uri), - answer_(answer), - answerSize_(answerSize), - answerHeaders_(answerHeaders), - payload_(payload) - { - } - - const std::string& GetUri() const - { - return uri_; - } - - const void* GetAnswer() const - { - return answer_; - } - - size_t GetAnswerSize() const - { - return answerSize_; - } - - const HttpHeaders& GetAnswerHttpHeaders() const - { - return answerHeaders_; - } - - bool HasPayload() const - { - return payload_ != NULL; - } - - const Orthanc::IDynamicObject& GetPayload() const; - }; - - - class HttpRequestErrorMessage : public OrthancStone::IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const std::string& uri_; - const Orthanc::IDynamicObject* payload_; - - public: - HttpRequestErrorMessage(const std::string& uri, - const Orthanc::IDynamicObject* payload) : - uri_(uri), - payload_(payload) - { - } - - const std::string& GetUri() const - { - return uri_; - } - - bool HasPayload() const - { - return payload_ != NULL; - } - - const Orthanc::IDynamicObject& GetPayload() const; - }; - - - IWebService(OrthancStone::MessageBroker& broker) : - broker_(broker) - { - } - - - virtual ~IWebService() - { - } - - virtual void EnableCache(bool enable) = 0; - - virtual void GetAsync(const std::string& uri, - const HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - unsigned int timeoutInSeconds = 60) = 0; - - virtual void PostAsync(const std::string& uri, - const HttpHeaders& headers, - const std::string& body, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - unsigned int timeoutInSeconds = 60) = 0; - - virtual void DeleteAsync(const std::string& uri, - const HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - unsigned int timeoutInSeconds = 60) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/OrthancApiClient.cpp --- a/Framework/Toolbox/OrthancApiClient.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,337 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - -#include "OrthancApiClient.h" - -#include "MessagingToolbox.h" -#include "Framework/Toolbox/MessagingToolbox.h" - -#include - -namespace Deprecated -{ - const Orthanc::IDynamicObject& OrthancApiClient::JsonResponseReadyMessage::GetPayload() const - { - if (HasPayload()) - { - return *payload_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - - const Orthanc::IDynamicObject& OrthancApiClient::BinaryResponseReadyMessage::GetPayload() const - { - if (HasPayload()) - { - return *payload_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - - const Orthanc::IDynamicObject& OrthancApiClient::EmptyResponseReadyMessage::GetPayload() const - { - if (HasPayload()) - { - return *payload_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - - class OrthancApiClient::WebServicePayload : public Orthanc::IDynamicObject - { - private: - std::auto_ptr< OrthancStone::MessageHandler > emptyHandler_; - std::auto_ptr< OrthancStone::MessageHandler > jsonHandler_; - std::auto_ptr< OrthancStone::MessageHandler > binaryHandler_; - std::auto_ptr< OrthancStone::MessageHandler > failureHandler_; - std::auto_ptr< Orthanc::IDynamicObject > userPayload_; - - void NotifyConversionError(const IWebService::HttpRequestSuccessMessage& message) const - { - if (failureHandler_.get() != NULL) - { - failureHandler_->Apply(IWebService::HttpRequestErrorMessage - (message.GetUri(), userPayload_.get())); - } - } - - public: - WebServicePayload(OrthancStone::MessageHandler* handler, - OrthancStone::MessageHandler* failureHandler, - Orthanc::IDynamicObject* userPayload) : - emptyHandler_(handler), - failureHandler_(failureHandler), - userPayload_(userPayload) - { - if (handler == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - WebServicePayload(OrthancStone::MessageHandler* handler, - OrthancStone::MessageHandler* failureHandler, - Orthanc::IDynamicObject* userPayload) : - binaryHandler_(handler), - failureHandler_(failureHandler), - userPayload_(userPayload) - { - if (handler == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - WebServicePayload(OrthancStone::MessageHandler* handler, - OrthancStone::MessageHandler* failureHandler, - Orthanc::IDynamicObject* userPayload) : - jsonHandler_(handler), - failureHandler_(failureHandler), - userPayload_(userPayload) - { - if (handler == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - void HandleSuccess(const IWebService::HttpRequestSuccessMessage& message) const - { - if (emptyHandler_.get() != NULL) - { - emptyHandler_->Apply(OrthancApiClient::EmptyResponseReadyMessage - (message.GetUri(), userPayload_.get())); - } - else if (binaryHandler_.get() != NULL) - { - binaryHandler_->Apply(OrthancApiClient::BinaryResponseReadyMessage - (message.GetUri(), message.GetAnswer(), - message.GetAnswerSize(), userPayload_.get())); - } - else if (jsonHandler_.get() != NULL) - { - Json::Value response; - if (OrthancStone::MessagingToolbox::ParseJson(response, message.GetAnswer(), message.GetAnswerSize())) - { - jsonHandler_->Apply(OrthancApiClient::JsonResponseReadyMessage - (message.GetUri(), response, userPayload_.get())); - } - else - { - NotifyConversionError(message); - } - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - void HandleFailure(const IWebService::HttpRequestErrorMessage& message) const - { - if (failureHandler_.get() != NULL) - { - failureHandler_->Apply(IWebService::HttpRequestErrorMessage - (message.GetUri(), userPayload_.get())); - } - } - }; - - - OrthancApiClient::OrthancApiClient(OrthancStone::MessageBroker& broker, - IWebService& web, - const std::string& baseUrl) : - IObservable(broker), - IObserver(broker), - web_(web), - baseUrl_(baseUrl) - { - } - - - void OrthancApiClient::GetJsonAsync( - const std::string& uri, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - IWebService::HttpHeaders emptyHeaders; - web_.GetAsync(baseUrl_ + uri, - emptyHeaders, - new WebServicePayload(successCallback, failureCallback, payload), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpSuccess), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); - } - - - void OrthancApiClient::GetBinaryAsync( - const std::string& uri, - const std::string& contentType, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - IWebService::HttpHeaders headers; - headers["Accept"] = contentType; - GetBinaryAsync(uri, headers, successCallback, failureCallback, payload); - } - - void OrthancApiClient::GetBinaryAsync( - const std::string& uri, - const IWebService::HttpHeaders& headers, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - // printf("GET [%s] [%s]\n", baseUrl_.c_str(), uri.c_str()); - - web_.GetAsync(baseUrl_ + uri, headers, - new WebServicePayload(successCallback, failureCallback, payload), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpSuccess), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); - } - - - void OrthancApiClient::PostBinaryAsyncExpectJson( - const std::string& uri, - const std::string& body, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, - new WebServicePayload(successCallback, failureCallback, payload), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpSuccess), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); - - } - - void OrthancApiClient::PostBinaryAsync( - const std::string& uri, - const std::string& body) - { - web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, NULL, NULL, NULL); - } - - void OrthancApiClient::PostBinaryAsync( - const std::string& uri, - const std::string& body, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload /* takes ownership */) - { - web_.PostAsync(baseUrl_ + uri, IWebService::HttpHeaders(), body, - new WebServicePayload(successCallback, failureCallback, payload), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpSuccess), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); - } - - void OrthancApiClient::PostJsonAsyncExpectJson( - const std::string& uri, - const Json::Value& data, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); - return PostBinaryAsyncExpectJson(uri, body, successCallback, failureCallback, payload); - } - - void OrthancApiClient::PostJsonAsync( - const std::string& uri, - const Json::Value& data) - { - std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); - return PostBinaryAsync(uri, body); - } - - void OrthancApiClient::PostJsonAsync( - const std::string& uri, - const Json::Value& data, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload /* takes ownership */) - { - std::string body; - OrthancStone::MessagingToolbox::JsonToString(body, data); - return PostBinaryAsync(uri, body, successCallback, failureCallback, payload); - } - - void OrthancApiClient::DeleteAsync( - const std::string& uri, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback, - Orthanc::IDynamicObject* payload) - { - web_.DeleteAsync(baseUrl_ + uri, IWebService::HttpHeaders(), - new WebServicePayload(successCallback, failureCallback, payload), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpSuccess), - new OrthancStone::Callable - (*this, &OrthancApiClient::NotifyHttpError)); - } - - - void OrthancApiClient::NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message) - { - if (message.HasPayload()) - { - dynamic_cast(message.GetPayload()).HandleSuccess(message); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - void OrthancApiClient::NotifyHttpError(const IWebService::HttpRequestErrorMessage& message) - { - if (message.HasPayload()) - { - dynamic_cast(message.GetPayload()).HandleFailure(message); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/OrthancApiClient.h --- a/Framework/Toolbox/OrthancApiClient.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,243 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include -#include - -#include "IWebService.h" -#include "../Messages/IObservable.h" -#include "../Messages/Promise.h" - -namespace Deprecated -{ - class OrthancApiClient : - public OrthancStone::IObservable, - public OrthancStone::IObserver - { - public: - class JsonResponseReadyMessage : public OrthancStone::IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const std::string& uri_; - const Json::Value& json_; - const Orthanc::IDynamicObject* payload_; - - public: - JsonResponseReadyMessage(const std::string& uri, - const Json::Value& json, - const Orthanc::IDynamicObject* payload) : - uri_(uri), - json_(json), - payload_(payload) - { - } - - const std::string& GetUri() const - { - return uri_; - } - - const Json::Value& GetJson() const - { - return json_; - } - - bool HasPayload() const - { - return payload_ != NULL; - } - - const Orthanc::IDynamicObject& GetPayload() const; - }; - - - class BinaryResponseReadyMessage : public OrthancStone::IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const std::string& uri_; - const void* answer_; - size_t answerSize_; - const Orthanc::IDynamicObject* payload_; - - public: - BinaryResponseReadyMessage(const std::string& uri, - const void* answer, - size_t answerSize, - const Orthanc::IDynamicObject* payload) : - uri_(uri), - answer_(answer), - answerSize_(answerSize), - payload_(payload) - { - } - - const std::string& GetUri() const - { - return uri_; - } - - const void* GetAnswer() const - { - return answer_; - } - - size_t GetAnswerSize() const - { - return answerSize_; - } - - bool HasPayload() const - { - return payload_ != NULL; - } - - const Orthanc::IDynamicObject& GetPayload() const; - }; - - - class EmptyResponseReadyMessage : public OrthancStone::IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const std::string& uri_; - const Orthanc::IDynamicObject* payload_; - - public: - EmptyResponseReadyMessage(const std::string& uri, - const Orthanc::IDynamicObject* payload) : - uri_(uri), - payload_(payload) - { - } - - const std::string& GetUri() const - { - return uri_; - } - - bool HasPayload() const - { - return payload_ != NULL; - } - - const Orthanc::IDynamicObject& GetPayload() const; - }; - - - - private: - class WebServicePayload; - - protected: - IWebService& web_; - std::string baseUrl_; - - public: - OrthancApiClient(OrthancStone::MessageBroker& broker, - IWebService& web, - const std::string& baseUrl); - - virtual ~OrthancApiClient() - { - } - - const std::string& GetBaseUrl() const {return baseUrl_;} - - // schedule a GET request expecting a JSON response. - void GetJsonAsync(const std::string& uri, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a GET request expecting a binary response. - void GetBinaryAsync(const std::string& uri, - const std::string& contentType, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a GET request expecting a binary response. - void GetBinaryAsync(const std::string& uri, - const IWebService::HttpHeaders& headers, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a POST request expecting a JSON response. - void PostBinaryAsyncExpectJson(const std::string& uri, - const std::string& body, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a POST request expecting a JSON response. - void PostJsonAsyncExpectJson(const std::string& uri, - const Json::Value& data, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a POST request and don't mind the response. - void PostJsonAsync(const std::string& uri, - const Json::Value& data); - - // schedule a POST request and don't expect any response. - void PostJsonAsync(const std::string& uri, - const Json::Value& data, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - - // schedule a POST request and don't mind the response. - void PostBinaryAsync(const std::string& uri, - const std::string& body); - - // schedule a POST request and don't expect any response. - void PostBinaryAsync(const std::string& uri, - const std::string& body, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - // schedule a DELETE request expecting an empty response. - void DeleteAsync(const std::string& uri, - OrthancStone::MessageHandler* successCallback, - OrthancStone::MessageHandler* failureCallback = NULL, - Orthanc::IDynamicObject* payload = NULL /* takes ownership */); - - void NotifyHttpSuccess(const IWebService::HttpRequestSuccessMessage& message); - - void NotifyHttpError(const IWebService::HttpRequestErrorMessage& message); - - private: - void HandleFromCache(const std::string& uri, - const IWebService::HttpHeaders& headers, - Orthanc::IDynamicObject* payload /* takes ownership */); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/OrthancSlicesLoader.cpp --- a/Framework/Toolbox/OrthancSlicesLoader.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,904 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "OrthancSlicesLoader.h" - -#include "MessagingToolbox.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - - -/** - * TODO This is a SLOW implementation of base64 decoding, because - * "Orthanc::Toolbox::DecodeBase64()" does not work properly with - * WASM. UNDERSTAND WHY. - * https://stackoverflow.com/a/34571089/881731 - **/ -static std::string base64_decode(const std::string &in) -{ - std::string out; - - std::vector T(256,-1); - for (int i=0; i<64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; - - int val=0, valb=-8; - for (size_t i = 0; i < in.size(); i++) { - unsigned char c = in[i]; - if (T[c] == -1) break; - val = (val<<6) + T[c]; - valb += 6; - if (valb>=0) { - out.push_back(char((val>>valb)&0xFF)); - valb-=8; - } - } - return out; -} - - - -namespace Deprecated -{ - class OrthancSlicesLoader::Operation : public Orthanc::IDynamicObject - { - private: - Mode mode_; - unsigned int frame_; - unsigned int sliceIndex_; - const Slice* slice_; - std::string instanceId_; - OrthancStone::SliceImageQuality quality_; - - Operation(Mode mode) : - mode_(mode) - { - } - - public: - Mode GetMode() const - { - return mode_; - } - - OrthancStone::SliceImageQuality GetQuality() const - { - assert(mode_ == Mode_LoadImage || - mode_ == Mode_LoadRawImage); - return quality_; - } - - unsigned int GetSliceIndex() const - { - assert(mode_ == Mode_LoadImage || - mode_ == Mode_LoadRawImage); - return sliceIndex_; - } - - const Slice& GetSlice() const - { - assert(mode_ == Mode_LoadImage || - mode_ == Mode_LoadRawImage); - assert(slice_ != NULL); - return *slice_; - } - - unsigned int GetFrame() const - { - assert(mode_ == Mode_FrameGeometry); - return frame_; - } - - const std::string& GetInstanceId() const - { - assert(mode_ == Mode_FrameGeometry || - mode_ == Mode_InstanceGeometry); - return instanceId_; - } - - static Operation* DownloadInstanceGeometry(const std::string& instanceId) - { - std::auto_ptr operation(new Operation(Mode_InstanceGeometry)); - operation->instanceId_ = instanceId; - return operation.release(); - } - - static Operation* DownloadFrameGeometry(const std::string& instanceId, - unsigned int frame) - { - std::auto_ptr operation(new Operation(Mode_FrameGeometry)); - operation->instanceId_ = instanceId; - operation->frame_ = frame; - return operation.release(); - } - - static Operation* DownloadSliceImage(unsigned int sliceIndex, - const Slice& slice, - OrthancStone::SliceImageQuality quality) - { - std::auto_ptr tmp(new Operation(Mode_LoadImage)); - tmp->sliceIndex_ = sliceIndex; - tmp->slice_ = &slice; - tmp->quality_ = quality; - return tmp.release(); - } - - static Operation* DownloadSliceRawImage(unsigned int sliceIndex, - const Slice& slice) - { - std::auto_ptr tmp(new Operation(Mode_LoadRawImage)); - tmp->sliceIndex_ = sliceIndex; - tmp->slice_ = &slice; - tmp->quality_ = OrthancStone::SliceImageQuality_InternalRaw; - return tmp.release(); - } - - static Operation* DownloadDicomFile(const Slice& slice) - { - std::auto_ptr tmp(new Operation(Mode_LoadDicomFile)); - tmp->slice_ = &slice; - return tmp.release(); - } - - }; - - void OrthancSlicesLoader::NotifySliceImageSuccess(const Operation& operation, - const Orthanc::ImageAccessor& image) - { - OrthancSlicesLoader::SliceImageReadyMessage msg - (*this, operation.GetSliceIndex(), operation.GetSlice(), image, operation.GetQuality()); - BroadcastMessage(msg); - } - - - void OrthancSlicesLoader::NotifySliceImageError(const Operation& operation) - { - OrthancSlicesLoader::SliceImageErrorMessage msg - (*this, operation.GetSliceIndex(), operation.GetSlice(), operation.GetQuality()); - BroadcastMessage(msg); - } - - - void OrthancSlicesLoader::SortAndFinalizeSlices() - { - bool ok = slices_.Sort(); - - state_ = State_GeometryReady; - - if (ok) - { - LOG(INFO) << "Loaded a series with " << slices_.GetSlicesCount() << " slice(s)"; - BroadcastMessage(SliceGeometryReadyMessage(*this)); - } - else - { - LOG(ERROR) << "This series is empty"; - BroadcastMessage(SliceGeometryErrorMessage(*this)); - } - } - - void OrthancSlicesLoader::OnGeometryError(const IWebService::HttpRequestErrorMessage& message) - { - BroadcastMessage(SliceGeometryErrorMessage(*this)); - state_ = State_Error; - } - - void OrthancSlicesLoader::OnSliceImageError(const IWebService::HttpRequestErrorMessage& message) - { - NotifySliceImageError(dynamic_cast(message.GetPayload())); - state_ = State_Error; - } - - void OrthancSlicesLoader::ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) - { - const Json::Value& series = message.GetJson(); - Json::Value::Members instances = series.getMemberNames(); - - slices_.Reserve(instances.size()); - - for (size_t i = 0; i < instances.size(); i++) - { - OrthancPlugins::FullOrthancDataset dataset(series[instances[i]]); - - Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); - - unsigned int frames; - if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) - { - frames = 1; - } - - for (unsigned int frame = 0; frame < frames; frame++) - { - std::auto_ptr slice(new Slice); - if (slice->ParseOrthancFrame(dicom, instances[i], frame)) - { - OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); - slices_.AddSlice(geometry, slice.release()); - } - else - { - LOG(WARNING) << "Skipping invalid frame " << frame << " within instance " << instances[i]; - } - } - } - - SortAndFinalizeSlices(); - } - - void OrthancSlicesLoader::ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) - { - const Json::Value& tags = message.GetJson(); - const std::string& instanceId = dynamic_cast(message.GetPayload()).GetInstanceId(); - - OrthancPlugins::FullOrthancDataset dataset(tags); - - Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); - - unsigned int frames; - if (!dicom.ParseUnsignedInteger32(frames, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) - { - frames = 1; - } - - LOG(INFO) << "Instance " << instanceId << " contains " << frames << " frame(s)"; - - for (unsigned int frame = 0; frame < frames; frame++) - { - std::auto_ptr slice(new Slice); - if (slice->ParseOrthancFrame(dicom, instanceId, frame)) - { - OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); - slices_.AddSlice(geometry, slice.release()); - } - else - { - LOG(WARNING) << "Skipping invalid multi-frame instance " << instanceId; - BroadcastMessage(SliceGeometryErrorMessage(*this)); - return; - } - } - - SortAndFinalizeSlices(); - } - - - void OrthancSlicesLoader::ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message) - { - const Json::Value& tags = message.GetJson(); - const std::string& instanceId = dynamic_cast(message.GetPayload()).GetInstanceId(); - unsigned int frame = dynamic_cast(message.GetPayload()).GetFrame(); - - OrthancPlugins::FullOrthancDataset dataset(tags); - - state_ = State_GeometryReady; - - Orthanc::DicomMap dicom; - OrthancStone::MessagingToolbox::ConvertDataset(dicom, dataset); - - std::auto_ptr slice(new Slice); - if (slice->ParseOrthancFrame(dicom, instanceId, frame)) - { - LOG(INFO) << "Loaded instance geometry " << instanceId; - - OrthancStone::CoordinateSystem3D geometry = slice->GetGeometry(); - slices_.AddSlice(geometry, slice.release()); - - BroadcastMessage(SliceGeometryReadyMessage(*this)); - } - else - { - LOG(WARNING) << "Skipping invalid instance " << instanceId; - BroadcastMessage(SliceGeometryErrorMessage(*this)); - } - } - - - void OrthancSlicesLoader::ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message) - { - const Operation& operation = dynamic_cast(message.GetPayload()); - std::auto_ptr image; - - try - { - image.reset(new Orthanc::PngReader); - dynamic_cast(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize()); - } - catch (Orthanc::OrthancException&) - { - NotifySliceImageError(operation); - return; - } - - if (image->GetWidth() != operation.GetSlice().GetWidth() || - image->GetHeight() != operation.GetSlice().GetHeight()) - { - NotifySliceImageError(operation); - return; - } - - if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() == - Orthanc::PixelFormat_SignedGrayscale16) - { - if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) - { - image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); - } - else - { - NotifySliceImageError(operation); - return; - } - } - - NotifySliceImageSuccess(operation, *image); - } - - void OrthancSlicesLoader::ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message) - { - const Operation& operation = dynamic_cast(message.GetPayload()); - std::auto_ptr image; - - try - { - image.reset(new Orthanc::PamReader); - dynamic_cast(*image).ReadFromMemory(message.GetAnswer(), message.GetAnswerSize()); - } - catch (Orthanc::OrthancException&) - { - NotifySliceImageError(operation); - return; - } - - if (image->GetWidth() != operation.GetSlice().GetWidth() || - image->GetHeight() != operation.GetSlice().GetHeight()) - { - NotifySliceImageError(operation); - return; - } - - if (operation.GetSlice().GetConverter().GetExpectedPixelFormat() == - Orthanc::PixelFormat_SignedGrayscale16) - { - if (image->GetFormat() == Orthanc::PixelFormat_Grayscale16) - { - image->SetFormat(Orthanc::PixelFormat_SignedGrayscale16); - } - else - { - NotifySliceImageError(operation); - return; - } - } - - NotifySliceImageSuccess(operation, *image); - } - - - void OrthancSlicesLoader::ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message) - { - const Operation& operation = dynamic_cast(message.GetPayload()); - - const Json::Value& encoded = message.GetJson(); - if (encoded.type() != Json::objectValue || - !encoded.isMember("Orthanc") || - encoded["Orthanc"].type() != Json::objectValue) - { - NotifySliceImageError(operation); - return; - } - - const Json::Value& info = encoded["Orthanc"]; - if (!info.isMember("PixelData") || - !info.isMember("Stretched") || - !info.isMember("Compression") || - info["Compression"].type() != Json::stringValue || - info["PixelData"].type() != Json::stringValue || - info["Stretched"].type() != Json::booleanValue || - info["Compression"].asString() != "Jpeg") - { - NotifySliceImageError(operation); - return; - } - - bool isSigned = false; - bool isStretched = info["Stretched"].asBool(); - - if (info.isMember("IsSigned")) - { - if (info["IsSigned"].type() != Json::booleanValue) - { - NotifySliceImageError(operation); - return; - } - else - { - isSigned = info["IsSigned"].asBool(); - } - } - - std::auto_ptr reader; - - { - std::string jpeg; - //Orthanc::Toolbox::DecodeBase64(jpeg, info["PixelData"].asString()); - jpeg = base64_decode(info["PixelData"].asString()); - - try - { - reader.reset(new Orthanc::JpegReader); - dynamic_cast(*reader).ReadFromMemory(jpeg); - } - catch (Orthanc::OrthancException&) - { - NotifySliceImageError(operation); - return; - } - } - - Orthanc::PixelFormat expectedFormat = - operation.GetSlice().GetConverter().GetExpectedPixelFormat(); - - if (reader->GetFormat() == Orthanc::PixelFormat_RGB24) // This is a color image - { - if (expectedFormat != Orthanc::PixelFormat_RGB24) - { - NotifySliceImageError(operation); - return; - } - - if (isSigned || isStretched) - { - NotifySliceImageError(operation); - return; - } - else - { - NotifySliceImageSuccess(operation, *reader); - return; - } - } - - if (reader->GetFormat() != Orthanc::PixelFormat_Grayscale8) - { - NotifySliceImageError(operation); - return; - } - - if (!isStretched) - { - if (expectedFormat != reader->GetFormat()) - { - NotifySliceImageError(operation); - return; - } - else - { - NotifySliceImageSuccess(operation, *reader); - return; - } - } - - int32_t stretchLow = 0; - int32_t stretchHigh = 0; - - if (!info.isMember("StretchLow") || - !info.isMember("StretchHigh") || - info["StretchLow"].type() != Json::intValue || - info["StretchHigh"].type() != Json::intValue) - { - NotifySliceImageError(operation); - return; - } - - stretchLow = info["StretchLow"].asInt(); - stretchHigh = info["StretchHigh"].asInt(); - - if (stretchLow < -32768 || - stretchHigh > 65535 || - (stretchLow < 0 && stretchHigh > 32767)) - { - // This range cannot be represented with a uint16_t or an int16_t - NotifySliceImageError(operation); - return; - } - - // Decode a grayscale JPEG 8bpp image coming from the Web viewer - std::auto_ptr image - (new Orthanc::Image(expectedFormat, reader->GetWidth(), reader->GetHeight(), false)); - - Orthanc::ImageProcessing::Convert(*image, *reader); - reader.reset(); - - float scaling = static_cast(stretchHigh - stretchLow) / 255.0f; - - if (!OrthancStone::LinearAlgebra::IsCloseToZero(scaling)) - { - float offset = static_cast(stretchLow) / scaling; - Orthanc::ImageProcessing::ShiftScale(*image, offset, scaling, true); - } - - NotifySliceImageSuccess(operation, *image); - } - - - class StringImage : public Orthanc::ImageAccessor - { - private: - std::string buffer_; - - public: - StringImage(Orthanc::PixelFormat format, - unsigned int width, - unsigned int height, - std::string& buffer) - { - if (buffer.size() != Orthanc::GetBytesPerPixel(format) * width * height) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat); - } - - buffer_.swap(buffer); // The source buffer is now empty - - void* data = (buffer_.empty() ? NULL : &buffer_[0]); - - AssignWritable(format, width, height, - Orthanc::GetBytesPerPixel(format) * width, data); - } - }; - - void OrthancSlicesLoader::ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message) - { - const Operation& operation = dynamic_cast(message.GetPayload()); - Orthanc::GzipCompressor compressor; - - std::string raw; - compressor.Uncompress(raw, message.GetAnswer(), message.GetAnswerSize()); - - const Orthanc::DicomImageInformation& info = operation.GetSlice().GetImageInformation(); - - if (info.GetBitsAllocated() == 32 && - info.GetBitsStored() == 32 && - info.GetHighBit() == 31 && - info.GetChannelCount() == 1 && - !info.IsSigned() && - info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && - raw.size() == info.GetWidth() * info.GetHeight() * 4) - { - // This is the case of RT-DOSE (uint32_t values) - - std::auto_ptr image - (new StringImage(Orthanc::PixelFormat_Grayscale32, info.GetWidth(), - info.GetHeight(), raw)); - - // TODO - Only for big endian - for (unsigned int y = 0; y < image->GetHeight(); y++) - { - uint32_t *p = reinterpret_cast(image->GetRow(y)); - for (unsigned int x = 0; x < image->GetWidth(); x++, p++) - { - *p = le32toh(*p); - } - } - - NotifySliceImageSuccess(operation, *image); - } - else if (info.GetBitsAllocated() == 16 && - info.GetBitsStored() == 16 && - info.GetHighBit() == 15 && - info.GetChannelCount() == 1 && - !info.IsSigned() && - info.GetPhotometricInterpretation() == Orthanc::PhotometricInterpretation_Monochrome2 && - raw.size() == info.GetWidth() * info.GetHeight() * 2) - { - std::auto_ptr image - (new StringImage(Orthanc::PixelFormat_Grayscale16, info.GetWidth(), - info.GetHeight(), raw)); - - // TODO - Big endian ? - - NotifySliceImageSuccess(operation, *image); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - } - - - OrthancSlicesLoader::OrthancSlicesLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - OrthancStone::IObservable(broker), - OrthancStone::IObserver(broker), - orthanc_(orthanc), - state_(State_Initialization) - { - } - - - void OrthancSlicesLoader::ScheduleLoadSeries(const std::string& seriesId) - { - if (state_ != State_Initialization) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - state_ = State_LoadingGeometry; - orthanc_.GetJsonAsync("/series/" + seriesId + "/instances-tags", - new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseSeriesGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - NULL); - } - } - - void OrthancSlicesLoader::ScheduleLoadInstance(const std::string& instanceId) - { - if (state_ != State_Initialization) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - state_ = State_LoadingGeometry; - - // Tag "3004-000c" is "Grid Frame Offset Vector", which is - // mandatory to read RT DOSE, but is too long to be returned by default - orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags?ignore-length=3004-000c", - new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseInstanceGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadInstanceGeometry(instanceId)); - } - } - - - void OrthancSlicesLoader::ScheduleLoadFrame(const std::string& instanceId, - unsigned int frame) - { - if (state_ != State_Initialization) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - state_ = State_LoadingGeometry; - - orthanc_.GetJsonAsync("/instances/" + instanceId + "/tags", - new OrthancStone::Callable(*this, &OrthancSlicesLoader::ParseFrameGeometry), - new OrthancStone::Callable(*this, &OrthancSlicesLoader::OnGeometryError), - Operation::DownloadFrameGeometry(instanceId, frame)); - } - } - - - bool OrthancSlicesLoader::IsGeometryReady() const - { - return state_ == State_GeometryReady; - } - - - size_t OrthancSlicesLoader::GetSlicesCount() const - { - if (state_ != State_GeometryReady) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return slices_.GetSlicesCount(); - } - - - const Slice& OrthancSlicesLoader::GetSlice(size_t index) const - { - if (state_ != State_GeometryReady) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return dynamic_cast(slices_.GetSlicePayload(index)); - } - - - bool OrthancSlicesLoader::LookupSlice(size_t& index, - const OrthancStone::CoordinateSystem3D& plane) const - { - if (state_ != State_GeometryReady) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - double distance; - return (slices_.LookupClosestSlice(index, distance, plane) && - distance <= GetSlice(index).GetThickness() / 2.0); - } - - - void OrthancSlicesLoader::ScheduleSliceImagePng(const Slice& slice, - size_t index) - { - std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + - boost::lexical_cast(slice.GetFrame())); - - switch (slice.GetConverter().GetExpectedPixelFormat()) - { - case Orthanc::PixelFormat_RGB24: - uri += "/preview"; - break; - - case Orthanc::PixelFormat_Grayscale16: - uri += "/image-uint16"; - break; - - case Orthanc::PixelFormat_SignedGrayscale16: - uri += "/image-int16"; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - orthanc_.GetBinaryAsync(uri, "image/png", - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceImagePng), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast(index), slice, OrthancStone::SliceImageQuality_FullPng)); -} - - void OrthancSlicesLoader::ScheduleSliceImagePam(const Slice& slice, - size_t index) - { - std::string uri = - ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + - boost::lexical_cast(slice.GetFrame())); - - switch (slice.GetConverter().GetExpectedPixelFormat()) - { - case Orthanc::PixelFormat_RGB24: - uri += "/preview"; - break; - - case Orthanc::PixelFormat_Grayscale16: - uri += "/image-uint16"; - break; - - case Orthanc::PixelFormat_SignedGrayscale16: - uri += "/image-int16"; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - orthanc_.GetBinaryAsync(uri, "image/x-portable-arbitrarymap", - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceImagePam), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage(static_cast(index), - slice, OrthancStone::SliceImageQuality_FullPam)); - } - - - - void OrthancSlicesLoader::ScheduleSliceImageJpeg(const Slice& slice, - size_t index, - OrthancStone::SliceImageQuality quality) - { - unsigned int value; - - switch (quality) - { - case OrthancStone::SliceImageQuality_Jpeg50: - value = 50; - break; - - case OrthancStone::SliceImageQuality_Jpeg90: - value = 90; - break; - - case OrthancStone::SliceImageQuality_Jpeg95: - value = 95; - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - // This requires the official Web viewer plugin to be installed! - std::string uri = ("/web-viewer/instances/jpeg" + - boost::lexical_cast(value) + - "-" + slice.GetOrthancInstanceId() + "_" + - boost::lexical_cast(slice.GetFrame())); - - orthanc_.GetJsonAsync(uri, - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceImageJpeg), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceImage( - static_cast(index), slice, quality)); - } - - - - void OrthancSlicesLoader::ScheduleLoadSliceImage(size_t index, - OrthancStone::SliceImageQuality quality) - { - if (state_ != State_GeometryReady) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - const Slice& slice = GetSlice(index); - - if (slice.HasOrthancDecoding()) - { - switch (quality) - { - case OrthancStone::SliceImageQuality_FullPng: - ScheduleSliceImagePng(slice, index); - break; - case OrthancStone::SliceImageQuality_FullPam: - ScheduleSliceImagePam(slice, index); - break; - default: - ScheduleSliceImageJpeg(slice, index, quality); - } - } - else - { - std::string uri = ("/instances/" + slice.GetOrthancInstanceId() + "/frames/" + - boost::lexical_cast(slice.GetFrame()) + "/raw.gz"); - orthanc_.GetBinaryAsync(uri, IWebService::HttpHeaders(), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::ParseSliceRawImage), - new OrthancStone::Callable - (*this, &OrthancSlicesLoader::OnSliceImageError), - Operation::DownloadSliceRawImage( - static_cast(index), slice)); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/OrthancSlicesLoader.h --- a/Framework/Toolbox/OrthancSlicesLoader.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,209 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Messages/IObservable.h" -#include "../StoneEnumerations.h" -#include "IWebService.h" -#include "OrthancApiClient.h" -#include "SlicesSorter.h" -#include "Slice.h" - -#include - - -namespace Deprecated -{ - class OrthancSlicesLoader : public OrthancStone::IObservable, public OrthancStone::IObserver - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryReadyMessage, OrthancSlicesLoader); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, SliceGeometryErrorMessage, OrthancSlicesLoader); - - - class SliceImageReadyMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - unsigned int sliceIndex_; - const Slice& slice_; - const Orthanc::ImageAccessor& image_; - OrthancStone::SliceImageQuality effectiveQuality_; - - public: - SliceImageReadyMessage(const OrthancSlicesLoader& origin, - unsigned int sliceIndex, - const Slice& slice, - const Orthanc::ImageAccessor& image, - OrthancStone::SliceImageQuality effectiveQuality) : - OriginMessage(origin), - sliceIndex_(sliceIndex), - slice_(slice), - image_(image), - effectiveQuality_(effectiveQuality) - { - } - - unsigned int GetSliceIndex() const - { - return sliceIndex_; - } - - const Slice& GetSlice() const - { - return slice_; - } - - const Orthanc::ImageAccessor& GetImage() const - { - return image_; - } - - OrthancStone::SliceImageQuality GetEffectiveQuality() const - { - return effectiveQuality_; - } - }; - - - class SliceImageErrorMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const Slice& slice_; - unsigned int sliceIndex_; - OrthancStone::SliceImageQuality effectiveQuality_; - - public: - SliceImageErrorMessage(const OrthancSlicesLoader& origin, - unsigned int sliceIndex, - const Slice& slice, - OrthancStone::SliceImageQuality effectiveQuality) : - OriginMessage(origin), - slice_(slice), - sliceIndex_(sliceIndex), - effectiveQuality_(effectiveQuality) - { - } - unsigned int GetSliceIndex() const - { - return sliceIndex_; - } - - const Slice& GetSlice() const - { - return slice_; - } - - OrthancStone::SliceImageQuality GetEffectiveQuality() const - { - return effectiveQuality_; - } - }; - - private: - enum State - { - State_Error, - State_Initialization, - State_LoadingGeometry, - State_GeometryReady - }; - - enum Mode - { - Mode_SeriesGeometry, - Mode_InstanceGeometry, - Mode_FrameGeometry, - Mode_LoadImage, - Mode_LoadRawImage, - Mode_LoadDicomFile - }; - - class Operation; - - OrthancApiClient& orthanc_; - State state_; - OrthancStone::SlicesSorter slices_; - - void NotifySliceImageSuccess(const Operation& operation, - const Orthanc::ImageAccessor& image); - - void NotifySliceImageError(const Operation& operation); - - void OnGeometryError(const IWebService::HttpRequestErrorMessage& message); - - void OnSliceImageError(const IWebService::HttpRequestErrorMessage& message); - - void ParseSeriesGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); - - void ParseInstanceGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); - - void ParseFrameGeometry(const OrthancApiClient::JsonResponseReadyMessage& message); - - void ParseSliceImagePng(const OrthancApiClient::BinaryResponseReadyMessage& message); - - void ParseSliceImagePam(const OrthancApiClient::BinaryResponseReadyMessage& message); - - void ParseSliceImageJpeg(const OrthancApiClient::JsonResponseReadyMessage& message); - - void ParseSliceRawImage(const OrthancApiClient::BinaryResponseReadyMessage& message); - - void ScheduleSliceImagePng(const Slice& slice, - size_t index); - - void ScheduleSliceImagePam(const Slice& slice, - size_t index); - - void ScheduleSliceImageJpeg(const Slice& slice, - size_t index, - OrthancStone::SliceImageQuality quality); - - void SortAndFinalizeSlices(); - - public: - OrthancSlicesLoader(OrthancStone::MessageBroker& broker, - //ISliceLoaderObserver& callback, - OrthancApiClient& orthancApi); - - void ScheduleLoadSeries(const std::string& seriesId); - - void ScheduleLoadInstance(const std::string& instanceId); - - void ScheduleLoadFrame(const std::string& instanceId, - unsigned int frame); - - bool IsGeometryReady() const; - - size_t GetSlicesCount() const; - - const Slice& GetSlice(size_t index) const; - - bool LookupSlice(size_t& index, - const OrthancStone::CoordinateSystem3D& plane) const; - - void ScheduleLoadSliceImage(size_t index, - OrthancStone::SliceImageQuality requestedQuality); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/Slice.cpp --- a/Framework/Toolbox/Slice.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "Slice.h" - -#include "../StoneEnumerations.h" -#include "GeometryToolbox.h" - -#include -#include -#include - -#include - -namespace Deprecated -{ - static bool ParseDouble(double& target, - const std::string& source) - { - try - { - target = boost::lexical_cast(source); - return true; - } - catch (boost::bad_lexical_cast&) - { - return false; - } - } - - Slice* Slice::Clone() const - { - std::auto_ptr target(new Slice()); - - target->type_ = type_; - target->orthancInstanceId_ = orthancInstanceId_; - target->sopClassUid_ = sopClassUid_; - target->frame_ = frame_; - target->frameCount_ = frameCount_; - target->geometry_ = geometry_; - target->pixelSpacingX_ = pixelSpacingX_; - target->pixelSpacingY_ = pixelSpacingY_; - target->thickness_ = thickness_; - target->width_ = width_; - target->height_ = height_; - target->converter_ = converter_; - if (imageInformation_.get() != NULL) - target->imageInformation_.reset(imageInformation_->Clone()); - - return target.release(); - } - - bool Slice::ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset, - unsigned int frame) - { - // http://dicom.nema.org/medical/Dicom/2016a/output/chtml/part03/sect_C.8.8.3.2.html - - { - std::string increment; - - if (dataset.CopyToString(increment, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER, false)) - { - Orthanc::Toolbox::ToUpperCase(increment); - if (increment != "3004,000C") // This is the "Grid Frame Offset Vector" tag - { - LOG(ERROR) << "Bad value for the \"FrameIncrementPointer\" tag"; - return false; - } - } - } - - std::string offsetTag; - - if (!dataset.CopyToString(offsetTag, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, false) || - offsetTag.empty()) - { - LOG(ERROR) << "Cannot read the \"GridFrameOffsetVector\" tag, check you are using Orthanc >= 1.3.1"; - return false; - } - - std::vector offsets; - Orthanc::Toolbox::TokenizeString(offsets, offsetTag, '\\'); - - if (frameCount_ <= 1 || - offsets.size() < frameCount_ || - offsets.size() < 2 || - frame >= frameCount_) - { - LOG(ERROR) << "No information about the 3D location of some slice(s) in a RT DOSE"; - return false; - } - - double offset0, offset1, z; - - if (!ParseDouble(offset0, offsets[0]) || - !ParseDouble(offset1, offsets[1]) || - !ParseDouble(z, offsets[frame])) - { - LOG(ERROR) << "Invalid syntax"; - return false; - } - - if (!OrthancStone::LinearAlgebra::IsCloseToZero(offset0)) - { - LOG(ERROR) << "Invalid syntax"; - return false; - } - - geometry_ = OrthancStone::CoordinateSystem3D(geometry_.GetOrigin() + z * geometry_.GetNormal(), - //+ 650 * geometry_.GetAxisX(), - geometry_.GetAxisX(), - geometry_.GetAxisY()); - - thickness_ = offset1 - offset0; - if (thickness_ < 0) - { - thickness_ = -thickness_; - } - - return true; - } - - - bool Slice::ParseOrthancFrame(const Orthanc::DicomMap& dataset, - const std::string& instanceId, - unsigned int frame) - { - orthancInstanceId_ = instanceId; - frame_ = frame; - type_ = Type_OrthancDecodableFrame; - imageInformation_.reset(new Orthanc::DicomImageInformation(dataset)); - - if (!dataset.CopyToString(sopClassUid_, Orthanc::DICOM_TAG_SOP_CLASS_UID, false) || - sopClassUid_.empty()) - { - LOG(ERROR) << "Instance without a SOP class UID"; - return false; - } - - if (!dataset.ParseUnsignedInteger32(frameCount_, Orthanc::DICOM_TAG_NUMBER_OF_FRAMES)) - { - frameCount_ = 1; // Assume instance with one frame - } - - if (frame >= frameCount_) - { - return false; - } - - if (!dataset.ParseUnsignedInteger32(width_, Orthanc::DICOM_TAG_COLUMNS) || - !dataset.ParseUnsignedInteger32(height_, Orthanc::DICOM_TAG_ROWS)) - { - return false; - } - - thickness_ = 100.0 * std::numeric_limits::epsilon(); - - std::string tmp; - if (dataset.CopyToString(tmp, Orthanc::DICOM_TAG_SLICE_THICKNESS, false)) - { - if (!tmp.empty() && - !ParseDouble(thickness_, tmp)) - { - return false; // Syntax error - } - } - - converter_.ReadParameters(dataset); - - OrthancStone::GeometryToolbox::GetPixelSpacing(pixelSpacingX_, pixelSpacingY_, dataset); - - std::string position, orientation; - if (dataset.CopyToString(position, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT, false) && - dataset.CopyToString(orientation, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false)) - { - geometry_ = OrthancStone::CoordinateSystem3D(position, orientation); - - bool ok = true; - - switch (OrthancStone::StringToSopClassUid(sopClassUid_)) - { - case OrthancStone::SopClassUid_RTDose: - type_ = Type_OrthancRawFrame; - ok = ComputeRTDoseGeometry(dataset, frame); - break; - - default: - break; - } - - if (!ok) - { - LOG(ERROR) << "Cannot deduce the 3D location of frame " << frame - << " in instance " << instanceId << ", whose SOP class UID is: " << sopClassUid_; - return false; - } - } - - return true; - } - - - const std::string Slice::GetOrthancInstanceId() const - { - if (type_ == Type_OrthancDecodableFrame || - type_ == Type_OrthancRawFrame) - { - return orthancInstanceId_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - - - unsigned int Slice::GetFrame() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return frame_; - } - - - const OrthancStone::CoordinateSystem3D& Slice::GetGeometry() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return geometry_; - } - - - double Slice::GetThickness() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return thickness_; - } - - - double Slice::GetPixelSpacingX() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return pixelSpacingX_; - } - - - double Slice::GetPixelSpacingY() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return pixelSpacingY_; - } - - - unsigned int Slice::GetWidth() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return width_; - } - - - unsigned int Slice::GetHeight() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return height_; - } - - - const DicomFrameConverter& Slice::GetConverter() const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - return converter_; - } - - - bool Slice::ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const - { - if (type_ == Type_Invalid) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - bool opposite; - return (OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, - GetGeometry().GetNormal(), - plane.GetNormal()) && - OrthancStone::LinearAlgebra::IsNear(GetGeometry().ProjectAlongNormal(GetGeometry().GetOrigin()), - GetGeometry().ProjectAlongNormal(plane.GetOrigin()), - thickness_ / 2.0)); - } - - - void Slice::GetExtent(std::vector& points) const - { - double sx = GetPixelSpacingX(); - double sy = GetPixelSpacingY(); - double w = static_cast(GetWidth()); - double h = static_cast(GetHeight()); - - points.clear(); - points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5 * sx, -0.5 * sy)); - points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, -0.5 * sy)); - points.push_back(GetGeometry().MapSliceToWorldCoordinates(-0.5 * sx, (h - 0.5) * sy)); - points.push_back(GetGeometry().MapSliceToWorldCoordinates((w - 0.5) * sx, (h - 0.5) * sy)); - } - - - const Orthanc::DicomImageInformation& Slice::GetImageInformation() const - { - if (imageInformation_.get() == NULL) - { - // Only available if constructing the "Slice" object with a DICOM map - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - return *imageInformation_; - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/Slice.h --- a/Framework/Toolbox/Slice.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "CoordinateSystem3D.h" -#include "DicomFrameConverter.h" - -#include -#include - -namespace Deprecated -{ - // TODO - Remove this class - class Slice : - public Orthanc::IDynamicObject /* to be used as a payload of SlicesSorter */ - { - private: - enum Type - { - Type_Invalid, - Type_Standalone, - Type_OrthancDecodableFrame, - Type_OrthancRawFrame - // TODO A slice could come from some DICOM file (URL) - }; - - bool ComputeRTDoseGeometry(const Orthanc::DicomMap& dataset, - unsigned int frame); - - Type type_; - std::string orthancInstanceId_; - std::string sopClassUid_; - unsigned int frame_; - unsigned int frameCount_; // TODO : Redundant with "imageInformation_" - OrthancStone::CoordinateSystem3D geometry_; - double pixelSpacingX_; - double pixelSpacingY_; - double thickness_; - unsigned int width_; // TODO : Redundant with "imageInformation_" - unsigned int height_; // TODO : Redundant with "imageInformation_" - DicomFrameConverter converter_; // TODO : Partially redundant with "imageInformation_" - - std::auto_ptr imageInformation_; - - public: - Slice() : - type_(Type_Invalid) - { - } - - - // this constructor is used to reference, i.e, a slice that is being loaded - Slice(const std::string& orthancInstanceId, - unsigned int frame) : - type_(Type_Invalid), - orthancInstanceId_(orthancInstanceId), - frame_(frame) - { - } - - // TODO Is this constructor the best way to go to tackle missing - // layers within SliceViewerWidget? - Slice(const OrthancStone::CoordinateSystem3D& plane, - double thickness) : - type_(Type_Standalone), - frame_(0), - frameCount_(0), - geometry_(plane), - pixelSpacingX_(1), - pixelSpacingY_(1), - thickness_(thickness), - width_(0), - height_(0) - { - } - - Slice(const OrthancStone::CoordinateSystem3D& plane, - double pixelSpacingX, - double pixelSpacingY, - double thickness, - unsigned int width, - unsigned int height, - const DicomFrameConverter& converter) : - type_(Type_Standalone), - frameCount_(1), - geometry_(plane), - pixelSpacingX_(pixelSpacingX), - pixelSpacingY_(pixelSpacingY), - thickness_(thickness), - width_(width), - height_(height), - converter_(converter) - { - } - - bool IsValid() const - { - return type_ != Type_Invalid; - } - - bool ParseOrthancFrame(const Orthanc::DicomMap& dataset, - const std::string& instanceId, - unsigned int frame); - - bool HasOrthancDecoding() const - { - return type_ == Type_OrthancDecodableFrame; - } - - const std::string GetOrthancInstanceId() const; - - unsigned int GetFrame() const; - - const OrthancStone::CoordinateSystem3D& GetGeometry() const; - - double GetThickness() const; - - double GetPixelSpacingX() const; - - double GetPixelSpacingY() const; - - unsigned int GetWidth() const; - - unsigned int GetHeight() const; - - const DicomFrameConverter& GetConverter() const; - - bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const; - - void GetExtent(std::vector& points) const; - - const Orthanc::DicomImageInformation& GetImageInformation() const; - - Slice* Clone() const; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/ViewportGeometry.cpp --- a/Framework/Toolbox/ViewportGeometry.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,217 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "ViewportGeometry.h" - -#include -#include - -#include - -namespace Deprecated -{ - void ViewportGeometry::ComputeTransform() - { - // The following lines must be read in reverse order! - cairo_matrix_t tmp; - - // Bring the center of the scene to the center of the view - cairo_matrix_init_translate(&transform_, - panX_ + static_cast(width_) / 2.0, - panY_ + static_cast(height_) / 2.0); - - // Apply the zoom around (0,0) - cairo_matrix_init_scale(&tmp, zoom_, zoom_); - cairo_matrix_multiply(&transform_, &tmp, &transform_); - - // Bring the center of the scene to (0,0) - cairo_matrix_init_translate(&tmp, - -(sceneExtent_.GetX1() + sceneExtent_.GetX2()) / 2.0, - -(sceneExtent_.GetY1() + sceneExtent_.GetY2()) / 2.0); - cairo_matrix_multiply(&transform_, &tmp, &transform_); - } - - - ViewportGeometry::ViewportGeometry() - { - width_ = 0; - height_ = 0; - - zoom_ = 1; - panX_ = 0; - panY_ = 0; - - ComputeTransform(); - } - - - void ViewportGeometry::SetDisplaySize(unsigned int width, - unsigned int height) - { - if (width_ != width || - height_ != height) - { - LOG(INFO) << "New display size: " << width << "x" << height; - - width_ = width; - height_ = height; - - ComputeTransform(); - } - } - - - void ViewportGeometry::SetSceneExtent(const OrthancStone::Extent2D& extent) - { - LOG(INFO) << "New scene extent: (" - << extent.GetX1() << "," << extent.GetY1() << ") => (" - << extent.GetX2() << "," << extent.GetY2() << ")"; - - sceneExtent_ = extent; - ComputeTransform(); - } - - - void ViewportGeometry::MapDisplayToScene(double& sceneX /* out */, - double& sceneY /* out */, - double x, - double y) const - { - cairo_matrix_t transform = transform_; - - if (cairo_matrix_invert(&transform) != CAIRO_STATUS_SUCCESS) - { - LOG(ERROR) << "Cannot invert singular matrix"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - sceneX = x; - sceneY = y; - cairo_matrix_transform_point(&transform, &sceneX, &sceneY); - } - - - void ViewportGeometry::MapSceneToDisplay(int& displayX /* out */, - int& displayY /* out */, - double x, - double y) const - { - cairo_matrix_transform_point(&transform_, &x, &y); - - displayX = static_cast(boost::math::iround(x)); - displayY = static_cast(boost::math::iround(y)); - } - - - void ViewportGeometry::MapPixelCenterToScene(std::vector& sceneTouches /* out */, - const std::vector& displayTouches) const - { - double sceneX, sceneY; - sceneTouches.clear(); - for (size_t t = 0; t < displayTouches.size(); t++) - { - MapPixelCenterToScene( - sceneX, - sceneY, - static_cast(displayTouches[t].x), - static_cast(displayTouches[t].y)); - - sceneTouches.push_back(Touch((float)sceneX, (float)sceneY)); - } - } - - void ViewportGeometry::MapPixelCenterToScene(double& sceneX, - double& sceneY, - int x, - int y) const - { - // Take the center of the pixel - MapDisplayToScene(sceneX, sceneY, - static_cast(x) + 0.5, - static_cast(y) + 0.5); - } - - - void ViewportGeometry::FitContent() - { - if (width_ > 0 && - height_ > 0 && - !sceneExtent_.IsEmpty()) - { - double zoomX = static_cast(width_) / (sceneExtent_.GetX2() - sceneExtent_.GetX1()); - double zoomY = static_cast(height_) / (sceneExtent_.GetY2() - sceneExtent_.GetY1()); - zoom_ = zoomX < zoomY ? zoomX : zoomY; - - panX_ = 0; - panY_ = 0; - - ComputeTransform(); - } - } - - - void ViewportGeometry::ApplyTransform(OrthancStone::CairoContext& context) const - { - cairo_set_matrix(context.GetObject(), &transform_); - } - - - void ViewportGeometry::GetPan(double& x, - double& y) const - { - x = panX_; - y = panY_; - } - - - void ViewportGeometry::SetPan(double x, - double y) - { - panX_ = x; - panY_ = y; - ComputeTransform(); - } - - - void ViewportGeometry::SetZoom(double zoom) - { - zoom_ = zoom; - ComputeTransform(); - } - - - OrthancStone::Matrix ViewportGeometry::GetMatrix() const - { - OrthancStone::Matrix m(3, 3); - - m(0, 0) = transform_.xx; - m(0, 1) = transform_.xy; - m(0, 2) = transform_.x0; - m(1, 0) = transform_.yx; - m(1, 1) = transform_.yy; - m(1, 2) = transform_.y0; - m(2, 0) = 0; - m(2, 1) = 0; - m(2, 2) = 1; - - return m; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Toolbox/ViewportGeometry.h --- a/Framework/Toolbox/ViewportGeometry.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Viewport/CairoContext.h" -#include "Extent2D.h" -#include "LinearAlgebra.h" -#include "../Viewport/IMouseTracker.h" // to include "Touch" definition - -namespace Deprecated -{ - class ViewportGeometry - { - private: - // Extent of the scene (in world units) - OrthancStone::Extent2D sceneExtent_; - - // Size of the display (in pixels) - unsigned int width_; - unsigned int height_; - - // Zoom/pan - double zoom_; - double panX_; // In pixels (display units) - double panY_; - - cairo_matrix_t transform_; // Scene-to-display transformation - - void ComputeTransform(); - - public: - ViewportGeometry(); - - void SetDisplaySize(unsigned int width, - unsigned int height); - - void SetSceneExtent(const OrthancStone::Extent2D& extent); - - const OrthancStone::Extent2D& GetSceneExtent() const - { - return sceneExtent_; - } - - void MapDisplayToScene(double& sceneX /* out */, - double& sceneY /* out */, - double x, - double y) const; - - void MapPixelCenterToScene(double& sceneX /* out */, - double& sceneY /* out */, - int x, - int y) const; - - void MapPixelCenterToScene(std::vector& sceneTouches /* out */, - const std::vector& displayTouches) const; - - void MapSceneToDisplay(int& displayX /* out */, - int& displayY /* out */, - double x, - double y) const; - - unsigned int GetDisplayWidth() const - { - return width_; - } - - unsigned int GetDisplayHeight() const - { - return height_; - } - - double GetZoom() const - { - return zoom_; - } - - void FitContent(); - - void ApplyTransform(OrthancStone::CairoContext& context) const; - - void GetPan(double& x, - double& y) const; - - void SetPan(double x, - double y); - - void SetZoom(double zoom); - - OrthancStone::Matrix GetMatrix() const; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Viewport/IMouseTracker.h --- a/Framework/Viewport/IMouseTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "CairoSurface.h" -#include - -namespace Deprecated -{ - struct Touch - { - float x; - float y; - - Touch(float x, float y) - : x(x), - y(y) - { - } - Touch() - : x(0.0f), - y(0.0f) - { - } - }; - - - // this is tracking a mouse in screen coordinates/pixels unlike - // the IWorldSceneMouseTracker that is tracking a mouse - // in scene coordinates/mm. - class IMouseTracker : public boost::noncopyable - { - public: - virtual ~IMouseTracker() - { - } - - virtual void Render(Orthanc::ImageAccessor& surface) = 0; - - virtual void MouseUp() = 0; - - // Returns "true" iff. the background scene must be repainted - virtual void MouseMove(int x, - int y, - const std::vector& displayTouches) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Viewport/IStatusBar.h --- a/Framework/Viewport/IStatusBar.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include -#include - -namespace Deprecated -{ - class IStatusBar : public boost::noncopyable - { - public: - virtual ~IStatusBar() - { - } - - virtual void ClearMessage() = 0; - - virtual void SetMessage(const std::string& message) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Viewport/IViewport.h --- a/Framework/Viewport/IViewport.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IStatusBar.h" -#include "../StoneEnumerations.h" -#include "../Messages/IObservable.h" - -#include -#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition - -namespace Deprecated -{ - class IWidget; // Forward declaration - - class IViewport : public OrthancStone::IObservable - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ViewportChangedMessage, IViewport); - - IViewport(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - - virtual ~IViewport() - { - } - - virtual void FitContent() = 0; - - virtual void SetStatusBar(IStatusBar& statusBar) = 0; - - virtual void SetSize(unsigned int width, - unsigned int height) = 0; - - // The function returns "true" iff. a new frame was rendered - virtual bool Render(Orthanc::ImageAccessor& surface) = 0; - - virtual void MouseDown(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) = 0; - - virtual void MouseUp() = 0; - - virtual void MouseMove(int x, - int y, - const std::vector& displayTouches) = 0; - - virtual void MouseEnter() = 0; - - virtual void MouseLeave() = 0; - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) = 0; - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) = 0; - - virtual bool HasAnimation() = 0; - - virtual void DoAnimation() = 0; - - // Should only be called from IWidget - // TODO Why should this be virtual? - virtual void NotifyContentChanged() - { - BroadcastMessage(ViewportChangedMessage(*this)); - } - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Viewport/WidgetViewport.cpp --- a/Framework/Viewport/WidgetViewport.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,289 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "WidgetViewport.h" - -#include -#include - -namespace Deprecated -{ - WidgetViewport::WidgetViewport(OrthancStone::MessageBroker& broker) : - IViewport(broker), - statusBar_(NULL), - isMouseOver_(false), - lastMouseX_(0), - lastMouseY_(0), - backgroundChanged_(false) - { - } - - - void WidgetViewport::FitContent() - { - if (centralWidget_.get() != NULL) - { - centralWidget_->FitContent(); - } - } - - - void WidgetViewport::SetStatusBar(IStatusBar& statusBar) - { - statusBar_ = &statusBar; - - if (centralWidget_.get() != NULL) - { - centralWidget_->SetStatusBar(statusBar); - } - } - - - IWidget& WidgetViewport::SetCentralWidget(IWidget* widget) - { - if (widget == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - mouseTracker_.reset(NULL); - - centralWidget_.reset(widget); - centralWidget_->SetViewport(*this); - - if (statusBar_ != NULL) - { - centralWidget_->SetStatusBar(*statusBar_); - } - - NotifyBackgroundChanged(); - - return *widget; - } - - - void WidgetViewport::NotifyBackgroundChanged() - { - backgroundChanged_ = true; - NotifyContentChanged(); - } - - - void WidgetViewport::SetSize(unsigned int width, - unsigned int height) - { - background_.SetSize(width, height, false /* no alpha */); - - if (centralWidget_.get() != NULL) - { - centralWidget_->SetSize(width, height); - } - - NotifyBackgroundChanged(); - } - - - bool WidgetViewport::Render(Orthanc::ImageAccessor& surface) - { - if (centralWidget_.get() == NULL) - { - return false; - } - - Orthanc::ImageAccessor background; - background_.GetWriteableAccessor(background); - - if (backgroundChanged_ && - !centralWidget_->Render(background)) - { - return false; - } - - if (background.GetWidth() != surface.GetWidth() || - background.GetHeight() != surface.GetHeight()) - { - return false; - } - - Orthanc::ImageProcessing::Convert(surface, background); - - if (mouseTracker_.get() != NULL) - { - mouseTracker_->Render(surface); - } - else if (isMouseOver_) - { - centralWidget_->RenderMouseOver(surface, lastMouseX_, lastMouseY_); - } - - return true; - } - - void WidgetViewport::TouchStart(const std::vector& displayTouches) - { - MouseDown(OrthancStone::MouseButton_Left, (int)displayTouches[0].x, (int)displayTouches[0].y, OrthancStone::KeyboardModifiers_None, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates - } - - void WidgetViewport::TouchMove(const std::vector& displayTouches) - { - MouseMove((int)displayTouches[0].x, (int)displayTouches[0].y, displayTouches); // one touch is equivalent to a mouse tracker without left button -> set the mouse coordinates to the first touch coordinates - } - - void WidgetViewport::TouchEnd(const std::vector& displayTouches) - { - // note: TouchEnd is not triggered when a single touch gesture ends (it is only triggered when - // going from 2 touches to 1 touch, ...) - MouseUp(); - } - - void WidgetViewport::MouseDown(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& displayTouches - ) - { - lastMouseX_ = x; - lastMouseY_ = y; - - if (centralWidget_.get() != NULL) - { - mouseTracker_.reset(centralWidget_->CreateMouseTracker(button, x, y, modifiers, displayTouches)); - } - else - { - mouseTracker_.reset(NULL); - } - - NotifyContentChanged(); - } - - - void WidgetViewport::MouseUp() - { - if (mouseTracker_.get() != NULL) - { - mouseTracker_->MouseUp(); - mouseTracker_.reset(NULL); - NotifyContentChanged(); - } - } - - - void WidgetViewport::MouseMove(int x, - int y, - const std::vector& displayTouches) - { - if (centralWidget_.get() == NULL) - { - return; - } - - lastMouseX_ = x; - lastMouseY_ = y; - - bool repaint = false; - - if (mouseTracker_.get() != NULL) - { - mouseTracker_->MouseMove(x, y, displayTouches); - repaint = true; - } - else - { - repaint = centralWidget_->HasRenderMouseOver(); - } - - if (repaint) - { - // The scene must be repainted, notify the observers - NotifyContentChanged(); - } - } - - - void WidgetViewport::MouseEnter() - { - isMouseOver_ = true; - NotifyContentChanged(); - } - - - void WidgetViewport::MouseLeave() - { - isMouseOver_ = false; - - if (mouseTracker_.get() != NULL) - { - mouseTracker_->MouseUp(); - mouseTracker_.reset(NULL); - } - - NotifyContentChanged(); - } - - - void WidgetViewport::MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - if (centralWidget_.get() != NULL && - mouseTracker_.get() == NULL) - { - centralWidget_->MouseWheel(direction, x, y, modifiers); - } - } - - - void WidgetViewport::KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) - { - if (centralWidget_.get() != NULL && - mouseTracker_.get() == NULL) - { - centralWidget_->KeyPressed(key, keyChar, modifiers); - } - } - - - bool WidgetViewport::HasAnimation() - { - if (centralWidget_.get() != NULL) - { - return centralWidget_->HasAnimation(); - } - else - { - return false; - } - } - - - void WidgetViewport::DoAnimation() - { - if (centralWidget_.get() != NULL) - { - centralWidget_->DoAnimation(); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Viewport/WidgetViewport.h --- a/Framework/Viewport/WidgetViewport.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IViewport.h" -#include "../Widgets/IWidget.h" - -#include - -namespace Deprecated -{ - class WidgetViewport : public IViewport - { - private: - std::auto_ptr centralWidget_; - IStatusBar* statusBar_; - std::auto_ptr mouseTracker_; - bool isMouseOver_; - int lastMouseX_; - int lastMouseY_; - OrthancStone::CairoSurface background_; - bool backgroundChanged_; - - public: - WidgetViewport(OrthancStone::MessageBroker& broker); - - virtual void FitContent(); - - virtual void SetStatusBar(IStatusBar& statusBar); - - IWidget& SetCentralWidget(IWidget* widget); // Takes ownership - - virtual void NotifyBackgroundChanged(); - - virtual void SetSize(unsigned int width, - unsigned int height); - - virtual bool Render(Orthanc::ImageAccessor& surface); - - virtual void MouseDown(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& displayTouches); - - virtual void MouseUp(); - - virtual void MouseMove(int x, - int y, - const std::vector& displayTouches); - - virtual void MouseEnter(); - - virtual void MouseLeave(); - - virtual void TouchStart(const std::vector& touches); - - virtual void TouchMove(const std::vector& touches); - - virtual void TouchEnd(const std::vector& touches); - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers); - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers); - - virtual bool HasAnimation(); - - virtual void DoAnimation(); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Volumes/ISlicedVolume.h --- a/Framework/Volumes/ISlicedVolume.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Messages/IObservable.h" -#include "../Toolbox/Slice.h" - -namespace Deprecated -{ - class ISlicedVolume : public OrthancStone::IObservable - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, ISlicedVolume); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, ISlicedVolume); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, ISlicedVolume); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeReadyMessage, ISlicedVolume); - - - class SliceContentChangedMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - size_t sliceIndex_; - const Slice& slice_; - - public: - SliceContentChangedMessage(ISlicedVolume& origin, - size_t sliceIndex, - const Slice& slice) : - OriginMessage(origin), - sliceIndex_(sliceIndex), - slice_(slice) - { - } - - size_t GetSliceIndex() const - { - return sliceIndex_; - } - - const Slice& GetSlice() const - { - return slice_; - } - }; - - - ISlicedVolume(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - - virtual size_t GetSliceCount() const = 0; - - virtual const Slice& GetSlice(size_t slice) const = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Volumes/IVolumeLoader.h --- a/Framework/Volumes/IVolumeLoader.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Messages/IObservable.h" - -namespace Deprecated -{ - class IVolumeLoader : public OrthancStone::IObservable - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryReadyMessage, IVolumeLoader); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryErrorMessage, IVolumeLoader); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, IVolumeLoader); - - IVolumeLoader(OrthancStone::MessageBroker& broker) : - IObservable(broker) - { - } - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Volumes/ImageBuffer3D.h --- a/Framework/Volumes/ImageBuffer3D.h Tue May 21 13:27:54 2019 +0200 +++ b/Framework/Volumes/ImageBuffer3D.h Tue May 21 14:27:35 2019 +0200 @@ -21,11 +21,11 @@ #pragma once +#include "../Deprecated/Layers/RenderStyle.h" +#include "../Deprecated/Toolbox/DicomFrameConverter.h" #include "../StoneEnumerations.h" -#include "../Layers/RenderStyle.h" +#include "../Toolbox/ParallelSlices.h" #include "../Toolbox/VolumeImageGeometry.h" -#include "../Toolbox/DicomFrameConverter.h" -#include "../Toolbox/ParallelSlices.h" #include diff -r 529189f399ec -r c35e98d22764 Framework/Volumes/StructureSetLoader.cpp --- a/Framework/Volumes/StructureSetLoader.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "StructureSetLoader.h" - -#include "../Toolbox/MessagingToolbox.h" - -#include - -namespace Deprecated -{ - StructureSetLoader::StructureSetLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc) : - IVolumeLoader(broker), - IObserver(broker), - orthanc_(orthanc) - { - } - - - void StructureSetLoader::OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message) - { - OrthancPlugins::FullOrthancDataset dataset(message.GetJson()); - - Orthanc::DicomMap slice; - OrthancStone::MessagingToolbox::ConvertDataset(slice, dataset); - structureSet_->AddReferencedSlice(slice); - - BroadcastMessage(ContentChangedMessage(*this)); - } - - - void StructureSetLoader::OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message) - { - OrthancPlugins::FullOrthancDataset dataset(message.GetJson()); - structureSet_.reset(new OrthancStone::DicomStructureSet(dataset)); - - std::set instances; - structureSet_->GetReferencedInstances(instances); - - for (std::set::const_iterator it = instances.begin(); - it != instances.end(); ++it) - { - orthanc_.PostBinaryAsyncExpectJson("/tools/lookup", *it, - new OrthancStone::Callable(*this, &StructureSetLoader::OnLookupCompleted)); - } - - BroadcastMessage(GeometryReadyMessage(*this)); - } - - - void StructureSetLoader::OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message) - { - const Json::Value& lookup = message.GetJson(); - - if (lookup.type() != Json::arrayValue || - lookup.size() != 1 || - !lookup[0].isMember("Type") || - !lookup[0].isMember("Path") || - lookup[0]["Type"].type() != Json::stringValue || - lookup[0]["ID"].type() != Json::stringValue || - lookup[0]["Type"].asString() != "Instance") - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - - const std::string& instance = lookup[0]["ID"].asString(); - orthanc_.GetJsonAsync("/instances/" + instance + "/tags", - new OrthancStone::Callable(*this, &StructureSetLoader::OnReferencedSliceLoaded)); - } - - - void StructureSetLoader::ScheduleLoadInstance(const std::string& instance) - { - if (structureSet_.get() != NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - orthanc_.GetJsonAsync("/instances/" + instance + "/tags?ignore-length=3006-0050", - new OrthancStone::Callable(*this, &StructureSetLoader::OnStructureSetLoaded)); - } - } - - - OrthancStone::DicomStructureSet& StructureSetLoader::GetStructureSet() - { - if (structureSet_.get() == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - return *structureSet_; - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Volumes/StructureSetLoader.h --- a/Framework/Volumes/StructureSetLoader.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Toolbox/DicomStructureSet.h" -#include "../Toolbox/OrthancApiClient.h" -#include "IVolumeLoader.h" - -namespace Deprecated -{ - class StructureSetLoader : - public IVolumeLoader, - public OrthancStone::IObserver - { - private: - OrthancApiClient& orthanc_; - std::auto_ptr structureSet_; - - void OnReferencedSliceLoaded(const OrthancApiClient::JsonResponseReadyMessage& message); - - void OnStructureSetLoaded(const OrthancApiClient::JsonResponseReadyMessage& message); - - void OnLookupCompleted(const OrthancApiClient::JsonResponseReadyMessage& message); - - public: - StructureSetLoader(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc); - - void ScheduleLoadInstance(const std::string& instance); - - bool HasStructureSet() const - { - return structureSet_.get() != NULL; - } - - OrthancStone::DicomStructureSet& GetStructureSet(); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/CairoWidget.cpp --- a/Framework/Widgets/CairoWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,101 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "CairoWidget.h" - -#include -#include - -namespace Deprecated -{ - static bool IsAligned(const Orthanc::ImageAccessor& target) - { - // TODO - return true; - } - - CairoWidget::CairoWidget(const std::string& name) : - WidgetBase(name) - { - } - - void CairoWidget::SetSize(unsigned int width, - unsigned int height) - { - surface_.SetSize(width, height, false /* no alpha */); - } - - - bool CairoWidget::Render(Orthanc::ImageAccessor& target) - { - // Don't call the base class here, as - // "ClearBackgroundCairo()" is a faster alternative - - if (IsAligned(target)) - { - OrthancStone::CairoSurface surface(target, false /* no alpha */); - OrthancStone::CairoContext context(surface); - ClearBackgroundCairo(context); - return RenderCairo(context); - } - else - { - OrthancStone::CairoContext context(surface_); - ClearBackgroundCairo(context); - - if (RenderCairo(context)) - { - Orthanc::ImageAccessor surface; - surface_.GetReadOnlyAccessor(surface); - Orthanc::ImageProcessing::Copy(target, surface); - return true; - } - else - { - return false; - } - } - } - - - void CairoWidget::RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y) - { - if (IsAligned(target)) - { - OrthancStone::CairoSurface surface(target, false /* no alpha */); - OrthancStone::CairoContext context(surface); - RenderMouseOverCairo(context, x, y); - } - else - { - Orthanc::ImageAccessor accessor; - surface_.GetWriteableAccessor(accessor); - Orthanc::ImageProcessing::Copy(accessor, target); - - OrthancStone::CairoContext context(surface_); - RenderMouseOverCairo(context, x, y); - - Orthanc::ImageProcessing::Copy(target, accessor); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/CairoWidget.h --- a/Framework/Widgets/CairoWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WidgetBase.h" - -namespace Deprecated -{ - class CairoWidget : public WidgetBase - { - private: - OrthancStone::CairoSurface surface_; - - protected: - virtual bool RenderCairo(OrthancStone::CairoContext& context) = 0; - - virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, - int x, - int y) = 0; - - public: - CairoWidget(const std::string& name); - - virtual void SetSize(unsigned int width, - unsigned int height); - - virtual bool Render(Orthanc::ImageAccessor& target); - - virtual void RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/EmptyWidget.cpp --- a/Framework/Widgets/EmptyWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "EmptyWidget.h" - -#include -#include - -namespace Deprecated -{ - bool EmptyWidget::Render(Orthanc::ImageAccessor& surface) - { - // Note: This call is slow - Orthanc::ImageProcessing::Set(surface, red_, green_, blue_, 255); - return true; - } - - - void EmptyWidget::DoAnimation() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/EmptyWidget.h --- a/Framework/Widgets/EmptyWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,116 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IWidget.h" - -namespace Deprecated -{ - /** - * This is a test widget that simply fills its surface with an - * uniform color. - **/ - class EmptyWidget : public IWidget - { - private: - uint8_t red_; - uint8_t green_; - uint8_t blue_; - - public: - EmptyWidget(uint8_t red, - uint8_t green, - uint8_t blue) : - red_(red), - green_(green), - blue_(blue) - { - } - - virtual void FitContent() - { - } - - virtual void SetParent(IWidget& widget) - { - } - - virtual void SetViewport(WidgetViewport& viewport) - { - } - - virtual void NotifyContentChanged() - { - } - - virtual void SetStatusBar(IStatusBar& statusBar) - { - } - - virtual void SetSize(unsigned int width, - unsigned int height) - { - } - - virtual bool Render(Orthanc::ImageAccessor& surface); - - virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) - { - return NULL; - } - - virtual void RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y) - { - } - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - } - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) - { - } - - virtual bool HasAnimation() const - { - return false; - } - - virtual void DoAnimation(); - - virtual bool HasRenderMouseOver() - { - return false; - } - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/IWidget.h --- a/Framework/Widgets/IWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../StoneEnumerations.h" -#include "../Viewport/IMouseTracker.h" -#include "../Viewport/IStatusBar.h" - -namespace Deprecated -{ - class WidgetViewport; // Forward declaration - - class IWidget : public boost::noncopyable - { - public: - virtual ~IWidget() - { - } - - virtual void FitContent() = 0; - - virtual void SetParent(IWidget& parent) = 0; - - virtual void SetViewport(WidgetViewport& viewport) = 0; - - virtual void SetStatusBar(IStatusBar& statusBar) = 0; - - virtual void SetSize(unsigned int width, - unsigned int height) = 0; - - virtual bool Render(Orthanc::ImageAccessor& surface) = 0; - - virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) = 0; - - virtual void RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y) = 0; - - virtual bool HasRenderMouseOver() = 0; - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) = 0; - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) = 0; - - virtual bool HasAnimation() const = 0; - - virtual void DoAnimation() = 0; - - // Subclasses can call this method to signal the display of the - // widget must be refreshed - virtual void NotifyContentChanged() = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/IWorldSceneInteractor.h --- a/Framework/Widgets/IWorldSceneInteractor.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IWorldSceneMouseTracker.h" - -#include "../Toolbox/ViewportGeometry.h" -#include "../StoneEnumerations.h" -#include "../Viewport/IStatusBar.h" - -namespace Deprecated -{ - class WorldSceneWidget; - - class IWorldSceneInteractor : public boost::noncopyable - { - public: - virtual ~IWorldSceneInteractor() - { - } - - virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, - const ViewportGeometry& view, - OrthancStone::MouseButton button, - OrthancStone::KeyboardModifiers modifiers, - int viewportX, - int viewportY, - double x, - double y, - IStatusBar* statusBar, - const std::vector& touches) = 0; - - virtual void MouseOver(OrthancStone::CairoContext& context, - WorldSceneWidget& widget, - const ViewportGeometry& view, - double x, - double y, - IStatusBar* statusBar) = 0; - - virtual void MouseWheel(WorldSceneWidget& widget, - OrthancStone::MouseWheelDirection direction, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) = 0; - - virtual void KeyPressed(WorldSceneWidget& widget, - OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/IWorldSceneMouseTracker.h --- a/Framework/Widgets/IWorldSceneMouseTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "../Viewport/CairoContext.h" -#include "../Viewport/IMouseTracker.h" // only to get the "Touch" definition - -namespace Deprecated -{ - - // this is tracking a mouse in scene coordinates/mm unlike - // the IMouseTracker that is tracking a mouse - // in screen coordinates/pixels. - class IWorldSceneMouseTracker : public boost::noncopyable - { - public: - virtual ~IWorldSceneMouseTracker() - { - } - - virtual bool HasRender() const = 0; - - virtual void Render(OrthancStone::CairoContext& context, - double zoom) = 0; - - virtual void MouseUp() = 0; - - virtual void MouseMove(int displayX, - int displayY, - double sceneX, - double sceneY, - const std::vector& displayTouches, - const std::vector& sceneTouches) = 0; - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/LayoutWidget.cpp --- a/Framework/Widgets/LayoutWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,503 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "LayoutWidget.h" - -#include -#include - -#include - -namespace Deprecated -{ - class LayoutWidget::LayoutMouseTracker : public IMouseTracker - { - private: - std::auto_ptr tracker_; - int left_; - int top_; - unsigned int width_; - unsigned int height_; - - public: - LayoutMouseTracker(IMouseTracker* tracker, - int left, - int top, - unsigned int width, - unsigned int height) : - tracker_(tracker), - left_(left), - top_(top), - width_(width), - height_(height) - { - if (tracker == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - virtual void Render(Orthanc::ImageAccessor& surface) - { - Orthanc::ImageAccessor accessor; - surface.GetRegion(accessor, left_, top_, width_, height_); - tracker_->Render(accessor); - } - - virtual void MouseUp() - { - tracker_->MouseUp(); - } - - virtual void MouseMove(int x, - int y, - const std::vector& displayTouches) - { - std::vector relativeTouches; - for (size_t t = 0; t < displayTouches.size(); t++) - { - relativeTouches.push_back(Touch(displayTouches[t].x - left_, displayTouches[t].y - top_)); - } - - tracker_->MouseMove(x - left_, y - top_, relativeTouches); - } - }; - - - class LayoutWidget::ChildWidget : public boost::noncopyable - { - private: - std::auto_ptr widget_; - int left_; - int top_; - unsigned int width_; - unsigned int height_; - - public: - ChildWidget(IWidget* widget) : - widget_(widget) - { - assert(widget != NULL); - SetEmpty(); - } - - void DoAnimation() - { - if (widget_->HasAnimation()) - { - widget_->DoAnimation(); - } - } - - IWidget& GetWidget() const - { - return *widget_; - } - - void SetRectangle(unsigned int left, - unsigned int top, - unsigned int width, - unsigned int height) - { - left_ = left; - top_ = top; - width_ = width; - height_ = height; - - widget_->SetSize(width, height); - } - - void SetEmpty() - { - SetRectangle(0, 0, 0, 0); - } - - bool Contains(int x, - int y) const - { - return (x >= left_ && - y >= top_ && - x < left_ + static_cast(width_) && - y < top_ + static_cast(height_)); - } - - bool Render(Orthanc::ImageAccessor& target) - { - if (width_ == 0 || - height_ == 0) - { - return true; - } - else - { - Orthanc::ImageAccessor accessor; - target.GetRegion(accessor, left_, top_, width_, height_); - return widget_->Render(accessor); - } - } - - IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) - { - if (Contains(x, y)) - { - IMouseTracker* tracker = widget_->CreateMouseTracker(button, - x - left_, - y - top_, - modifiers, - touches); - if (tracker) - { - return new LayoutMouseTracker(tracker, left_, top_, width_, height_); - } - } - - return NULL; - } - - void RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y) - { - if (Contains(x, y)) - { - Orthanc::ImageAccessor accessor; - target.GetRegion(accessor, left_, top_, width_, height_); - - widget_->RenderMouseOver(accessor, x - left_, y - top_); - } - } - - void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - if (Contains(x, y)) - { - widget_->MouseWheel(direction, x - left_, y - top_, modifiers); - } - } - - bool HasRenderMouseOver() - { - return widget_->HasRenderMouseOver(); - } - }; - - - void LayoutWidget::ComputeChildrenExtents() - { - if (children_.size() == 0) - { - return; - } - - float internal = static_cast(paddingInternal_); - - if (width_ <= paddingLeft_ + paddingRight_ || - height_ <= paddingTop_ + paddingBottom_) - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->SetEmpty(); - } - } - else if (isHorizontal_) - { - unsigned int padding = paddingLeft_ + paddingRight_ + (static_cast(children_.size()) - 1) * paddingInternal_; - float childWidth = ((static_cast(width_) - static_cast(padding)) / - static_cast(children_.size())); - - for (size_t i = 0; i < children_.size(); i++) - { - float left = static_cast(paddingLeft_) + static_cast(i) * (childWidth + internal); - float right = left + childWidth; - - if (left >= right) - { - children_[i]->SetEmpty(); - } - else - { - children_[i]->SetRectangle(static_cast(left), - paddingTop_, - boost::math::iround(right - left), - height_ - paddingTop_ - paddingBottom_); - } - } - } - else - { - unsigned int padding = paddingTop_ + paddingBottom_ + (static_cast(children_.size()) - 1) * paddingInternal_; - float childHeight = ((static_cast(height_) - static_cast(padding)) / - static_cast(children_.size())); - - for (size_t i = 0; i < children_.size(); i++) - { - float top = static_cast(paddingTop_) + static_cast(i) * (childHeight + internal); - float bottom = top + childHeight; - - if (top >= bottom) - { - children_[i]->SetEmpty(); - } - else - { - children_[i]->SetRectangle(paddingTop_, - static_cast(top), - width_ - paddingLeft_ - paddingRight_, - boost::math::iround(bottom - top)); - } - } - } - - NotifyContentChanged(*this); - } - - - LayoutWidget::LayoutWidget(const std::string& name) : - WidgetBase(name), - isHorizontal_(true), - width_(0), - height_(0), - paddingLeft_(0), - paddingTop_(0), - paddingRight_(0), - paddingBottom_(0), - paddingInternal_(0) - { - } - - - LayoutWidget::~LayoutWidget() - { - for (size_t i = 0; i < children_.size(); i++) - { - delete children_[i]; - } - } - - - void LayoutWidget::FitContent() - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->GetWidget().FitContent(); - } - } - - - void LayoutWidget::NotifyContentChanged(const IWidget& widget) - { - // One of the children has changed - WidgetBase::NotifyContentChanged(); - } - - - void LayoutWidget::SetHorizontal() - { - isHorizontal_ = true; - ComputeChildrenExtents(); - } - - - void LayoutWidget::SetVertical() - { - isHorizontal_ = false; - ComputeChildrenExtents(); - } - - - void LayoutWidget::SetPadding(unsigned int left, - unsigned int top, - unsigned int right, - unsigned int bottom, - unsigned int spacing) - { - paddingLeft_ = left; - paddingTop_ = top; - paddingRight_ = right; - paddingBottom_ = bottom; - paddingInternal_ = spacing; - } - - - void LayoutWidget::SetPadding(unsigned int padding) - { - paddingLeft_ = padding; - paddingTop_ = padding; - paddingRight_ = padding; - paddingBottom_ = padding; - paddingInternal_ = padding; - } - - - IWidget& LayoutWidget::AddWidget(IWidget* widget) // Takes ownership - { - if (widget == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - if (GetStatusBar() != NULL) - { - widget->SetStatusBar(*GetStatusBar()); - } - - children_.push_back(new ChildWidget(widget)); - widget->SetParent(*this); - - ComputeChildrenExtents(); - - if (widget->HasAnimation()) - { - hasAnimation_ = true; - } - - return *widget; - } - - - void LayoutWidget::SetStatusBar(IStatusBar& statusBar) - { - WidgetBase::SetStatusBar(statusBar); - - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->GetWidget().SetStatusBar(statusBar); - } - } - - - void LayoutWidget::SetSize(unsigned int width, - unsigned int height) - { - width_ = width; - height_ = height; - ComputeChildrenExtents(); - } - - - bool LayoutWidget::Render(Orthanc::ImageAccessor& surface) - { - if (!WidgetBase::Render(surface)) - { - return false; - } - - for (size_t i = 0; i < children_.size(); i++) - { - if (!children_[i]->Render(surface)) - { - return false; - } - } - - return true; - } - - - IMouseTracker* LayoutWidget::CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) - { - for (size_t i = 0; i < children_.size(); i++) - { - IMouseTracker* tracker = children_[i]->CreateMouseTracker(button, x, y, modifiers, touches); - if (tracker != NULL) - { - return tracker; - } - } - - return NULL; - } - - - void LayoutWidget::RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y) - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->RenderMouseOver(target, x, y); - } - } - - - void LayoutWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->MouseWheel(direction, x, y, modifiers); - } - } - - - void LayoutWidget::KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->GetWidget().KeyPressed(key, keyChar, modifiers); - } - } - - - void LayoutWidget::DoAnimation() - { - if (hasAnimation_) - { - for (size_t i = 0; i < children_.size(); i++) - { - children_[i]->DoAnimation(); - } - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - bool LayoutWidget::HasRenderMouseOver() - { - for (size_t i = 0; i < children_.size(); i++) - { - if (children_[i]->HasRenderMouseOver()) - { - return true; - } - } - - return false; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/LayoutWidget.h --- a/Framework/Widgets/LayoutWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,134 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WidgetBase.h" - -#include -#include - -namespace Deprecated -{ - class LayoutWidget : public WidgetBase - { - private: - class LayoutMouseTracker; - class ChildWidget; - - std::vector children_; - bool isHorizontal_; - unsigned int width_; - unsigned int height_; - std::auto_ptr mouseTracker_; - unsigned int paddingLeft_; - unsigned int paddingTop_; - unsigned int paddingRight_; - unsigned int paddingBottom_; - unsigned int paddingInternal_; - bool hasAnimation_; - - void ComputeChildrenExtents(); - - public: - LayoutWidget(const std::string& name); - - virtual ~LayoutWidget(); - - virtual void FitContent(); - - virtual void NotifyContentChanged(const IWidget& widget); - - void SetHorizontal(); - - void SetVertical(); - - void SetPadding(unsigned int left, - unsigned int top, - unsigned int right, - unsigned int bottom, - unsigned int spacing); - - void SetPadding(unsigned int padding); - - unsigned int GetPaddingLeft() const - { - return paddingLeft_; - } - - unsigned int GetPaddingTop() const - { - return paddingTop_; - } - - unsigned int GetPaddingRight() const - { - return paddingRight_; - } - - unsigned int GetPaddingBottom() const - { - return paddingBottom_; - } - - unsigned int GetPaddingInternal() const - { - return paddingInternal_; - } - - IWidget& AddWidget(IWidget* widget); // Takes ownership - - virtual void SetStatusBar(IStatusBar& statusBar); - - virtual void SetSize(unsigned int width, - unsigned int height); - - virtual bool Render(Orthanc::ImageAccessor& surface); - - virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches); - - virtual void RenderMouseOver(Orthanc::ImageAccessor& target, - int x, - int y); - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers); - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers); - - virtual bool HasAnimation() const - { - return hasAnimation_; - } - - virtual void DoAnimation(); - - virtual bool HasRenderMouseOver(); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/PanMouseTracker.cpp --- a/Framework/Widgets/PanMouseTracker.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "PanMouseTracker.h" - -#include -#include - -namespace Deprecated -{ - PanMouseTracker::PanMouseTracker(WorldSceneWidget& that, - int x, - int y) : - that_(that) - { - that.GetView().GetPan(originalPanX_, originalPanY_); - that.GetView().MapPixelCenterToScene(downX_, downY_, x, y); - } - - - void PanMouseTracker::Render(OrthancStone::CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - - void PanMouseTracker::MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches) - { - ViewportGeometry view = that_.GetView(); - view.SetPan(originalPanX_ + (x - downX_) * view.GetZoom(), - originalPanY_ + (y - downY_) * view.GetZoom()); - that_.SetView(view); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/PanMouseTracker.h --- a/Framework/Widgets/PanMouseTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" - -namespace Deprecated -{ - class PanMouseTracker : public IWorldSceneMouseTracker - { - private: - WorldSceneWidget& that_; - double originalPanX_; - double originalPanY_; - double downX_; - double downY_; - - public: - PanMouseTracker(WorldSceneWidget& that, - int x, - int y); - - virtual bool HasRender() const - { - return false; - } - - virtual void MouseUp() - { - } - - virtual void Render(OrthancStone::CairoContext& context, - double zoom); - - virtual void MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/PanZoomMouseTracker.cpp --- a/Framework/Widgets/PanZoomMouseTracker.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "PanZoomMouseTracker.h" - -#include -#include -#include - -namespace Deprecated -{ - Touch GetCenter(const std::vector& touches) - { - return Touch((touches[0].x + touches[1].x) / 2.0f, (touches[0].y + touches[1].y) / 2.0f); - } - - double GetDistance(const std::vector& touches) - { - float dx = touches[0].x - touches[1].x; - float dy = touches[0].y - touches[1].y; - return sqrt((double)(dx * dx) + (double)(dy * dy)); - } - - - PanZoomMouseTracker::PanZoomMouseTracker(WorldSceneWidget& that, - const std::vector& startTouches) - : that_(that), - originalZoom_(that.GetView().GetZoom()) - { - that.GetView().GetPan(originalPanX_, originalPanY_); - that.GetView().MapPixelCenterToScene(originalSceneTouches_, startTouches); - - originalDisplayCenter_ = GetCenter(startTouches); - originalSceneCenter_ = GetCenter(originalSceneTouches_); - originalDisplayDistanceBetweenTouches_ = GetDistance(startTouches); - -// printf("original Pan %f %f\n", originalPanX_, originalPanY_); -// printf("original Zoom %f \n", originalZoom_); -// printf("original distance %f \n", (float)originalDisplayDistanceBetweenTouches_); -// printf("original display touches 0 %f %f\n", startTouches[0].x, startTouches[0].y); -// printf("original display touches 1 %f %f\n", startTouches[1].x, startTouches[1].y); -// printf("original Scene center %f %f\n", originalSceneCenter_.x, originalSceneCenter_.y); - - unsigned int height = that.GetView().GetDisplayHeight(); - - if (height <= 3) - { - idle_ = true; - LOG(WARNING) << "image is too small to zoom (current height = " << height << ")"; - } - else - { - idle_ = false; - normalization_ = 1.0 / static_cast(height - 1); - } - - } - - - void PanZoomMouseTracker::Render(OrthancStone::CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - - void PanZoomMouseTracker::MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches) - { - ViewportGeometry view = that_.GetView(); - -// printf("Display touches 0 %f %f\n", displayTouches[0].x, displayTouches[0].y); -// printf("Display touches 1 %f %f\n", displayTouches[1].x, displayTouches[1].y); -// printf("Scene touches 0 %f %f\n", sceneTouches[0].x, sceneTouches[0].y); -// printf("Scene touches 1 %f %f\n", sceneTouches[1].x, sceneTouches[1].y); - -// printf("zoom = %f\n", view.GetZoom()); - Touch currentSceneCenter = GetCenter(sceneTouches); - double panX = originalPanX_ + (currentSceneCenter.x - originalSceneCenter_.x) * view.GetZoom(); - double panY = originalPanY_ + (currentSceneCenter.y - originalSceneCenter_.y) * view.GetZoom(); - - view.SetPan(panX, panY); - - static const double MIN_ZOOM = -4; - static const double MAX_ZOOM = 4; - - if (!idle_) - { - double currentDistanceBetweenTouches = GetDistance(displayTouches); - - double dy = static_cast(currentDistanceBetweenTouches - originalDisplayDistanceBetweenTouches_) * normalization_; // In the range [-1,1] - double z; - - // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] - if (dy < -1.0) - { - z = MIN_ZOOM; - } - else if (dy > 1.0) - { - z = MAX_ZOOM; - } - else - { - z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; - } - - z = pow(2.0, z); - - view.SetZoom(z * originalZoom_); - } - - that_.SetView(view); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/PanZoomMouseTracker.h --- a/Framework/Widgets/PanZoomMouseTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" - -namespace Deprecated -{ - class PanZoomMouseTracker : public IWorldSceneMouseTracker - { - private: - WorldSceneWidget& that_; - std::vector originalSceneTouches_; - Touch originalSceneCenter_; - Touch originalDisplayCenter_; - double originalPanX_; - double originalPanY_; - double originalZoom_; - double originalDisplayDistanceBetweenTouches_; - bool idle_; - double normalization_; - - public: - PanZoomMouseTracker(WorldSceneWidget& that, - const std::vector& startTouches); - - virtual bool HasRender() const - { - return false; - } - - virtual void MouseUp() - { - } - - virtual void Render(OrthancStone::CairoContext& context, - double zoom); - - virtual void MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/SliceViewerWidget.cpp --- a/Framework/Widgets/SliceViewerWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,654 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "SliceViewerWidget.h" - -#include "../Layers/SliceOutlineRenderer.h" -#include "../Toolbox/GeometryToolbox.h" -#include "Framework/Layers/FrameRenderer.h" - -#include -#include - -#include - - -static const double THIN_SLICE_THICKNESS = 100.0 * std::numeric_limits::epsilon(); - -namespace Deprecated -{ - class SliceViewerWidget::Scene : public boost::noncopyable - { - private: - OrthancStone::CoordinateSystem3D plane_; - double thickness_; - size_t countMissing_; - std::vector renderers_; - - public: - void DeleteLayer(size_t index) - { - if (index >= renderers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - assert(countMissing_ <= renderers_.size()); - - if (renderers_[index] != NULL) - { - assert(countMissing_ < renderers_.size()); - delete renderers_[index]; - renderers_[index] = NULL; - countMissing_++; - } - } - - Scene(const OrthancStone::CoordinateSystem3D& plane, - double thickness, - size_t countLayers) : - plane_(plane), - thickness_(thickness), - countMissing_(countLayers), - renderers_(countLayers, NULL) - { - if (thickness <= 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - ~Scene() - { - for (size_t i = 0; i < renderers_.size(); i++) - { - DeleteLayer(i); - } - } - - void SetLayer(size_t index, - ILayerRenderer* renderer) // Takes ownership - { - if (renderer == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - DeleteLayer(index); - - renderers_[index] = renderer; - countMissing_--; - } - - const OrthancStone::CoordinateSystem3D& GetPlane() const - { - return plane_; - } - - bool HasRenderer(size_t index) - { - return renderers_[index] != NULL; - } - - bool IsComplete() const - { - return countMissing_ == 0; - } - - unsigned int GetCountMissing() const - { - return static_cast(countMissing_); - } - - bool RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view, - const OrthancStone::CoordinateSystem3D& viewportPlane) - { - bool fullQuality = true; - cairo_t *cr = context.GetObject(); - - for (size_t i = 0; i < renderers_.size(); i++) - { - if (renderers_[i] != NULL) - { - const OrthancStone::CoordinateSystem3D& framePlane = renderers_[i]->GetLayerPlane(); - - double x0, y0, x1, y1, x2, y2; - viewportPlane.ProjectPoint(x0, y0, framePlane.GetOrigin()); - viewportPlane.ProjectPoint(x1, y1, framePlane.GetOrigin() + framePlane.GetAxisX()); - viewportPlane.ProjectPoint(x2, y2, framePlane.GetOrigin() + framePlane.GetAxisY()); - - /** - * Now we solve the system of linear equations Ax + b = x', given: - * A [0 ; 0] + b = [x0 ; y0] - * A [1 ; 0] + b = [x1 ; y1] - * A [0 ; 1] + b = [x2 ; y2] - * <=> - * b = [x0 ; y0] - * A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0] - * A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0] - * <=> - * b = [x0 ; y0] - * [a11 ; a21] = [x1 - x0 ; y1 - y0] - * [a12 ; a22] = [x2 - x0 ; y2 - y0] - **/ - - cairo_matrix_t transform; - cairo_matrix_init(&transform, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0); - - cairo_save(cr); - cairo_transform(cr, &transform); - - if (!renderers_[i]->RenderLayer(context, view)) - { - cairo_restore(cr); - return false; - } - - cairo_restore(cr); - } - - if (renderers_[i] != NULL && - !renderers_[i]->IsFullQuality()) - { - fullQuality = false; - } - } - - if (!fullQuality) - { - double x, y; - view.MapDisplayToScene(x, y, static_cast(view.GetDisplayWidth()) / 2.0, 10); - - cairo_translate(cr, x, y); - -#if 1 - double s = 5.0 / view.GetZoom(); - cairo_rectangle(cr, -s, -s, 2.0 * s, 2.0 * s); -#else - // TODO Drawing filled circles makes WebAssembly crash! - cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2.0 * boost::math::constants::pi()); -#endif - - cairo_set_line_width(cr, 2.0 / view.GetZoom()); - cairo_set_source_rgb(cr, 1, 1, 1); - cairo_stroke_preserve(cr); - cairo_set_source_rgb(cr, 1, 0, 0); - cairo_fill(cr); - } - - return true; - } - - void SetLayerStyle(size_t index, - const RenderStyle& style) - { - if (renderers_[index] != NULL) - { - renderers_[index]->SetLayerStyle(style); - } - } - - bool ContainsPlane(const OrthancStone::CoordinateSystem3D& plane) const - { - bool isOpposite; - if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, - plane.GetNormal(), - plane_.GetNormal())) - { - return false; - } - else - { - double z = (plane_.ProjectAlongNormal(plane.GetOrigin()) - - plane_.ProjectAlongNormal(plane_.GetOrigin())); - - if (z < 0) - { - z = -z; - } - - return z <= thickness_; - } - } - - double GetThickness() const - { - return thickness_; - } - }; - - - bool SliceViewerWidget::LookupLayer(size_t& index /* out */, - const IVolumeSlicer& layer) const - { - LayersIndex::const_iterator found = layersIndex_.find(&layer); - - if (found == layersIndex_.end()) - { - return false; - } - else - { - index = found->second; - assert(index < layers_.size() && - layers_[index] == &layer); - return true; - } - } - - - void SliceViewerWidget::GetLayerExtent(OrthancStone::Extent2D& extent, - IVolumeSlicer& source) const - { - extent.Reset(); - - std::vector points; - if (source.GetExtent(points, plane_)) - { - for (size_t i = 0; i < points.size(); i++) - { - double x, y; - plane_.ProjectPoint(x, y, points[i]); - extent.AddPoint(x, y); - } - } - } - - - OrthancStone::Extent2D SliceViewerWidget::GetSceneExtent() - { - OrthancStone::Extent2D sceneExtent; - - for (size_t i = 0; i < layers_.size(); i++) - { - assert(layers_[i] != NULL); - OrthancStone::Extent2D layerExtent; - GetLayerExtent(layerExtent, *layers_[i]); - - sceneExtent.Union(layerExtent); - } - - return sceneExtent; - } - - - bool SliceViewerWidget::RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - if (currentScene_.get() != NULL) - { - return currentScene_->RenderScene(context, view, plane_); - } - else - { - return true; - } - } - - - void SliceViewerWidget::ResetPendingScene() - { - double thickness; - if (pendingScene_.get() == NULL) - { - thickness = 1.0; - } - else - { - thickness = pendingScene_->GetThickness(); - } - - pendingScene_.reset(new Scene(plane_, thickness, layers_.size())); - } - - - void SliceViewerWidget::UpdateLayer(size_t index, - ILayerRenderer* renderer, - const OrthancStone::CoordinateSystem3D& plane) - { - LOG(INFO) << "Updating layer " << index; - - std::auto_ptr tmp(renderer); - - if (renderer == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - if (index >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - assert(layers_.size() == styles_.size()); - renderer->SetLayerStyle(styles_[index]); - - if (currentScene_.get() != NULL && - currentScene_->ContainsPlane(plane)) - { - currentScene_->SetLayer(index, tmp.release()); - NotifyContentChanged(); - } - else if (pendingScene_.get() != NULL && - pendingScene_->ContainsPlane(plane)) - { - pendingScene_->SetLayer(index, tmp.release()); - - if (currentScene_.get() == NULL || - !currentScene_->IsComplete() || - pendingScene_->IsComplete()) - { - currentScene_ = pendingScene_; - NotifyContentChanged(); - } - } - } - - - SliceViewerWidget::SliceViewerWidget(OrthancStone::MessageBroker& broker, - const std::string& name) : - WorldSceneWidget(name), - IObserver(broker), - IObservable(broker), - started_(false) - { - SetBackgroundCleared(true); - } - - - SliceViewerWidget::~SliceViewerWidget() - { - for (size_t i = 0; i < layers_.size(); i++) - { - delete layers_[i]; - } - } - - void SliceViewerWidget::ObserveLayer(IVolumeSlicer& layer) - { - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnGeometryReady)); - // currently ignore errors layer->RegisterObserverCallback(new Callable(*this, &SliceViewerWidget::...)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnSliceChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnContentChanged)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnLayerReady)); - layer.RegisterObserverCallback(new OrthancStone::Callable - (*this, &SliceViewerWidget::OnLayerError)); - } - - - size_t SliceViewerWidget::AddLayer(IVolumeSlicer* layer) // Takes ownership - { - if (layer == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - size_t index = layers_.size(); - layers_.push_back(layer); - styles_.push_back(RenderStyle()); - layersIndex_[layer] = index; - - ResetPendingScene(); - - ObserveLayer(*layer); - - ResetChangedLayers(); - - return index; - } - - - void SliceViewerWidget::ReplaceLayer(size_t index, IVolumeSlicer* layer) // Takes ownership - { - if (layer == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - if (index >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - delete layers_[index]; - layers_[index] = layer; - layersIndex_[layer] = index; - - ResetPendingScene(); - - ObserveLayer(*layer); - - InvalidateLayer(index); - } - - - void SliceViewerWidget::RemoveLayer(size_t index) - { - if (index >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - IVolumeSlicer* previousLayer = layers_[index]; - layersIndex_.erase(layersIndex_.find(previousLayer)); - layers_.erase(layers_.begin() + index); - changedLayers_.erase(changedLayers_.begin() + index); - styles_.erase(styles_.begin() + index); - - delete layers_[index]; - - currentScene_->DeleteLayer(index); - ResetPendingScene(); - - NotifyContentChanged(); - } - - - const RenderStyle& SliceViewerWidget::GetLayerStyle(size_t layer) const - { - if (layer >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - assert(layers_.size() == styles_.size()); - return styles_[layer]; - } - - - void SliceViewerWidget::SetLayerStyle(size_t layer, - const RenderStyle& style) - { - if (layer >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - assert(layers_.size() == styles_.size()); - styles_[layer] = style; - - if (currentScene_.get() != NULL) - { - currentScene_->SetLayerStyle(layer, style); - } - - if (pendingScene_.get() != NULL) - { - pendingScene_->SetLayerStyle(layer, style); - } - - NotifyContentChanged(); - } - - - void SliceViewerWidget::SetSlice(const OrthancStone::CoordinateSystem3D& plane) - { - LOG(INFO) << "Setting slice origin: (" << plane.GetOrigin()[0] - << "," << plane.GetOrigin()[1] - << "," << plane.GetOrigin()[2] << ")"; - - Deprecated::Slice displayedSlice(plane_, THIN_SLICE_THICKNESS); - - //if (!displayedSlice.ContainsPlane(slice)) - { - if (currentScene_.get() == NULL || - (pendingScene_.get() != NULL && - pendingScene_->IsComplete())) - { - currentScene_ = pendingScene_; - } - - plane_ = plane; - ResetPendingScene(); - - InvalidateAllLayers(); // TODO Removing this line avoid loading twice the image in WASM - } - - BroadcastMessage(DisplayedSliceMessage(*this, displayedSlice)); - } - - - void SliceViewerWidget::OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message) - { - size_t i; - if (LookupLayer(i, message.GetOrigin())) - { - LOG(INFO) << ": Geometry ready for layer " << i << " in " << GetName(); - - changedLayers_[i] = true; - //layers_[i]->ScheduleLayerCreation(plane_); - } - BroadcastMessage(GeometryChangedMessage(*this)); - } - - - void SliceViewerWidget::InvalidateAllLayers() - { - for (size_t i = 0; i < layers_.size(); i++) - { - assert(layers_[i] != NULL); - changedLayers_[i] = true; - - //layers_[i]->ScheduleLayerCreation(plane_); - } - } - - - void SliceViewerWidget::InvalidateLayer(size_t layer) - { - if (layer >= layers_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - assert(layers_[layer] != NULL); - changedLayers_[layer] = true; - - //layers_[layer]->ScheduleLayerCreation(plane_); - } - - - void SliceViewerWidget::OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message) - { - size_t index; - if (LookupLayer(index, message.GetOrigin())) - { - InvalidateLayer(index); - } - - BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); - } - - - void SliceViewerWidget::OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message) - { - if (message.GetSlice().ContainsPlane(plane_)) - { - size_t index; - if (LookupLayer(index, message.GetOrigin())) - { - InvalidateLayer(index); - } - } - - BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); - } - - - void SliceViewerWidget::OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message) - { - size_t index; - if (LookupLayer(index, message.GetOrigin())) - { - LOG(INFO) << "Renderer ready for layer " << index; - UpdateLayer(index, message.CreateRenderer(), message.GetSlice()); - } - - BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); - } - - - void SliceViewerWidget::OnLayerError(const IVolumeSlicer::LayerErrorMessage& message) - { - size_t index; - if (LookupLayer(index, message.GetOrigin())) - { - LOG(ERROR) << "Using error renderer on layer " << index; - - // TODO - //UpdateLayer(index, new SliceOutlineRenderer(slice), slice); - - BroadcastMessage(SliceViewerWidget::ContentChangedMessage(*this)); - } - } - - - void SliceViewerWidget::ResetChangedLayers() - { - changedLayers_.resize(layers_.size()); - - for (size_t i = 0; i < changedLayers_.size(); i++) - { - changedLayers_[i] = false; - } - } - - - void SliceViewerWidget::DoAnimation() - { - assert(changedLayers_.size() <= layers_.size()); - - for (size_t i = 0; i < changedLayers_.size(); i++) - { - if (changedLayers_[i]) - { - layers_[i]->ScheduleLayerCreation(plane_); - } - } - - ResetChangedLayers(); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/SliceViewerWidget.h --- a/Framework/Widgets/SliceViewerWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" -#include "../Layers/IVolumeSlicer.h" -#include "../Toolbox/Extent2D.h" -#include "../../Framework/Messages/IObserver.h" - -#include - -namespace Deprecated -{ - class SliceViewerWidget : - public WorldSceneWidget, - public OrthancStone::IObserver, - public OrthancStone::IObservable - { - public: - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, GeometryChangedMessage, SliceViewerWidget); - ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, ContentChangedMessage, SliceViewerWidget); - - - // TODO - Use this message in ReferenceLineSource - class DisplayedSliceMessage : public OrthancStone::OriginMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - private: - const Deprecated::Slice& slice_; - - public: - DisplayedSliceMessage(SliceViewerWidget& origin, - const Deprecated::Slice& slice) : - OriginMessage(origin), - slice_(slice) - { - } - - const Deprecated::Slice& GetSlice() const - { - return slice_; - } - }; - - private: - SliceViewerWidget(const SliceViewerWidget&); - SliceViewerWidget& operator=(const SliceViewerWidget&); - - class Scene; - - typedef std::map LayersIndex; - - bool started_; - LayersIndex layersIndex_; - std::vector layers_; - std::vector styles_; - OrthancStone::CoordinateSystem3D plane_; - std::auto_ptr currentScene_; - std::auto_ptr pendingScene_; - std::vector changedLayers_; - - bool LookupLayer(size_t& index /* out */, - const IVolumeSlicer& layer) const; - - void GetLayerExtent(OrthancStone::Extent2D& extent, - IVolumeSlicer& source) const; - - void OnGeometryReady(const IVolumeSlicer::GeometryReadyMessage& message); - - virtual void OnContentChanged(const IVolumeSlicer::ContentChangedMessage& message); - - virtual void OnSliceChanged(const IVolumeSlicer::SliceContentChangedMessage& message); - - virtual void OnLayerReady(const IVolumeSlicer::LayerReadyMessage& message); - - virtual void OnLayerError(const IVolumeSlicer::LayerErrorMessage& message); - - void ObserveLayer(IVolumeSlicer& source); - - void ResetChangedLayers(); - - public: - SliceViewerWidget(OrthancStone::MessageBroker& broker, - const std::string& name); - - virtual OrthancStone::Extent2D GetSceneExtent(); - - protected: - virtual bool RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view); - - void ResetPendingScene(); - - void UpdateLayer(size_t index, - ILayerRenderer* renderer, - const OrthancStone::CoordinateSystem3D& plane); - - void InvalidateAllLayers(); - - void InvalidateLayer(size_t layer); - - public: - virtual ~SliceViewerWidget(); - - size_t AddLayer(IVolumeSlicer* layer); // Takes ownership - - void ReplaceLayer(size_t layerIndex, IVolumeSlicer* layer); // Takes ownership - - void RemoveLayer(size_t layerIndex); - - size_t GetLayerCount() const - { - return layers_.size(); - } - - const RenderStyle& GetLayerStyle(size_t layer) const; - - void SetLayerStyle(size_t layer, - const RenderStyle& style); - - void SetSlice(const OrthancStone::CoordinateSystem3D& plane); - - const OrthancStone::CoordinateSystem3D& GetSlice() const - { - return plane_; - } - - virtual bool HasAnimation() const - { - return true; - } - - virtual void DoAnimation(); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/TestCairoWidget.cpp --- a/Framework/Widgets/TestCairoWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "TestCairoWidget.h" - -#include - - -namespace Deprecated -{ - namespace Samples - { - void TestCairoWidget::DoAnimation() - { - value_ -= 0.01f; - if (value_ < 0) - { - value_ = 1; - } - - NotifyContentChanged(); - } - - - bool TestCairoWidget::RenderCairo(OrthancStone::CairoContext& context) - { - cairo_t* cr = context.GetObject(); - - cairo_set_source_rgb (cr, .3, 0, 0); - cairo_paint(cr); - - cairo_set_source_rgb(cr, 0, 1, 0); - cairo_rectangle(cr, width_ / 4, height_ / 4, width_ / 2, height_ / 2); - cairo_set_line_width(cr, 1.0); - cairo_fill(cr); - - cairo_set_source_rgb(cr, 0, 1, value_); - cairo_rectangle(cr, width_ / 2 - 50, height_ / 2 - 50, 100, 100); - cairo_fill(cr); - - return true; - } - - - void TestCairoWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context, - int x, - int y) - { - cairo_t* cr = context.GetObject(); - - cairo_set_source_rgb (cr, 1, 0, 0); - cairo_rectangle(cr, x - 5, y - 5, 10, 10); - cairo_set_line_width(cr, 1.0); - cairo_stroke(cr); - - char buf[64]; - sprintf(buf, "(%d,%d)", x, y); - UpdateStatusBar(buf); - } - - - TestCairoWidget::TestCairoWidget(const std::string& name, bool animate) : - CairoWidget(name), - width_(0), - height_(0), - value_(1), - animate_(animate) - { - } - - - void TestCairoWidget::SetSize(unsigned int width, - unsigned int height) - { - CairoWidget::SetSize(width, height); - width_ = width; - height_ = height; - } - - - IMouseTracker* TestCairoWidget::CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) - { - UpdateStatusBar("Click"); - return NULL; - } - - - void TestCairoWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - UpdateStatusBar(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up"); - } - - - void TestCairoWidget::KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) - { - UpdateStatusBar("Key pressed: \"" + std::string(1, keyChar) + "\""); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/TestCairoWidget.h --- a/Framework/Widgets/TestCairoWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "CairoWidget.h" - -namespace Deprecated -{ - namespace Samples - { - class TestCairoWidget : public CairoWidget - { - private: - unsigned int width_; - unsigned int height_; - float value_; - bool animate_; - - protected: - virtual bool RenderCairo(OrthancStone::CairoContext& context); - - virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, - int x, - int y); - - public: - TestCairoWidget(const std::string& name, bool animate); - - virtual void SetSize(unsigned int width, - unsigned int height); - - virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches); - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers); - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers); - - virtual bool HasAnimation() const - { - return animate_; - } - - virtual void DoAnimation(); - - virtual bool HasRenderMouseOver() - { - return true; - } - }; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/TestWorldSceneWidget.cpp --- a/Framework/Widgets/TestWorldSceneWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "TestWorldSceneWidget.h" - -#include - -#include -#include - -namespace Deprecated -{ - namespace Samples - { - class TestWorldSceneWidget::Interactor : public IWorldSceneInteractor - { - public: - virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, - const ViewportGeometry& view, - OrthancStone::MouseButton button, - OrthancStone::KeyboardModifiers modifiers, - int viewportX, - int viewportY, - double x, - double y, - IStatusBar* statusBar, - const std::vector& touches) - { - if (statusBar) - { - char buf[64]; - sprintf(buf, "X = %0.2f, Y = %0.2f", x, y); - statusBar->SetMessage(buf); - } - - return NULL; - } - - virtual void MouseOver(OrthancStone::CairoContext& context, - WorldSceneWidget& widget, - const ViewportGeometry& view, - double x, - double y, - IStatusBar* statusBar) - { - double S = 0.5; - - if (fabs(x) <= S && - fabs(y) <= S) - { - cairo_t* cr = context.GetObject(); - cairo_set_source_rgb(cr, 1, 0, 0); - cairo_rectangle(cr, -S, -S , 2.0 * S, 2.0 * S); - cairo_set_line_width(cr, 1.0 / view.GetZoom()); - cairo_stroke(cr); - } - } - - virtual void MouseWheel(WorldSceneWidget& widget, - OrthancStone::MouseWheelDirection direction, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) - { - if (statusBar) - { - statusBar->SetMessage(direction == OrthancStone::MouseWheelDirection_Down ? "Wheel down" : "Wheel up"); - } - } - - virtual void KeyPressed(WorldSceneWidget& widget, - OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) - { - if (statusBar) - { - statusBar->SetMessage("Key pressed: \"" + std::string(1, keyChar) + "\""); - } - } - }; - - - bool TestWorldSceneWidget::RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view) - { - cairo_t* cr = context.GetObject(); - - // Clear background - cairo_set_source_rgb(cr, 0, 0, 0); - cairo_paint(cr); - - float color = static_cast(count_ % 16) / 15.0f; - cairo_set_source_rgb(cr, 0, 1.0f - color, color); - cairo_rectangle(cr, -10, -.5, 20, 1); - cairo_fill(cr); - - return true; - } - - - TestWorldSceneWidget::TestWorldSceneWidget(const std::string& name, bool animate) : - WorldSceneWidget(name), - interactor_(new Interactor), - animate_(animate), - count_(0) - { - SetInteractor(*interactor_); - } - - - OrthancStone::Extent2D TestWorldSceneWidget::GetSceneExtent() - { - return OrthancStone::Extent2D(-10, -.5, 10, .5); - } - - - void TestWorldSceneWidget::DoAnimation() - { - if (animate_) - { - count_++; - NotifyContentChanged(); - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/TestWorldSceneWidget.h --- a/Framework/Widgets/TestWorldSceneWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" - -#include - -namespace Deprecated -{ - namespace Samples - { - class TestWorldSceneWidget : public WorldSceneWidget - { - private: - class Interactor; - - std::auto_ptr interactor_; - bool animate_; - unsigned int count_; - - protected: - virtual bool RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view); - - public: - TestWorldSceneWidget(const std::string& name, bool animate); - - virtual OrthancStone::Extent2D GetSceneExtent(); - - virtual bool HasAnimation() const - { - return animate_; - } - - virtual void DoAnimation(); - - virtual bool HasRenderMouseOver() - { - return true; - } - }; - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/WidgetBase.cpp --- a/Framework/Widgets/WidgetBase.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,166 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "WidgetBase.h" - -#include -#include -#include - -namespace Deprecated -{ - void WidgetBase::NotifyContentChanged() - { - if (parent_ != NULL) - { - parent_->NotifyContentChanged(); - } - - if (viewport_ != NULL) - { - viewport_->NotifyBackgroundChanged(); - } - } - - - void WidgetBase::SetParent(IWidget& parent) - { - if (parent_ != NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - parent_ = &parent; - } - } - - - void WidgetBase::ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const - { - // Clear the background using Orthanc - - if (backgroundCleared_) - { - Orthanc::ImageProcessing::Set(target, - backgroundColor_[0], - backgroundColor_[1], - backgroundColor_[2], - 255 /* alpha */); - } - } - - - void WidgetBase::ClearBackgroundCairo(OrthancStone::CairoContext& context) const - { - // Clear the background using Cairo - - if (IsBackgroundCleared()) - { - uint8_t red, green, blue; - GetBackgroundColor(red, green, blue); - - context.SetSourceColor(red, green, blue); - cairo_paint(context.GetObject()); - } - } - - - void WidgetBase::ClearBackgroundCairo(Orthanc::ImageAccessor& target) const - { - OrthancStone::CairoSurface surface(target, false /* no alpha */); - OrthancStone::CairoContext context(surface); - ClearBackgroundCairo(context); - } - - - void WidgetBase::UpdateStatusBar(const std::string& message) - { - if (statusBar_ != NULL) - { - statusBar_->SetMessage(message); - } - } - - - WidgetBase::WidgetBase(const std::string& name) : - parent_(NULL), - viewport_(NULL), - statusBar_(NULL), - backgroundCleared_(false), - transmitMouseOver_(false), - name_(name) - { - backgroundColor_[0] = 0; - backgroundColor_[1] = 0; - backgroundColor_[2] = 0; - } - - - void WidgetBase::SetViewport(WidgetViewport& viewport) - { - if (viewport_ != NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - viewport_ = &viewport; - } - } - - - void WidgetBase::SetBackgroundColor(uint8_t red, - uint8_t green, - uint8_t blue) - { - backgroundColor_[0] = red; - backgroundColor_[1] = green; - backgroundColor_[2] = blue; - } - - void WidgetBase::GetBackgroundColor(uint8_t& red, - uint8_t& green, - uint8_t& blue) const - { - red = backgroundColor_[0]; - green = backgroundColor_[1]; - blue = backgroundColor_[2]; - } - - - bool WidgetBase::Render(Orthanc::ImageAccessor& surface) - { -#if 0 - ClearBackgroundOrthanc(surface); -#else - ClearBackgroundCairo(surface); // Faster than Orthanc -#endif - - return true; - } - - - void WidgetBase::DoAnimation() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/WidgetBase.h --- a/Framework/Widgets/WidgetBase.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "IWidget.h" - -#include "../Viewport/CairoContext.h" -#include "../Viewport/WidgetViewport.h" - -namespace Deprecated -{ - class WidgetBase : public IWidget - { - private: - IWidget* parent_; - WidgetViewport* viewport_; - IStatusBar* statusBar_; - bool backgroundCleared_; - uint8_t backgroundColor_[3]; - bool transmitMouseOver_; - std::string name_; - - protected: - void ClearBackgroundOrthanc(Orthanc::ImageAccessor& target) const; - - void ClearBackgroundCairo(OrthancStone::CairoContext& context) const; - - void ClearBackgroundCairo(Orthanc::ImageAccessor& target) const; - - void UpdateStatusBar(const std::string& message); - - IStatusBar* GetStatusBar() const - { - return statusBar_; - } - - public: - WidgetBase(const std::string& name); - - virtual void FitContent() - { - } - - virtual void SetParent(IWidget& parent); - - virtual void SetViewport(WidgetViewport& viewport); - - void SetBackgroundCleared(bool clear) - { - backgroundCleared_ = clear; - } - - bool IsBackgroundCleared() const - { - return backgroundCleared_; - } - - void SetTransmitMouseOver(bool transmit) - { - transmitMouseOver_ = transmit; - } - - void SetBackgroundColor(uint8_t red, - uint8_t green, - uint8_t blue); - - void GetBackgroundColor(uint8_t& red, - uint8_t& green, - uint8_t& blue) const; - - virtual void SetStatusBar(IStatusBar& statusBar) - { - statusBar_ = &statusBar; - } - - virtual bool Render(Orthanc::ImageAccessor& surface); - - virtual bool HasAnimation() const - { - return false; - } - - virtual void DoAnimation(); - - virtual bool HasRenderMouseOver() - { - return transmitMouseOver_; - } - - virtual void NotifyContentChanged(); - - const std::string& GetName() const - { - return name_; - } - - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/WorldSceneWidget.cpp --- a/Framework/Widgets/WorldSceneWidget.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,231 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "WorldSceneWidget.h" - -#include "PanMouseTracker.h" -#include "ZoomMouseTracker.h" -#include "PanZoomMouseTracker.h" - -#include -#include - -#include -#include -#include - -namespace Deprecated -{ - // this is an adapter between a IWorldSceneMouseTracker - // that is tracking a mouse in scene coordinates/mm and - // an IMouseTracker that is tracking a mouse - // in screen coordinates/pixels. - class WorldSceneWidget::SceneMouseTracker : public IMouseTracker - { - private: - ViewportGeometry view_; - std::auto_ptr tracker_; - - public: - SceneMouseTracker(const ViewportGeometry& view, - IWorldSceneMouseTracker* tracker) : - view_(view), - tracker_(tracker) - { - if (tracker == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - } - - virtual void Render(Orthanc::ImageAccessor& target) - { - if (tracker_->HasRender()) - { - OrthancStone::CairoSurface surface(target, false /* no alpha */); - OrthancStone::CairoContext context(surface); - view_.ApplyTransform(context); - tracker_->Render(context, view_.GetZoom()); - } - } - - virtual void MouseUp() - { - tracker_->MouseUp(); - } - - virtual void MouseMove(int x, - int y, - const std::vector& displayTouches) - { - double sceneX, sceneY; - view_.MapPixelCenterToScene(sceneX, sceneY, x, y); - - std::vector sceneTouches; - for (size_t t = 0; t < displayTouches.size(); t++) - { - double sx, sy; - - view_.MapPixelCenterToScene( - sx, sy, (int)displayTouches[t].x, (int)displayTouches[t].y); - - sceneTouches.push_back( - Touch(static_cast(sx), static_cast(sy))); - } - tracker_->MouseMove(x, y, sceneX, sceneY, displayTouches, sceneTouches); - } - }; - - - bool WorldSceneWidget::RenderCairo(OrthancStone::CairoContext& context) - { - view_.ApplyTransform(context); - return RenderScene(context, view_); - } - - - void WorldSceneWidget::RenderMouseOverCairo(OrthancStone::CairoContext& context, - int x, - int y) - { - ViewportGeometry view = GetView(); - view.ApplyTransform(context); - - double sceneX, sceneY; - view.MapPixelCenterToScene(sceneX, sceneY, x, y); - - if (interactor_) - { - interactor_->MouseOver(context, *this, view, sceneX, sceneY, GetStatusBar()); - } - } - - - void WorldSceneWidget::SetSceneExtent(ViewportGeometry& view) - { - view.SetSceneExtent(GetSceneExtent()); - } - - - void WorldSceneWidget::SetSize(unsigned int width, - unsigned int height) - { - CairoWidget::SetSize(width, height); - view_.SetDisplaySize(width, height); - } - - - void WorldSceneWidget::SetInteractor(IWorldSceneInteractor& interactor) - { - interactor_ = &interactor; - } - - - void WorldSceneWidget::FitContent() - { - SetSceneExtent(view_); - view_.FitContent(); - - NotifyContentChanged(); - } - - - void WorldSceneWidget::SetView(const ViewportGeometry& view) - { - view_ = view; - - NotifyContentChanged(); - } - - - IMouseTracker* WorldSceneWidget::CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches) - { - double sceneX, sceneY; - view_.MapPixelCenterToScene(sceneX, sceneY, x, y); - - // asks the Widget Interactor to provide a mouse tracker - std::auto_ptr tracker; - - if (interactor_) - { - tracker.reset(interactor_->CreateMouseTracker(*this, view_, button, modifiers, x, y, sceneX, sceneY, GetStatusBar(), touches)); - } - - if (tracker.get() != NULL) - { - return new SceneMouseTracker(view_, tracker.release()); - } - else if (hasDefaultMouseEvents_) - { - printf("has default mouse events\n"); - if (touches.size() == 2) - { - printf("2 touches !\n"); - return new SceneMouseTracker(view_, new PanZoomMouseTracker(*this, touches)); - } - else - { - switch (button) - { - case OrthancStone::MouseButton_Middle: - return new SceneMouseTracker(view_, new PanMouseTracker(*this, x, y)); - - case OrthancStone::MouseButton_Right: - return new SceneMouseTracker(view_, new ZoomMouseTracker(*this, x, y)); - - default: - return NULL; - } - } - } - else - { - return NULL; - } - } - - - void WorldSceneWidget::MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers) - { - if (interactor_) - { - interactor_->MouseWheel(*this, direction, modifiers, GetStatusBar()); - } - } - - - void WorldSceneWidget::KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers) - { - if (interactor_) - { - interactor_->KeyPressed(*this, key, keyChar, modifiers, GetStatusBar()); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/WorldSceneWidget.h --- a/Framework/Widgets/WorldSceneWidget.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,103 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "CairoWidget.h" -#include "IWorldSceneInteractor.h" - -#include "../Toolbox/ViewportGeometry.h" - -namespace Deprecated -{ - class WorldSceneWidget : public CairoWidget - { - private: - class SceneMouseTracker; - - ViewportGeometry view_; - IWorldSceneInteractor* interactor_; - bool hasDefaultMouseEvents_; - - protected: - virtual OrthancStone::Extent2D GetSceneExtent() = 0; - - virtual bool RenderScene(OrthancStone::CairoContext& context, - const ViewportGeometry& view) = 0; - - // From CairoWidget - virtual bool RenderCairo(OrthancStone::CairoContext& context); - - // From CairoWidget - virtual void RenderMouseOverCairo(OrthancStone::CairoContext& context, - int x, - int y); - - void SetSceneExtent(ViewportGeometry& geometry); - - public: - WorldSceneWidget(const std::string& name) : - CairoWidget(name), - interactor_(NULL), - hasDefaultMouseEvents_(true) - { - } - - void SetDefaultMouseEvents(bool value) - { - hasDefaultMouseEvents_ = value; - } - - bool HasDefaultMouseEvents() const - { - return hasDefaultMouseEvents_; - } - - void SetInteractor(IWorldSceneInteractor& interactor); - - void SetView(const ViewportGeometry& view); - - const ViewportGeometry& GetView() const - { - return view_; - } - - virtual void SetSize(unsigned int width, - unsigned int height); - - virtual void FitContent(); - - virtual IMouseTracker* CreateMouseTracker(OrthancStone::MouseButton button, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers, - const std::vector& touches); - - virtual void MouseWheel(OrthancStone::MouseWheelDirection direction, - int x, - int y, - OrthancStone::KeyboardModifiers modifiers); - - virtual void KeyPressed(OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/ZoomMouseTracker.cpp --- a/Framework/Widgets/ZoomMouseTracker.cpp Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#include "ZoomMouseTracker.h" - -#include -#include - -namespace Deprecated -{ - ZoomMouseTracker::ZoomMouseTracker(WorldSceneWidget& that, - int x, - int y) : - that_(that), - originalZoom_(that.GetView().GetZoom()), - downX_(x), - downY_(y) - { - that.GetView().MapPixelCenterToScene(centerX_, centerY_, x, y); - - unsigned int height = that.GetView().GetDisplayHeight(); - - if (height <= 3) - { - idle_ = true; - LOG(WARNING) << "image is too small to zoom (current height = " << height << ")"; - } - else - { - idle_ = false; - normalization_ = 1.0 / static_cast(height - 1); - } - } - - - void ZoomMouseTracker::Render(OrthancStone::CairoContext& context, - double zoom) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - - void ZoomMouseTracker::MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches) - { - static const double MIN_ZOOM = -4; - static const double MAX_ZOOM = 4; - - - if (!idle_) - { - double dy = static_cast(displayY - downY_) * normalization_; // In the range [-1,1] - double z; - - // Linear interpolation from [-1, 1] to [MIN_ZOOM, MAX_ZOOM] - if (dy < -1.0) - { - z = MIN_ZOOM; - } - else if (dy > 1.0) - { - z = MAX_ZOOM; - } - else - { - z = MIN_ZOOM + (MAX_ZOOM - MIN_ZOOM) * (dy + 1.0) / 2.0; - } - - z = pow(2.0, z); - - ViewportGeometry view = that_.GetView(); - - view.SetZoom(z * originalZoom_); - - // Correct the pan so that the original click point is kept at - // the same location on the display - double panX, panY; - view.GetPan(panX, panY); - - int tx, ty; - view.MapSceneToDisplay(tx, ty, centerX_, centerY_); - view.SetPan(panX + static_cast(downX_ - tx), - panY + static_cast(downY_ - ty)); - - that_.SetView(view); - } - } -} diff -r 529189f399ec -r c35e98d22764 Framework/Widgets/ZoomMouseTracker.h --- a/Framework/Widgets/ZoomMouseTracker.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "WorldSceneWidget.h" - -namespace Deprecated -{ - class ZoomMouseTracker : public IWorldSceneMouseTracker - { - private: - WorldSceneWidget& that_; - double originalZoom_; - int downX_; - int downY_; - double centerX_; - double centerY_; - bool idle_; - double normalization_; - - public: - ZoomMouseTracker(WorldSceneWidget& that, - int x, - int y); - - virtual bool HasRender() const - { - return false; - } - - virtual void MouseUp() - { - } - - virtual void Render(OrthancStone::CairoContext& context, - double zoom); - - virtual void MouseMove(int displayX, - int displayY, - double x, - double y, - const std::vector& displayTouches, - const std::vector& sceneTouches); - }; -} diff -r 529189f399ec -r c35e98d22764 Framework/dev.h --- a/Framework/dev.h Tue May 21 13:27:54 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,958 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 Osimis S.A., 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 . - **/ - - -#pragma once - -#include "Layers/FrameRenderer.h" -#include "Layers/LineLayerRenderer.h" -#include "Layers/SliceOutlineRenderer.h" -#include "Toolbox/DownloadStack.h" -#include "Toolbox/GeometryToolbox.h" -#include "Toolbox/OrthancSlicesLoader.h" -#include "Volumes/ImageBuffer3D.h" -#include "Volumes/ISlicedVolume.h" -#include "Widgets/SliceViewerWidget.h" - -#include -#include -#include - -#include - - -namespace Deprecated -{ - // TODO: Handle errors while loading - class OrthancVolumeImage : - public ISlicedVolume, - public OrthancStone::IObserver - { - private: - OrthancSlicesLoader loader_; - std::auto_ptr image_; - std::auto_ptr downloadStack_; - bool computeRange_; - size_t pendingSlices_; - - void ScheduleSliceDownload() - { - assert(downloadStack_.get() != NULL); - - unsigned int slice; - if (downloadStack_->Pop(slice)) - { - loader_.ScheduleLoadSliceImage(slice, OrthancStone::SliceImageQuality_Jpeg90); - } - } - - - static bool IsCompatible(const Slice& a, - const Slice& b) - { - if (!OrthancStone::GeometryToolbox::IsParallel(a.GetGeometry().GetNormal(), - b.GetGeometry().GetNormal())) - { - LOG(ERROR) << "A slice in the volume image is not parallel to the others."; - return false; - } - - if (a.GetConverter().GetExpectedPixelFormat() != b.GetConverter().GetExpectedPixelFormat()) - { - LOG(ERROR) << "The pixel format changes across the slices of the volume image."; - return false; - } - - if (a.GetWidth() != b.GetWidth() || - a.GetHeight() != b.GetHeight()) - { - LOG(ERROR) << "The slices dimensions (width/height) are varying throughout the volume image"; - return false; - } - - if (!OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingX(), b.GetPixelSpacingX()) || - !OrthancStone::LinearAlgebra::IsNear(a.GetPixelSpacingY(), b.GetPixelSpacingY())) - { - LOG(ERROR) << "The pixel spacing of the slices change across the volume image"; - return false; - } - - return true; - } - - - static double GetDistance(const Slice& a, - const Slice& b) - { - return fabs(a.GetGeometry().ProjectAlongNormal(a.GetGeometry().GetOrigin()) - - a.GetGeometry().ProjectAlongNormal(b.GetGeometry().GetOrigin())); - } - - - void OnSliceGeometryReady(const OrthancSlicesLoader::SliceGeometryReadyMessage& message) - { - assert(&message.GetOrigin() == &loader_); - - if (loader_.GetSlicesCount() == 0) - { - LOG(ERROR) << "Empty volume image"; - BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); - return; - } - - for (size_t i = 1; i < loader_.GetSlicesCount(); i++) - { - if (!IsCompatible(loader_.GetSlice(0), loader_.GetSlice(i))) - { - BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); - return; - } - } - - double spacingZ; - - if (loader_.GetSlicesCount() > 1) - { - spacingZ = GetDistance(loader_.GetSlice(0), loader_.GetSlice(1)); - } - else - { - // This is a volume with one single slice: Choose a dummy - // z-dimension for voxels - spacingZ = 1; - } - - for (size_t i = 1; i < loader_.GetSlicesCount(); i++) - { - if (!OrthancStone::LinearAlgebra::IsNear(spacingZ, GetDistance(loader_.GetSlice(i - 1), loader_.GetSlice(i)), - 0.001 /* this is expressed in mm */)) - { - LOG(ERROR) << "The distance between successive slices is not constant in a volume image"; - BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); - return; - } - } - - unsigned int width = loader_.GetSlice(0).GetWidth(); - unsigned int height = loader_.GetSlice(0).GetHeight(); - Orthanc::PixelFormat format = loader_.GetSlice(0).GetConverter().GetExpectedPixelFormat(); - LOG(INFO) << "Creating a volume image of size " << width << "x" << height - << "x" << loader_.GetSlicesCount() << " in " << Orthanc::EnumerationToString(format); - - image_.reset(new OrthancStone::ImageBuffer3D(format, width, height, static_cast(loader_.GetSlicesCount()), computeRange_)); - image_->GetGeometry().SetAxialGeometry(loader_.GetSlice(0).GetGeometry()); - image_->GetGeometry().SetVoxelDimensions(loader_.GetSlice(0).GetPixelSpacingX(), - loader_.GetSlice(0).GetPixelSpacingY(), spacingZ); - image_->Clear(); - - downloadStack_.reset(new DownloadStack(static_cast(loader_.GetSlicesCount()))); - pendingSlices_ = loader_.GetSlicesCount(); - - for (unsigned int i = 0; i < 4; i++) // Limit to 4 simultaneous downloads - { - ScheduleSliceDownload(); - } - - // TODO Check the DicomFrameConverter are constant - - BroadcastMessage(ISlicedVolume::GeometryReadyMessage(*this)); - } - - - void OnSliceGeometryError(const OrthancSlicesLoader::SliceGeometryErrorMessage& message) - { - assert(&message.GetOrigin() == &loader_); - - LOG(ERROR) << "Unable to download a volume image"; - BroadcastMessage(ISlicedVolume::GeometryErrorMessage(*this)); - } - - - void OnSliceImageReady(const OrthancSlicesLoader::SliceImageReadyMessage& message) - { - assert(&message.GetOrigin() == &loader_); - - { - OrthancStone::ImageBuffer3D::SliceWriter writer(*image_, OrthancStone::VolumeProjection_Axial, message.GetSliceIndex()); - Orthanc::ImageProcessing::Copy(writer.GetAccessor(), message.GetImage()); - } - - BroadcastMessage(ISlicedVolume::SliceContentChangedMessage - (*this, message.GetSliceIndex(), message.GetSlice())); - - if (pendingSlices_ == 1) - { - BroadcastMessage(ISlicedVolume::VolumeReadyMessage(*this)); - pendingSlices_ = 0; - } - else if (pendingSlices_ > 1) - { - pendingSlices_ -= 1; - } - - ScheduleSliceDownload(); - } - - - void OnSliceImageError(const OrthancSlicesLoader::SliceImageErrorMessage& message) - { - assert(&message.GetOrigin() == &loader_); - - LOG(ERROR) << "Cannot download slice " << message.GetSliceIndex() << " in a volume image"; - ScheduleSliceDownload(); - } - - - public: - OrthancVolumeImage(OrthancStone::MessageBroker& broker, - OrthancApiClient& orthanc, - bool computeRange) : - ISlicedVolume(broker), - IObserver(broker), - loader_(broker, orthanc), - computeRange_(computeRange), - pendingSlices_(0) - { - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &OrthancVolumeImage::OnSliceGeometryReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &OrthancVolumeImage::OnSliceGeometryError)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &OrthancVolumeImage::OnSliceImageReady)); - - loader_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &OrthancVolumeImage::OnSliceImageError)); - } - - void ScheduleLoadSeries(const std::string& seriesId) - { - loader_.ScheduleLoadSeries(seriesId); - } - - void ScheduleLoadInstance(const std::string& instanceId) - { - loader_.ScheduleLoadInstance(instanceId); - } - - void ScheduleLoadFrame(const std::string& instanceId, - unsigned int frame) - { - loader_.ScheduleLoadFrame(instanceId, frame); - } - - virtual size_t GetSlicesCount() const - { - return loader_.GetSlicesCount(); - } - - virtual const Slice& GetSlice(size_t index) const - { - return loader_.GetSlice(index); - } - - OrthancStone::ImageBuffer3D& GetImage() const - { - if (image_.get() == NULL) - { - // The geometry is not ready yet - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - else - { - return *image_; - } - } - - bool FitWindowingToRange(RenderStyle& style, - const DicomFrameConverter& converter) const - { - if (image_.get() == NULL) - { - return false; - } - else - { - return image_->FitWindowingToRange(style, converter); - } - } - }; - - - class VolumeImageGeometry - { - private: - unsigned int width_; - unsigned int height_; - size_t depth_; - double pixelSpacingX_; - double pixelSpacingY_; - double sliceThickness_; - OrthancStone::CoordinateSystem3D reference_; - DicomFrameConverter converter_; - - double ComputeAxialThickness(const OrthancVolumeImage& volume) const - { - double thickness; - - size_t n = volume.GetSlicesCount(); - if (n > 1) - { - const Slice& a = volume.GetSlice(0); - const Slice& b = volume.GetSlice(n - 1); - thickness = ((reference_.ProjectAlongNormal(b.GetGeometry().GetOrigin()) - - reference_.ProjectAlongNormal(a.GetGeometry().GetOrigin())) / - (static_cast(n) - 1.0)); - } - else - { - thickness = volume.GetSlice(0).GetThickness(); - } - - if (thickness <= 0) - { - // The slices should have been sorted with increasing Z - // (along the normal) by the OrthancSlicesLoader - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - else - { - return thickness; - } - } - - void SetupAxial(const OrthancVolumeImage& volume) - { - const Slice& axial = volume.GetSlice(0); - - width_ = axial.GetWidth(); - height_ = axial.GetHeight(); - depth_ = volume.GetSlicesCount(); - - pixelSpacingX_ = axial.GetPixelSpacingX(); - pixelSpacingY_ = axial.GetPixelSpacingY(); - sliceThickness_ = ComputeAxialThickness(volume); - - reference_ = axial.GetGeometry(); - } - - void SetupCoronal(const OrthancVolumeImage& volume) - { - const Slice& axial = volume.GetSlice(0); - double axialThickness = ComputeAxialThickness(volume); - - width_ = axial.GetWidth(); - height_ = static_cast(volume.GetSlicesCount()); - depth_ = axial.GetHeight(); - - pixelSpacingX_ = axial.GetPixelSpacingX(); - pixelSpacingY_ = axialThickness; - sliceThickness_ = axial.GetPixelSpacingY(); - - OrthancStone::Vector origin = axial.GetGeometry().GetOrigin(); - origin += (static_cast(volume.GetSlicesCount() - 1) * - axialThickness * axial.GetGeometry().GetNormal()); - - reference_ = OrthancStone::CoordinateSystem3D(origin, - axial.GetGeometry().GetAxisX(), - - axial.GetGeometry().GetNormal()); - } - - void SetupSagittal(const OrthancVolumeImage& volume) - { - const Slice& axial = volume.GetSlice(0); - double axialThickness = ComputeAxialThickness(volume); - - width_ = axial.GetHeight(); - height_ = static_cast(volume.GetSlicesCount()); - depth_ = axial.GetWidth(); - - pixelSpacingX_ = axial.GetPixelSpacingY(); - pixelSpacingY_ = axialThickness; - sliceThickness_ = axial.GetPixelSpacingX(); - - OrthancStone::Vector origin = axial.GetGeometry().GetOrigin(); - origin += (static_cast(volume.GetSlicesCount() - 1) * - axialThickness * axial.GetGeometry().GetNormal()); - - reference_ = OrthancStone::CoordinateSystem3D(origin, - axial.GetGeometry().GetAxisY(), - axial.GetGeometry().GetNormal()); - } - - public: - VolumeImageGeometry(const OrthancVolumeImage& volume, - OrthancStone::VolumeProjection projection) - { - if (volume.GetSlicesCount() == 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - - converter_ = volume.GetSlice(0).GetConverter(); - - switch (projection) - { - case OrthancStone::VolumeProjection_Axial: - SetupAxial(volume); - break; - - case OrthancStone::VolumeProjection_Coronal: - SetupCoronal(volume); - break; - - case OrthancStone::VolumeProjection_Sagittal: - SetupSagittal(volume); - break; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - } - - size_t GetSlicesCount() const - { - return depth_; - } - - const OrthancStone::Vector& GetNormal() const - { - return reference_.GetNormal(); - } - - bool LookupSlice(size_t& index, - const OrthancStone::CoordinateSystem3D& slice) const - { - bool opposite; - if (!OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, - reference_.GetNormal(), - slice.GetNormal())) - { - return false; - } - - double z = (reference_.ProjectAlongNormal(slice.GetOrigin()) - - reference_.ProjectAlongNormal(reference_.GetOrigin())) / sliceThickness_; - - int s = static_cast(boost::math::iround(z)); - - if (s < 0 || - s >= static_cast(depth_)) - { - return false; - } - else - { - index = static_cast(s); - return true; - } - } - - Slice* GetSlice(size_t slice) const - { - if (slice >= depth_) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - else - { - OrthancStone::CoordinateSystem3D origin(reference_.GetOrigin() + - static_cast(slice) * sliceThickness_ * reference_.GetNormal(), - reference_.GetAxisX(), - reference_.GetAxisY()); - - return new Slice(origin, pixelSpacingX_, pixelSpacingY_, sliceThickness_, - width_, height_, converter_); - } - } - }; - - - - class VolumeImageMPRSlicer : - public IVolumeSlicer, - public OrthancStone::IObserver - { - private: - class RendererFactory : public LayerReadyMessage::IRendererFactory - { - private: - const Orthanc::ImageAccessor& frame_; - const Slice& slice_; - bool isFullQuality_; - - public: - RendererFactory(const Orthanc::ImageAccessor& frame, - const Slice& slice, - bool isFullQuality) : - frame_(frame), - slice_(slice), - isFullQuality_(isFullQuality) - { - } - - virtual ILayerRenderer* CreateRenderer() const - { - return FrameRenderer::CreateRenderer(frame_, slice_, isFullQuality_); - } - }; - - - OrthancVolumeImage& volume_; - std::auto_ptr axialGeometry_; - std::auto_ptr coronalGeometry_; - std::auto_ptr sagittalGeometry_; - - - bool IsGeometryReady() const - { - return axialGeometry_.get() != NULL; - } - - void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) - { - assert(&message.GetOrigin() == &volume_); - - // These 3 values are only used to speed up the IVolumeSlicer - axialGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Axial)); - coronalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Coronal)); - sagittalGeometry_.reset(new VolumeImageGeometry(volume_, OrthancStone::VolumeProjection_Sagittal)); - - BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); - } - - void OnGeometryError(const ISlicedVolume::GeometryErrorMessage& message) - { - assert(&message.GetOrigin() == &volume_); - - BroadcastMessage(IVolumeSlicer::GeometryErrorMessage(*this)); - } - - void OnContentChanged(const ISlicedVolume::ContentChangedMessage& message) - { - assert(&message.GetOrigin() == &volume_); - - BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); - } - - void OnSliceContentChanged(const ISlicedVolume::SliceContentChangedMessage& message) - { - assert(&message.GetOrigin() == &volume_); - - //IVolumeSlicer::OnSliceContentChange(slice); - - // TODO Improve this? - BroadcastMessage(IVolumeSlicer::ContentChangedMessage(*this)); - } - - const VolumeImageGeometry& GetProjectionGeometry(OrthancStone::VolumeProjection projection) - { - if (!IsGeometryReady()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } - - switch (projection) - { - case OrthancStone::VolumeProjection_Axial: - return *axialGeometry_; - - case OrthancStone::VolumeProjection_Sagittal: - return *sagittalGeometry_; - - case OrthancStone::VolumeProjection_Coronal: - return *coronalGeometry_; - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - bool DetectProjection(OrthancStone::VolumeProjection& projection, - const OrthancStone::CoordinateSystem3D& viewportSlice) - { - bool isOpposite; // Ignored - - if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, - viewportSlice.GetNormal(), - axialGeometry_->GetNormal())) - { - projection = OrthancStone::VolumeProjection_Axial; - return true; - } - else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, - viewportSlice.GetNormal(), - sagittalGeometry_->GetNormal())) - { - projection = OrthancStone::VolumeProjection_Sagittal; - return true; - } - else if (OrthancStone::GeometryToolbox::IsParallelOrOpposite(isOpposite, - viewportSlice.GetNormal(), - coronalGeometry_->GetNormal())) - { - projection = OrthancStone::VolumeProjection_Coronal; - return true; - } - else - { - return false; - } - } - - - public: - VolumeImageMPRSlicer(OrthancStone::MessageBroker& broker, - OrthancVolumeImage& volume) : - IVolumeSlicer(broker), - IObserver(broker), - volume_(volume) - { - volume_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &VolumeImageMPRSlicer::OnGeometryReady)); - - volume_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &VolumeImageMPRSlicer::OnGeometryError)); - - volume_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &VolumeImageMPRSlicer::OnContentChanged)); - - volume_.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &VolumeImageMPRSlicer::OnSliceContentChanged)); - } - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE - { - OrthancStone::VolumeProjection projection; - - if (!IsGeometryReady() || - !DetectProjection(projection, viewportSlice)) - { - return false; - } - else - { - // As the slices of the volumic image are arranged in a box, - // we only consider one single reference slice (the one with index 0). - std::auto_ptr slice(GetProjectionGeometry(projection).GetSlice(0)); - slice->GetExtent(points); - - return true; - } - } - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) ORTHANC_OVERRIDE - { - OrthancStone::VolumeProjection projection; - - if (IsGeometryReady() && - DetectProjection(projection, viewportSlice)) - { - const VolumeImageGeometry& geometry = GetProjectionGeometry(projection); - - size_t closest; - - if (geometry.LookupSlice(closest, viewportSlice)) - { - bool isFullQuality = true; // TODO - - std::auto_ptr frame; - - { - OrthancStone::ImageBuffer3D::SliceReader reader(volume_.GetImage(), projection, static_cast(closest)); - - // TODO Transfer ownership if non-axial, to avoid memcpy - frame.reset(Orthanc::Image::Clone(reader.GetAccessor())); - } - - std::auto_ptr slice(geometry.GetSlice(closest)); - - RendererFactory factory(*frame, *slice, isFullQuality); - - BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, slice->GetGeometry())); - return; - } - } - - // Error - OrthancStone::CoordinateSystem3D slice; - BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, slice)); - } - }; - - - class VolumeImageInteractor : - public IWorldSceneInteractor, - public OrthancStone::IObserver - { - private: - SliceViewerWidget& widget_; - OrthancStone::VolumeProjection projection_; - std::auto_ptr slices_; - size_t slice_; - - protected: - void OnGeometryReady(const ISlicedVolume::GeometryReadyMessage& message) - { - if (slices_.get() == NULL) - { - const OrthancVolumeImage& image = - dynamic_cast(message.GetOrigin()); - - slices_.reset(new VolumeImageGeometry(image, projection_)); - SetSlice(slices_->GetSlicesCount() / 2); - - widget_.FitContent(); - } - } - - virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& widget, - const ViewportGeometry& view, - OrthancStone::MouseButton button, - OrthancStone::KeyboardModifiers modifiers, - int viewportX, - int viewportY, - double x, - double y, - IStatusBar* statusBar, - const std::vector& touches) ORTHANC_OVERRIDE - { - return NULL; - } - - virtual void MouseOver(OrthancStone::CairoContext& context, - WorldSceneWidget& widget, - const ViewportGeometry& view, - double x, - double y, - IStatusBar* statusBar) ORTHANC_OVERRIDE - { - } - - virtual void MouseWheel(WorldSceneWidget& widget, - OrthancStone::MouseWheelDirection direction, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) ORTHANC_OVERRIDE - { - int scale = (modifiers & OrthancStone::KeyboardModifiers_Control ? 10 : 1); - - switch (direction) - { - case OrthancStone::MouseWheelDirection_Up: - OffsetSlice(-scale); - break; - - case OrthancStone::MouseWheelDirection_Down: - OffsetSlice(scale); - break; - - default: - break; - } - } - - virtual void KeyPressed(WorldSceneWidget& widget, - OrthancStone::KeyboardKeys key, - char keyChar, - OrthancStone::KeyboardModifiers modifiers, - IStatusBar* statusBar) ORTHANC_OVERRIDE - { - switch (keyChar) - { - case 's': - widget.FitContent(); - break; - - default: - break; - } - } - - public: - VolumeImageInteractor(OrthancStone::MessageBroker& broker, - OrthancVolumeImage& volume, - SliceViewerWidget& widget, - OrthancStone::VolumeProjection projection) : - IObserver(broker), - widget_(widget), - projection_(projection) - { - widget.SetInteractor(*this); - - volume.RegisterObserverCallback( - new OrthancStone::Callable - (*this, &VolumeImageInteractor::OnGeometryReady)); - } - - bool IsGeometryReady() const - { - return slices_.get() != NULL; - } - - size_t GetSlicesCount() const - { - if (slices_.get() == NULL) - { - return 0; - } - else - { - return slices_->GetSlicesCount(); - } - } - - void OffsetSlice(int offset) - { - if (slices_.get() != NULL) - { - int slice = static_cast(slice_) + offset; - - if (slice < 0) - { - slice = 0; - } - - if (slice >= static_cast(slices_->GetSlicesCount())) - { - slice = static_cast(slices_->GetSlicesCount()) - 1; - } - - if (slice != static_cast(slice_)) - { - SetSlice(slice); - } - } - } - - void SetSlice(size_t slice) - { - if (slices_.get() != NULL) - { - slice_ = slice; - - std::auto_ptr tmp(slices_->GetSlice(slice_)); - widget_.SetSlice(tmp->GetGeometry()); - } - } - }; - - - - class ReferenceLineSource : public IVolumeSlicer - { - private: - class RendererFactory : public LayerReadyMessage::IRendererFactory - { - private: - double x1_; - double y1_; - double x2_; - double y2_; - const OrthancStone::CoordinateSystem3D& slice_; - - public: - RendererFactory(double x1, - double y1, - double x2, - double y2, - const OrthancStone::CoordinateSystem3D& slice) : - x1_(x1), - y1_(y1), - x2_(x2), - y2_(y2), - slice_(slice) - { - } - - virtual ILayerRenderer* CreateRenderer() const - { - return new LineLayerRenderer(x1_, y1_, x2_, y2_, slice_); - } - }; - - SliceViewerWidget& otherPlane_; - - public: - ReferenceLineSource(OrthancStone::MessageBroker& broker, - SliceViewerWidget& otherPlane) : - IVolumeSlicer(broker), - otherPlane_(otherPlane) - { - BroadcastMessage(IVolumeSlicer::GeometryReadyMessage(*this)); - } - - virtual bool GetExtent(std::vector& points, - const OrthancStone::CoordinateSystem3D& viewportSlice) - { - return false; - } - - virtual void ScheduleLayerCreation(const OrthancStone::CoordinateSystem3D& viewportSlice) - { - Slice reference(viewportSlice, 0.001); - - OrthancStone::Vector p, d; - - const OrthancStone::CoordinateSystem3D& slice = otherPlane_.GetSlice(); - - // Compute the line of intersection between the two slices - if (!OrthancStone::GeometryToolbox::IntersectTwoPlanes(p, d, - slice.GetOrigin(), slice.GetNormal(), - viewportSlice.GetOrigin(), viewportSlice.GetNormal())) - { - // The two slice are parallel, don't try and display the intersection - BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); - } - else - { - double x1, y1, x2, y2; - viewportSlice.ProjectPoint(x1, y1, p); - viewportSlice.ProjectPoint(x2, y2, p + 1000.0 * d); - - const OrthancStone::Extent2D extent = otherPlane_.GetSceneExtent(); - - if (OrthancStone::GeometryToolbox::ClipLineToRectangle(x1, y1, x2, y2, - x1, y1, x2, y2, - extent.GetX1(), extent.GetY1(), - extent.GetX2(), extent.GetY2())) - { - RendererFactory factory(x1, y1, x2, y2, slice); - BroadcastMessage(IVolumeSlicer::LayerReadyMessage(*this, factory, reference.GetGeometry())); - } - else - { - // Error: Parallel slices - BroadcastMessage(IVolumeSlicer::LayerErrorMessage(*this, reference.GetGeometry())); - } - } - } - }; -} diff -r 529189f399ec -r c35e98d22764 Platforms/Generic/DelayedCallCommand.h --- a/Platforms/Generic/DelayedCallCommand.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Generic/DelayedCallCommand.h Tue May 21 14:27:35 2019 +0200 @@ -23,7 +23,7 @@ #include "IOracleCommand.h" -#include "../../Framework/Toolbox/IDelayedCallExecutor.h" +#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h" #include "../../Framework/Messages/IObservable.h" #include "../../Framework/Messages/ICallable.h" #include "../../Applications/Generic/NativeStoneApplicationContext.h" diff -r 529189f399ec -r c35e98d22764 Platforms/Generic/OracleDelayedCallExecutor.h --- a/Platforms/Generic/OracleDelayedCallExecutor.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Generic/OracleDelayedCallExecutor.h Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #pragma once -#include "../../Framework/Toolbox/IDelayedCallExecutor.h" +#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h" #include "Oracle.h" #include "../../Applications/Generic/NativeStoneApplicationContext.h" #include "DelayedCallCommand.h" diff -r 529189f399ec -r c35e98d22764 Platforms/Generic/OracleWebService.cpp --- a/Platforms/Generic/OracleWebService.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Generic/OracleWebService.cpp Tue May 21 14:27:35 2019 +0200 @@ -20,7 +20,7 @@ #include "OracleWebService.h" -#include "../../Framework/Toolbox/IWebService.h" +#include "../../Framework/Deprecated/Toolbox/IWebService.h" namespace Deprecated { diff -r 529189f399ec -r c35e98d22764 Platforms/Generic/OracleWebService.h --- a/Platforms/Generic/OracleWebService.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Generic/OracleWebService.h Tue May 21 14:27:35 2019 +0200 @@ -21,7 +21,7 @@ #pragma once -#include "../../Framework/Toolbox/BaseWebService.h" +#include "../../Framework/Deprecated/Toolbox/BaseWebService.h" #include "Oracle.h" #include "WebServiceGetCommand.h" #include "WebServicePostCommand.h" diff -r 529189f399ec -r c35e98d22764 Platforms/Generic/WebServiceCommandBase.h --- a/Platforms/Generic/WebServiceCommandBase.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Generic/WebServiceCommandBase.h Tue May 21 14:27:35 2019 +0200 @@ -23,7 +23,7 @@ #include "IOracleCommand.h" -#include "../../Framework/Toolbox/IWebService.h" +#include "../../Framework/Deprecated/Toolbox/IWebService.h" #include "../../Framework/Messages/IObservable.h" #include "../../Framework/Messages/ICallable.h" #include "../../Applications/Generic/NativeStoneApplicationContext.h" diff -r 529189f399ec -r c35e98d22764 Platforms/Wasm/Defaults.cpp --- a/Platforms/Wasm/Defaults.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Wasm/Defaults.cpp Tue May 21 14:27:35 2019 +0200 @@ -2,9 +2,8 @@ #include "WasmWebService.h" #include "WasmDelayedCallExecutor.h" -#include -#include "Framework/Widgets/TestCairoWidget.h" -#include +#include "../../Framework/Deprecated/Widgets/TestCairoWidget.h" +#include #include #include #include diff -r 529189f399ec -r c35e98d22764 Platforms/Wasm/Defaults.h --- a/Platforms/Wasm/Defaults.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Wasm/Defaults.h Tue May 21 14:27:35 2019 +0200 @@ -2,9 +2,8 @@ #include -#include -#include -#include +#include "../../Framework/Deprecated/Viewport/WidgetViewport.h" +#include "../../Framework/Deprecated/Widgets/LayoutWidget.h" #include #include diff -r 529189f399ec -r c35e98d22764 Platforms/Wasm/WasmDelayedCallExecutor.h --- a/Platforms/Wasm/WasmDelayedCallExecutor.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Wasm/WasmDelayedCallExecutor.h Tue May 21 14:27:35 2019 +0200 @@ -1,6 +1,6 @@ #pragma once -#include +#include "../../Framework/Deprecated/Toolbox/IDelayedCallExecutor.h" #include namespace Deprecated diff -r 529189f399ec -r c35e98d22764 Platforms/Wasm/WasmViewport.h --- a/Platforms/Wasm/WasmViewport.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Wasm/WasmViewport.h Tue May 21 14:27:35 2019 +0200 @@ -1,6 +1,6 @@ #pragma once -#include +#include "../../Framework/Deprecated/Viewport/WidgetViewport.h" #include diff -r 529189f399ec -r c35e98d22764 Platforms/Wasm/WasmWebService.h --- a/Platforms/Wasm/WasmWebService.h Tue May 21 13:27:54 2019 +0200 +++ b/Platforms/Wasm/WasmWebService.h Tue May 21 14:27:35 2019 +0200 @@ -1,6 +1,6 @@ #pragma once -#include +#include "../../Framework/Deprecated/Toolbox/BaseWebService.h" #include namespace Deprecated diff -r 529189f399ec -r c35e98d22764 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Tue May 21 13:27:54 2019 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Tue May 21 14:27:35 2019 +0200 @@ -305,7 +305,55 @@ DEPENDS "${ORTHANC_STONE_ROOT}/Platforms/Wasm/default-library.js") endif() + +set(ORTHANC_STONE_DEPRECATED_SOURCES + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/CircleMeasureTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/ColorFrameRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/DicomSeriesVolumeSlicer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/DicomStructureSetSlicer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/FrameRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/GrayscaleFrameRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/IVolumeSlicer.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/LineLayerRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/LineMeasureTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/RenderStyle.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Layers/SliceOutlineRenderer.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/SmartLoader.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/BaseWebService.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/DicomFrameConverter.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/DownloadStack.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IDelayedCallExecutor.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/IWebService.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancApiClient.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/OrthancSlicesLoader.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/Slice.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Toolbox/ViewportGeometry.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IMouseTracker.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IStatusBar.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/IViewport.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Viewport/WidgetViewport.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Volumes/StructureSetLoader.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/CairoWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/EmptyWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWidget.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWorldSceneInteractor.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/IWorldSceneMouseTracker.h + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/LayoutWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/PanMouseTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/PanZoomMouseTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/SliceViewerWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/TestCairoWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/TestWorldSceneWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/WidgetBase.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/WorldSceneWidget.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/Widgets/ZoomMouseTracker.cpp + ${ORTHANC_STONE_ROOT}/Framework/Deprecated/dev.h + ) + + list(APPEND ORTHANC_STONE_SOURCES + ${ORTHANC_STONE_DEPRECATED_SOURCES} + #${ORTHANC_STONE_ROOT}/Framework/Layers/SeriesFrameRendererFactory.cpp #${ORTHANC_STONE_ROOT}/Framework/Layers/SingleFrameRendererFactory.cpp @@ -362,24 +410,13 @@ ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/PointerTypes.h ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.cpp ${ORTHANC_STONE_ROOT}/Framework/Scene2DViewport/ViewportController.h - + ${ORTHANC_STONE_ROOT}/Framework/Fonts/FontRenderer.cpp ${ORTHANC_STONE_ROOT}/Framework/Fonts/Glyph.cpp ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphAlphabet.cpp ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphBitmapAlphabet.cpp ${ORTHANC_STONE_ROOT}/Framework/Fonts/GlyphTextureAlphabet.cpp ${ORTHANC_STONE_ROOT}/Framework/Fonts/TextBoundingBox.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/CircleMeasureTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/ColorFrameRenderer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomSeriesVolumeSlicer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/DicomStructureSetSlicer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/FrameRenderer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/GrayscaleFrameRenderer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/IVolumeSlicer.h - ${ORTHANC_STONE_ROOT}/Framework/Layers/LineLayerRenderer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/LineMeasureTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/RenderStyle.cpp - ${ORTHANC_STONE_ROOT}/Framework/Layers/SliceOutlineRenderer.cpp ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingItemsSorter.cpp ${ORTHANC_STONE_ROOT}/Framework/Loaders/BasicFetchingStrategy.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyAlphaLayer.cpp @@ -398,61 +435,31 @@ ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyTextLayer.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWidget.cpp ${ORTHANC_STONE_ROOT}/Framework/Radiography/RadiographyWindowingTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/SmartLoader.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneEnumerations.cpp ${ORTHANC_STONE_ROOT}/Framework/StoneException.h ${ORTHANC_STONE_ROOT}/Framework/StoneInitialization.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/AffineTransform2D.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/BaseWebService.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/CoordinateSystem3D.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomFrameConverter.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DicomStructureSet.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DownloadStack.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/DynamicBitmap.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Extent2D.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/FiniteProjectiveCamera.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/GeometryToolbox.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IDelayedCallExecutor.h - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/IWebService.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ImageGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/LinearAlgebra.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/MessagingToolbox.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrientedBoundingBox.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrthancApiClient.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/OrthancSlicesLoader.cpp + ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlices.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ParallelSlicesCursor.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ShearWarpProjectiveTransform.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/Slice.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/SlicesSorter.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/UndoRedoStack.cpp - ${ORTHANC_STONE_ROOT}/Framework/Toolbox/ViewportGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Toolbox/VolumeImageGeometry.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoContext.cpp ${ORTHANC_STONE_ROOT}/Framework/Viewport/CairoSurface.cpp - ${ORTHANC_STONE_ROOT}/Framework/Viewport/IMouseTracker.h - ${ORTHANC_STONE_ROOT}/Framework/Viewport/IStatusBar.h - ${ORTHANC_STONE_ROOT}/Framework/Viewport/IViewport.h - ${ORTHANC_STONE_ROOT}/Framework/Viewport/WidgetViewport.cpp ${ORTHANC_STONE_ROOT}/Framework/Volumes/ImageBuffer3D.cpp - ${ORTHANC_STONE_ROOT}/Framework/Volumes/StructureSetLoader.cpp ${ORTHANC_STONE_ROOT}/Framework/Volumes/VolumeReslicer.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/CairoWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/EmptyWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWidget.h - ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneInteractor.h - ${ORTHANC_STONE_ROOT}/Framework/Widgets/IWorldSceneMouseTracker.h - ${ORTHANC_STONE_ROOT}/Framework/Widgets/LayoutWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/PanMouseTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/PanZoomMouseTracker.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/SliceViewerWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestCairoWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/TestWorldSceneWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/WidgetBase.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/WorldSceneWidget.cpp - ${ORTHANC_STONE_ROOT}/Framework/Widgets/ZoomMouseTracker.cpp - - ${ORTHANC_STONE_ROOT}/Framework/dev.h ${ORTHANC_STONE_ROOT}/Framework/Messages/ICallable.h ${ORTHANC_STONE_ROOT}/Framework/Messages/IMessage.h diff -r 529189f399ec -r c35e98d22764 Samples/WebAssembly/BasicScene.cpp --- a/Samples/WebAssembly/BasicScene.cpp Tue May 21 13:27:54 2019 +0200 +++ b/Samples/WebAssembly/BasicScene.cpp Tue May 21 14:27:35 2019 +0200 @@ -153,10 +153,8 @@ void SetupEvents(const std::string& canvas); public: - WebAssemblyViewport(MessageBroker& broker, - const std::string& canvas) : + WebAssemblyViewport(const std::string& canvas) : context_(canvas), - scene_(broker), compositor_(context_, scene_) { compositor_.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, @@ -363,7 +361,6 @@ std::auto_ptr viewport1_; std::auto_ptr viewport2_; std::auto_ptr viewport3_; -OrthancStone::MessageBroker broker_; EM_BOOL OnWindowResize(int eventType, const EmscriptenUiEvent *uiEvent, void *userData) @@ -399,15 +396,15 @@ EMSCRIPTEN_KEEPALIVE void Initialize() { - viewport1_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas1")); + viewport1_.reset(new OrthancStone::WebAssemblyViewport("mycanvas1")); PrepareScene(viewport1_->GetScene()); viewport1_->UpdateSize(); - viewport2_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas2")); + viewport2_.reset(new OrthancStone::WebAssemblyViewport("mycanvas2")); PrepareScene(viewport2_->GetScene()); viewport2_->UpdateSize(); - viewport3_.reset(new OrthancStone::WebAssemblyViewport(broker_, "mycanvas3")); + viewport3_.reset(new OrthancStone::WebAssemblyViewport("mycanvas3")); PrepareScene(viewport3_->GetScene()); viewport3_->UpdateSize(); diff -r 529189f399ec -r c35e98d22764 UnitTestsSources/UnitTestsMain.cpp --- a/UnitTestsSources/UnitTestsMain.cpp Tue May 21 13:27:54 2019 +0200 +++ b/UnitTestsSources/UnitTestsMain.cpp Tue May 21 14:27:35 2019 +0200 @@ -19,14 +19,14 @@ **/ -#include "../Framework/dev.h" #include "gtest/gtest.h" -#include "../Framework/Layers/FrameRenderer.h" -#include "../Framework/Toolbox/DownloadStack.h" +#include "../Framework/Deprecated/Layers/FrameRenderer.h" +#include "../Framework/Deprecated/Toolbox/DownloadStack.h" +#include "../Framework/Deprecated/Toolbox/OrthancSlicesLoader.h" #include "../Framework/Toolbox/FiniteProjectiveCamera.h" +#include "../Framework/Toolbox/GeometryToolbox.h" #include "../Framework/Toolbox/MessagingToolbox.h" -#include "../Framework/Toolbox/OrthancSlicesLoader.h" #include "../Framework/Volumes/ImageBuffer3D.h" #include "../Platforms/Generic/OracleWebService.h" @@ -42,97 +42,6 @@ #include -#if 0 -namespace OrthancStone -{ - class Tata : public OrthancSlicesLoader::ICallback - { - public: - virtual void NotifyGeometryReady(const OrthancSlicesLoader& loader) - { - printf(">> %d\n", (int) loader.GetSliceCount()); - - for (size_t i = 0; i < loader.GetSliceCount(); i++) - { - const_cast(loader).ScheduleLoadSliceImage(i, SliceImageQuality_FullPng); - } - } - - virtual void NotifyGeometryError(const OrthancSlicesLoader& loader) - { - printf("Error\n"); - } - - virtual void NotifySliceImageReady(const OrthancSlicesLoader& loader, - unsigned int sliceIndex, - const Slice& slice, - std::auto_ptr& image, - SliceImageQuality quality) - { - std::auto_ptr tmp(image); - printf("Slice OK %dx%d\n", tmp->GetWidth(), tmp->GetHeight()); - } - - virtual void NotifySliceImageError(const OrthancSlicesLoader& loader, - unsigned int sliceIndex, - const Slice& slice, - SliceImageQuality quality) - { - printf("ERROR 2\n"); - } - }; -} - - -TEST(Toto, DISABLED_Tutu) -{ - OrthancStone::Oracle oracle(4); - oracle.Start(); - - Orthanc::WebServiceParameters web; - //OrthancStone::OrthancAsynchronousWebService orthanc(web, 4); - OrthancStone::OracleWebService orthanc(oracle, web); - //orthanc.Start(); - - OrthancStone::Tata tata; - OrthancStone::OrthancSlicesLoader loader(tata, orthanc); - loader.ScheduleLoadSeries("c1c4cb95-05e3bd11-8da9f5bb-87278f71-0b2b43f5"); - //loader.ScheduleLoadSeries("67f1b334-02c16752-45026e40-a5b60b6b-030ecab5"); - - //loader.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0); - - /*printf(">> %d\n", loader.GetSliceCount()); - loader.ScheduleLoadSliceImage(31);*/ - - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - - //orthanc.Stop(); - oracle.Stop(); -} - - -TEST(Toto, Tata) -{ - OrthancStone::Oracle oracle(4); - oracle.Start(); - - Orthanc::WebServiceParameters web; - OrthancStone::OracleWebService orthanc(oracle, web); - OrthancStone::OrthancVolumeImage volume(orthanc, true); - - //volume.ScheduleLoadInstance("19816330-cb02e1cf-df3a8fe8-bf510623-ccefe9f5", 0); - //volume.ScheduleLoadSeries("318603c5-03e8cffc-a82b6ee1-3ccd3c1e-18d7e3bb"); // COMUNIX PET - //volume.ScheduleLoadSeries("7124dba7-09803f33-98b73826-33f14632-ea842d29"); // COMUNIX CT - //volume.ScheduleLoadSeries("5990e39c-51e5f201-fe87a54c-31a55943-e59ef80e"); // Delphine sagital - volume.ScheduleLoadSeries("6f1b492a-e181e200-44e51840-ef8db55e-af529ab6"); // Delphine ax 2.5 - - boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); - - oracle.Stop(); -} -#endif - - TEST(GeometryToolbox, Interpolation) { using namespace OrthancStone::GeometryToolbox;