Mercurial > hg > orthanc-stone
view Framework/Widgets/LayerWidget.cpp @ 69:1553b67b24e5 wasm
OrthancSynchronousWebService
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 22 May 2017 20:35:11 +0200 |
parents | 298f375dcb68 |
children | 30c768873d47 |
line wrap: on
line source
/** * Stone of Orthanc * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium * Copyright (C) 2017 Osimis, 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 "LayerWidget.h" #include "../../Resources/Orthanc/Core/Logging.h" namespace OrthancStone { class LayerWidget::Scene : public boost::noncopyable { private: SliceGeometry slice_; size_t countMissing_; std::vector<ILayerRenderer*> renderers_; 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_++; } } public: Scene(const SliceGeometry& slice, size_t countLayers) : slice_(slice), countMissing_(countLayers), renderers_(countLayers, NULL) { } ~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 SliceGeometry& GetSlice() const { return slice_; } bool IsComplete() const { return countMissing_ == 0; } bool IsSamePlane(const SliceGeometry& slice, double sliceThickness) { return slice_.IsSamePlane(slice, sliceThickness); } bool RenderScene(CairoContext& context, const ViewportGeometry& view) { bool fullQuality = true; for (size_t i = 0; i < renderers_.size(); i++) { if (renderers_[i] != NULL && !renderers_[i]->RenderLayer(context, view)) { return false; } if (renderers_[i] != NULL && !renderers_[i]->IsFullQuality()) { fullQuality = false; } } if (!fullQuality) { double x, y; view.MapDisplayToScene(x, y, static_cast<double>(view.GetDisplayWidth()) / 2.0, 10); cairo_t *cr = context.GetObject(); cairo_translate(cr, x, y); cairo_arc(cr, 0, 0, 5.0 / view.GetZoom(), 0, 2 * M_PI); 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 LayerWidget::LookupLayer(size_t& index /* out */, ILayerSource& 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 LayerWidget::GetSceneExtent(double& x1, double& y1, double& x2, double& y2) { bool first = true; for (size_t i = 0; i < layers_.size(); i++) { double ax, ay, bx, by; assert(layers_[i] != NULL); if (layers_[i]->GetExtent(ax, ay, bx, by, slice_)) { if (ax > bx) { std::swap(ax, bx); } if (ay > by) { std::swap(ay, by); } //LOG(INFO) << "Extent of layer " << i << ": (" << ax << "," << ay << ")->(" << bx << "," << by << ")"; printf("Extent %d: (%f,%f) -> (%f,%f)\n", (int) i, ax, ay, bx, by); if (first) { x1 = ax; y1 = ay; x2 = bx; y2 = by; first = false; } else { x1 = std::min(x1, ax); y1 = std::min(y1, ay); x2 = std::max(x2, bx); y2 = std::max(y2, by); } } } if (first) { // Set a default extent of (-1,-1) -> (0,0) x1 = -1; y1 = -1; x2 = 1; y2 = 1; } // Ensure the extent is non-empty if (x1 >= x2) { double tmp = x1; x1 = tmp - 0.5; x2 = tmp + 0.5; } if (y1 >= y2) { double tmp = y1; y1 = tmp - 0.5; y2 = tmp + 0.5; } } bool LayerWidget::RenderScene(CairoContext& context, const ViewportGeometry& view) { if (currentScene_.get() != NULL) { return currentScene_->RenderScene(context, view); } else { return true; } } void LayerWidget::ResetPendingScene() { pendingScene_.reset(new Scene(slice_, layers_.size())); } void LayerWidget::UpdateLayer(size_t index, ILayerRenderer* renderer, const SliceGeometry& slice) { printf("Updating layer %d\n", (int) index); std::auto_ptr<ILayerRenderer> 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_->IsSamePlane(slice, sliceThickness_)) { currentScene_->SetLayer(index, tmp.release()); NotifyChange(); } else if (pendingScene_.get() != NULL && pendingScene_->IsSamePlane(slice, sliceThickness_)) { pendingScene_->SetLayer(index, tmp.release()); if (currentScene_.get() == NULL || pendingScene_->IsComplete()) { currentScene_ = pendingScene_; NotifyChange(); } } } LayerWidget::LayerWidget() : started_(false), sliceThickness_(1) { SetBackgroundCleared(true); } LayerWidget::~LayerWidget() { for (size_t i = 0; i < layers_.size(); i++) { delete layers_[i]; } } size_t LayerWidget::AddLayer(ILayerSource* 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(); layer->SetObserver(*this); return index; } void LayerWidget::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); } NotifyChange(); } void LayerWidget::SetSlice(const SliceGeometry& slice, double sliceThickness) { if (!slice_.IsSamePlane(slice, 100.0 * std::numeric_limits<double>::epsilon())) { if (currentScene_.get() == NULL || (pendingScene_.get() != NULL && pendingScene_->IsComplete())) { currentScene_ = pendingScene_; } slice_ = slice; sliceThickness_ = sliceThickness; ResetPendingScene(); if (started_) { for (size_t i = 0; i < layers_.size(); i++) { assert(layers_[i] != NULL); layers_[i]->ScheduleLayerCreation(slice_); } } } } void LayerWidget::NotifyGeometryReady(ILayerSource& source) { size_t i; if (LookupLayer(i, source)) printf("Geometry ready for layer %d\n", (int) i); SetDefaultView(); layers_[i]->ScheduleLayerCreation(slice_); } void LayerWidget::NotifySourceChange(ILayerSource& source) { source.ScheduleLayerCreation(slice_); } void LayerWidget::NotifySliceChange(ILayerSource& source, const SliceGeometry& slice) { if (slice_.IsSamePlane(slice, sliceThickness_)) { source.ScheduleLayerCreation(slice_); } } void LayerWidget::NotifyLayerReady(ILayerRenderer* renderer, ILayerSource& source, const SliceGeometry& viewportSlice) { std::auto_ptr<ILayerRenderer> tmp(renderer); size_t i; if (LookupLayer(i, source)) printf("Renderer ready for layer %d\n", (int) i); size_t index; if (LookupLayer(index, source)) { UpdateLayer(index, tmp.release(), viewportSlice); } } void LayerWidget::NotifyLayerError(ILayerSource& source, const SliceGeometry& viewportSlice) { size_t i; if (LookupLayer(i, source)) LOG(ERROR) << "Error on layer " << i; } void LayerWidget::Start() { if (started_) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } for (size_t i = 0; i < layers_.size(); i++) { assert(layers_[i] != NULL); layers_[i]->Start(); } } }