Mercurial > hg > orthanc-stone
diff Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp @ 319:daa04d15192c am-2
new SimpleViewer sample that has been split in multiple files to be able to scale it
author | am@osimis.io |
---|---|
date | Thu, 11 Oct 2018 13:16:54 +0200 |
parents | |
children | 56b2e47d3c0c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp Thu Oct 11 13:16:54 2018 +0200 @@ -0,0 +1,238 @@ +/** + * 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 <http://www.gnu.org/licenses/>. + **/ + + +#include "SimpleViewerApplication.h" + +#if ORTHANC_ENABLE_QT==1 +#include "Qt/SimpleViewerMainWindow.h" +#endif + +#if ORTHANC_ENABLE_WASM==1 +#include <Platforms/Wasm/WasmViewport.h> +#endif + +namespace SimpleViewer { + + void SimpleViewerApplication::Initialize(StoneApplicationContext* context, + IStatusBar& statusBar, + const boost::program_options::variables_map& parameters) + { + using namespace OrthancStone; + + context_ = context; + statusBar_ = &statusBar; + + {// initialize viewports and layout + mainLayout_ = new LayoutWidget("main-layout"); + mainLayout_->SetPadding(10); + mainLayout_->SetBackgroundCleared(true); + mainLayout_->SetBackgroundColor(0, 0, 0); + mainLayout_->SetHorizontal(); + + thumbnailsLayout_ = new LayoutWidget("thumbnail-layout"); + thumbnailsLayout_->SetPadding(10); + thumbnailsLayout_->SetBackgroundCleared(true); + thumbnailsLayout_->SetBackgroundColor(50, 50, 50); + thumbnailsLayout_->SetVertical(); + + mainWidget_ = new LayerWidget(IObserver::broker_, "main-viewport"); + //mainWidget_->RegisterObserver(*this); + + // hierarchy + mainLayout_->AddWidget(thumbnailsLayout_); + mainLayout_->AddWidget(mainWidget_); + + orthancApiClient_.reset(new OrthancApiClient(IObserver::broker_, context_->GetWebService())); + + // sources + smartLoader_.reset(new SmartLoader(IObserver::broker_, *orthancApiClient_)); + smartLoader_->SetImageQuality(SliceImageQuality_FullPam); + + mainLayout_->SetTransmitMouseOver(true); + mainWidgetInteractor_.reset(new MainWidgetInteractor(*this)); + mainWidget_->SetInteractor(*mainWidgetInteractor_); + thumbnailInteractor_.reset(new ThumbnailInteractor(*this)); + } + + statusBar.SetMessage("Use the key \"s\" to reinitialize the layout"); + statusBar.SetMessage("Use the key \"n\" to go to next image in the main viewport"); + + + if (parameters.count("studyId") < 1) + { + LOG(WARNING) << "The study ID is missing, will take the first studyId found in Orthanc"; + orthancApiClient_->GetJsonAsync("/studies", new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyListReceived)); + } + else + { + SelectStudy(parameters["studyId"].as<std::string>()); + } + } + + + void SimpleViewerApplication::DeclareStartupOptions(boost::program_options::options_description& options) + { + boost::program_options::options_description generic("Sample options"); + generic.add_options() + ("studyId", boost::program_options::value<std::string>(), + "Orthanc ID of the study") + ; + + options.add(generic); + } + + void SimpleViewerApplication::OnStudyListReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.Response; + + if (response.isArray() && response.size() > 1) + { + SelectStudy(response[0].asString()); + } + } + void SimpleViewerApplication::OnStudyReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.Response; + + if (response.isObject() && response["Series"].isArray()) + { + for (size_t i=0; i < response["Series"].size(); i++) + { + orthancApiClient_->GetJsonAsync("/series/" + response["Series"][(int)i].asString(), new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnSeriesReceived)); + } + } + } + + void SimpleViewerApplication::OnSeriesReceived(const OrthancApiClient::JsonResponseReadyMessage& message) + { + const Json::Value& response = message.Response; + + if (response.isObject() && response["Instances"].isArray() && response["Instances"].size() > 0) + { + // keep track of all instances IDs + const std::string& seriesId = response["ID"].asString(); + seriesTags_[seriesId] = response; + instancesIdsPerSeriesId_[seriesId] = std::vector<std::string>(); + for (size_t i = 0; i < response["Instances"].size(); i++) + { + const std::string& instanceId = response["Instances"][static_cast<int>(i)].asString(); + instancesIdsPerSeriesId_[seriesId].push_back(instanceId); + } + + // load the first instance in the thumbnail + LoadThumbnailForSeries(seriesId, instancesIdsPerSeriesId_[seriesId][0]); + + // if this is the first thumbnail loaded, load the first instance in the mainWidget + if (mainWidget_->GetLayerCount() == 0) + { + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); + } + } + } + + void SimpleViewerApplication::LoadThumbnailForSeries(const std::string& seriesId, const std::string& instanceId) + { + LOG(INFO) << "Loading thumbnail for series " << seriesId; + LayerWidget* thumbnailWidget = new LayerWidget(IObserver::broker_, "thumbnail-series-" + seriesId); + thumbnails_.push_back(thumbnailWidget); + thumbnailsLayout_->AddWidget(thumbnailWidget); + thumbnailWidget->RegisterObserverCallback(new Callable<SimpleViewerApplication, LayerWidget::GeometryChangedMessage>(*this, &SimpleViewerApplication::OnWidgetGeometryChanged)); + smartLoader_->SetFrameInWidget(*thumbnailWidget, 0, instanceId, 0); + thumbnailWidget->SetInteractor(*thumbnailInteractor_); + } + + void SimpleViewerApplication::SelectStudy(const std::string& studyId) + { + orthancApiClient_->GetJsonAsync("/studies/" + studyId, new Callable<SimpleViewerApplication, OrthancApiClient::JsonResponseReadyMessage>(*this, &SimpleViewerApplication::OnStudyReceived)); + } + + void SimpleViewerApplication::OnWidgetGeometryChanged(const LayerWidget::GeometryChangedMessage& message) + { + message.origin_.SetDefaultView(); + } + + void SimpleViewerApplication::SelectSeriesInMainViewport(const std::string& seriesId) + { + smartLoader_->SetFrameInWidget(*mainWidget_, 0, instancesIdsPerSeriesId_[seriesId][0], 0); + } + + + + void SimpleViewerApplication::ExecuteCommand(ICommand& command) + { + statusBar_->SetMessage("received command: " + std::string(command.GetName())); + if (command.GetName() == "selectTool:circle-measure") + { + SelectTool(Tools_CircleMeasure); + } + else if (command.GetName() == "selectTool:line-measure") + { + SelectTool(Tools_LineMeasure); + } + else if (command.GetName() == "selectTool:crop") + { + SelectTool(Tools_Crop); + } + else if (command.GetName() == "selectTool:windowing") + { + SelectTool(Tools_Windowing); + } + else if (command.GetName() == "action:rotate") + { + ExecuteAction(Actions_Rotate); + } + else if (command.GetName() == "action:invert") + { + ExecuteAction(Actions_Invert); + } + else + { + command.Execute(); + } + } + + void SimpleViewerApplication::ExecuteAction(SimpleViewerApplication::Actions action) + { + // TODO + } + + void SimpleViewerApplication::SelectTool(SimpleViewerApplication::Tools tool) + { + currentTool_ = tool; + } + +#if ORTHANC_ENABLE_QT==1 + QStoneMainWindow* SimpleViewerApplication::CreateQtMainWindow() + { + return new SimpleViewerMainWindow(dynamic_cast<OrthancStone::NativeStoneApplicationContext&>(*context_), *this); + } +#endif + +#if ORTHANC_ENABLE_WASM==1 + void SimpleViewerApplication::InitializeWasm() { + + AttachWidgetToWasmViewport("canvasThumbnails", thumbnailsLayout_); + AttachWidgetToWasmViewport("canvasMain", mainWidget_); + } +#endif + + +}