diff --git a/Modules/ROI/src/mitkROIMapper2D.cpp b/Modules/ROI/src/mitkROIMapper2D.cpp index 1435d4c6d7..035249e7e8 100644 --- a/Modules/ROI/src/mitkROIMapper2D.cpp +++ b/Modules/ROI/src/mitkROIMapper2D.cpp @@ -1,187 +1,186 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include "mitkROIMapperHelper.h" #include #include #include #include #include +#include #include #include namespace { mitk::Point3D GetBottomLeftPoint(vtkPoints* points, mitk::BaseRenderer* renderer) { mitk::Point3D point = points->GetPoint(0); mitk::Point2D bottomLeftDisplayPoint; renderer->WorldToDisplay(point, bottomLeftDisplayPoint); auto numPoints = points->GetNumberOfPoints(); mitk::Point2D displayPoint; for (decltype(numPoints) i = 1; i < numPoints; ++i) { point.FillPoint(points->GetPoint(i)); renderer->WorldToDisplay(point, displayPoint); bottomLeftDisplayPoint[0] = std::min(bottomLeftDisplayPoint[0], displayPoint[0]); bottomLeftDisplayPoint[1] = std::min(bottomLeftDisplayPoint[1], displayPoint[1]); } renderer->DisplayToWorld(bottomLeftDisplayPoint, point); return point; } } mitk::ROIMapper2D::LocalStorage::LocalStorage() { } mitk::ROIMapper2D::LocalStorage::~LocalStorage() { } const mitk::PlaneGeometry* mitk::ROIMapper2D::LocalStorage::GetLastPlaneGeometry() const { return m_LastPlaneGeometry; } void mitk::ROIMapper2D::LocalStorage::SetLastPlaneGeometry(const PlaneGeometry* planeGeometry) { m_LastPlaneGeometry = planeGeometry; } void mitk::ROIMapper2D::SetDefaultProperties(DataNode* node, BaseRenderer* renderer, bool override) { Superclass::SetDefaultProperties(node, renderer, override); ROIMapperHelper::SetDefaultProperties(node, renderer, override); } mitk::ROIMapper2D::ROIMapper2D() { } mitk::ROIMapper2D::~ROIMapper2D() { } void mitk::ROIMapper2D::GenerateDataForRenderer(BaseRenderer* renderer) { const auto timePoint = renderer->GetWorldTimeGeometry()->TimeStepToTimePoint(renderer->GetTimeStep()); const auto* planeGeometry = renderer->GetCurrentWorldPlaneGeometry(); auto* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); const auto* dataNode = this->GetDataNode(); if (localStorage->GetLastPlaneGeometry() != nullptr && localStorage->GetLastPlaneGeometry()->IsOnPlane(planeGeometry) && localStorage->GetLastGenerateDataTime() >= dataNode->GetMTime() && localStorage->GetLastTimePoint() == timePoint) { return; } localStorage->SetLastPlaneGeometry(planeGeometry->Clone()); localStorage->SetLastTimePoint(timePoint); auto data = static_cast(this->GetData()); if (!data->GetTimeGeometry()->IsValidTimePoint(timePoint)) return; const auto t = data->GetTimeGeometry()->TimePointToTimeStep(timePoint); auto propAssembly = vtkSmartPointer::New(); if (dataNode->IsVisible(renderer)) { const auto* geometry = data->GetGeometry(t); - const auto halfSpacing = geometry->GetSpacing() * 0.5f; auto plane = vtkSmartPointer::New(); plane->SetOrigin(planeGeometry->GetOrigin().data()); plane->SetNormal(planeGeometry->GetNormal().data()); for (const auto& [id, roi] : *data) { if (!roi.HasTimeStep(t)) continue; - Point3D min; - geometry->IndexToWorld(roi.GetMin(t), min); - min -= halfSpacing; - - Point3D max; - geometry->IndexToWorld(roi.GetMax(t), max); - max += halfSpacing; + Point3D min = roi.GetMin(t); + Point3D max = roi.GetMax(t); auto cube = vtkSmartPointer::New(); cube->SetBounds(min[0], max[0], min[1], max[1], min[2], max[2]); + auto transform = vtkSmartPointer::New(); + transform->SetTransform(geometry->GetVtkTransform()); + transform->SetInputConnection(cube->GetOutputPort()); + auto cutter = vtkSmartPointer::New(); - cutter->SetInputConnection(cube->GetOutputPort()); + cutter->SetInputConnection(transform->GetOutputPort()); cutter->SetPlane(plane); cutter->Update(); auto* slicePolyData = cutter->GetOutput(); if (slicePolyData->GetNumberOfLines() == 0) continue; auto mapper = vtkSmartPointer::New(); mapper->SetInputConnection(cutter->GetOutputPort()); auto actor = vtkSmartPointer::New(); actor->SetMapper(mapper); this->ApplyColorAndOpacityProperties(renderer, actor); ROIMapperHelper::ApplyIndividualProperties(roi, t, actor); propAssembly->AddPart(actor); if (std::string caption; dataNode->GetStringProperty("caption", caption, renderer)) { caption = ROIMapperHelper::ParseCaption(caption, roi, t); if (!caption.empty()) { auto bottomLeftPoint = GetBottomLeftPoint(slicePolyData->GetPoints(), renderer); auto captionActor = ROIMapperHelper::CreateCaptionActor(caption, bottomLeftPoint, actor->GetProperty(), dataNode, renderer); propAssembly->AddPart(captionActor); } } } } localStorage->SetPropAssembly(propAssembly); localStorage->UpdateGenerateDataTime(); } void mitk::ROIMapper2D::ApplyColorAndOpacityProperties(BaseRenderer* renderer, vtkActor* actor) { auto* property = actor->GetProperty(); float opacity = 1.0f; this->GetDataNode()->GetOpacity(opacity, renderer); property->SetOpacity(opacity); } vtkProp* mitk::ROIMapper2D::GetVtkProp(BaseRenderer* renderer) { return m_LocalStorageHandler.GetLocalStorage(renderer)->GetPropAssembly(); } diff --git a/Modules/ROI/src/mitkROIMapper3D.cpp b/Modules/ROI/src/mitkROIMapper3D.cpp index e8120de0e3..06425a8cdc 100644 --- a/Modules/ROI/src/mitkROIMapper3D.cpp +++ b/Modules/ROI/src/mitkROIMapper3D.cpp @@ -1,118 +1,116 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include "mitkROIMapperHelper.h" #include #include #include #include +#include mitk::ROIMapper3D::LocalStorage::LocalStorage() { } mitk::ROIMapper3D::LocalStorage::~LocalStorage() { } void mitk::ROIMapper3D::SetDefaultProperties(DataNode* node, BaseRenderer* renderer, bool override) { Superclass::SetDefaultProperties(node, renderer, override); ROIMapperHelper::SetDefaultProperties(node, renderer, override); } mitk::ROIMapper3D::ROIMapper3D() { } mitk::ROIMapper3D::~ROIMapper3D() { } void mitk::ROIMapper3D::GenerateDataForRenderer(BaseRenderer* renderer) { const auto timePoint = renderer->GetWorldTimeGeometry()->TimeStepToTimePoint(renderer->GetTimeStep()); auto* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); const auto* dataNode = this->GetDataNode(); if (localStorage->GetLastGenerateDataTime() >= dataNode->GetMTime() && localStorage->GetLastTimePoint() == timePoint) { return; } localStorage->SetLastTimePoint(timePoint); auto data = static_cast(this->GetData()); if (!data->GetTimeGeometry()->IsValidTimePoint(timePoint)) return; const auto t = data->GetTimeGeometry()->TimePointToTimeStep(timePoint); auto propAssembly = vtkSmartPointer::New(); if (dataNode->IsVisible(renderer)) { const auto* geometry = data->GetGeometry(); - const auto halfSpacing = geometry->GetSpacing() * 0.5f; for (const auto& [id, roi] : *data) { if (!roi.HasTimeStep(t)) continue; - Point3D min; - geometry->IndexToWorld(roi.GetMin(t), min); - min -= halfSpacing; - - Point3D max; - geometry->IndexToWorld(roi.GetMax(t), max); - max += halfSpacing; + Point3D min = roi.GetMin(t); + Point3D max = roi.GetMax(t); auto cube = vtkSmartPointer::New(); cube->SetBounds(min[0], max[0], min[1], max[1], min[2], max[2]); - cube->Update(); + + auto transform = vtkSmartPointer::New(); + transform->SetTransform(geometry->GetVtkTransform()); + transform->SetInputConnection(cube->GetOutputPort()); auto mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(cube->GetOutputPort()); + mapper->SetInputConnection(transform->GetOutputPort()); auto actor = vtkSmartPointer::New(); actor->SetMapper(mapper); this->ApplyColorAndOpacityProperties(renderer, actor); ROIMapperHelper::ApplyIndividualProperties(roi, t, actor); propAssembly->AddPart(actor); } } localStorage->SetPropAssembly(propAssembly); localStorage->UpdateGenerateDataTime(); } void mitk::ROIMapper3D::ApplyColorAndOpacityProperties(BaseRenderer* renderer, vtkActor* actor) { auto* property = actor->GetProperty(); float opacity = 1.0f; this->GetDataNode()->GetOpacity(opacity, renderer); property->SetOpacity(opacity); } vtkProp* mitk::ROIMapper3D::GetVtkProp(BaseRenderer* renderer) { return m_LocalStorageHandler.GetLocalStorage(renderer)->GetPropAssembly(); } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkConvertGeometryDataToROIAction.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkConvertGeometryDataToROIAction.cpp index f982b5807e..33fe0dd3f5 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkConvertGeometryDataToROIAction.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkConvertGeometryDataToROIAction.cpp @@ -1,189 +1,139 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkConvertGeometryDataToROIAction.h" #include #include #include #include #include namespace { void HandleInvalidNodeSelection() { auto message = QStringLiteral( - "All selected bounding boxes must be child nodes of a single common reference image " - "with a non-rotated geometry!"); + "All selected bounding boxes must be child nodes of a single common reference image!"); MITK_ERROR << message; QMessageBox::warning(nullptr, QStringLiteral("Convert to ROI"), message); } - bool IsRotated(const mitk::BaseGeometry* geometry) - { - auto matrix = geometry->GetVtkMatrix(); - - for (int j = 0; j < 3; ++j) - { - for (int i = 0; i < 3; ++i) - { - if (i != j && std::abs(matrix->GetElement(i, j)) > mitk::eps) - return true; - } - } - - return false; - } - - void FlipAxis(mitk::BaseGeometry* geometry, int axis) - { - auto matrix = geometry->GetVtkMatrix(); - matrix->SetElement(axis, axis, -matrix->GetElement(axis, axis)); - matrix->SetElement(axis, 3, matrix->GetElement(axis, 3) - geometry->GetExtentInMM(axis)); - - geometry->SetIndexToWorldTransformByVtkMatrix(matrix); - - auto bounds = geometry->GetBounds(); - int minIndex = 2 * axis; - bounds[minIndex] *= -1; - bounds[minIndex + 1] += 2 * bounds[minIndex]; - - geometry->SetBounds(bounds); - } - - mitk::BaseGeometry::Pointer RectifyGeometry(const mitk::BaseGeometry* geometry) - { - auto rectifiedGeometry = geometry->Clone(); - auto matrix = rectifiedGeometry->GetVtkMatrix(); - - for (int axis = 0; axis < 3; ++axis) - { - if (matrix->GetElement(axis, axis) < 0.0) - FlipAxis(rectifiedGeometry, axis); - } - - return rectifiedGeometry; - } - std::pair, mitk::DataNode*> GetValidInput(const QList& selectedNodes, const mitk::DataStorage* dataStorage) { std::pair, mitk::DataNode*> result; result.first.reserve(selectedNodes.size()); std::copy_if(selectedNodes.cbegin(), selectedNodes.cend(), std::back_inserter(result.first), [](const mitk::DataNode* node) { return node != nullptr && dynamic_cast(node->GetData()) != nullptr; }); for (auto node : result.first) { auto sourceNodes = dataStorage->GetSources(node, mitk::TNodePredicateDataType::New()); if (sourceNodes->size() != 1) mitkThrow(); if (result.second == nullptr) { - auto geometry = sourceNodes->front()->GetData()->GetGeometry(); - - if (IsRotated(geometry)) - mitkThrow(); - result.second = sourceNodes->front(); } else if (result.second != sourceNodes->front()) { mitkThrow(); } } return result; } } QmitkConvertGeometryDataToROIAction::QmitkConvertGeometryDataToROIAction() { } QmitkConvertGeometryDataToROIAction::~QmitkConvertGeometryDataToROIAction() { } void QmitkConvertGeometryDataToROIAction::Run(const QList& selectedNodes) { try { auto [nodes, referenceNode] = GetValidInput(selectedNodes, m_DataStorage); auto roi = mitk::ROI::New(); - roi->SetGeometry(RectifyGeometry(referenceNode->GetData()->GetGeometry())); + roi->SetGeometry(referenceNode->GetData()->GetGeometry()); unsigned int id = 0; for (auto node : nodes) { mitk::ROI::Element element(id++); element.SetProperty("name", mitk::StringProperty::New(node->GetName())); if (auto* color = node->GetProperty("Bounding Shape.Deselected Color"); color != nullptr) element.SetProperty("color", color); - auto geometry = RectifyGeometry(node->GetData()->GetGeometry()); - const auto origin = geometry->GetOrigin() - roi->GetGeometry()->GetOrigin(); - const auto spacing = geometry->GetSpacing(); + const auto* geometry = node->GetData()->GetGeometry(); + + mitk::Vector3D origin = geometry->GetOrigin() - roi->GetGeometry()->GetOrigin(); + geometry->WorldToIndex(origin, origin); + const auto bounds = geometry->GetBounds(); mitk::Point3D min; mitk::Point3D max; for (size_t i = 0; i < 3; ++i) { - min[i] = origin[i] / spacing[i] + bounds[2 * i]; - max[i] = origin[i] / spacing[i] + bounds[2 * i + 1] - 1; + min[i] = origin[i] + bounds[2 * i] - 0.5; + max[i] = origin[i] + bounds[2 * i + 1] - 1 + 0.5; } element.SetMin(min); element.SetMax(max); roi->AddElement(element); } auto roiNode = mitk::DataNode::New(); roiNode->SetName(referenceNode->GetName() + " ROI" + (roi->GetNumberOfElements() > 1 ? "s" : "")); roiNode->SetData(roi); m_DataStorage->Add(roiNode, referenceNode); } catch (const mitk::Exception&) { HandleInvalidNodeSelection(); } } void QmitkConvertGeometryDataToROIAction::SetDataStorage(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; } void QmitkConvertGeometryDataToROIAction::SetFunctionality(berry::QtViewPart*) { } void QmitkConvertGeometryDataToROIAction::SetSmoothed(bool) { } void QmitkConvertGeometryDataToROIAction::SetDecimated(bool) { }