diff --git a/Modules/BoundingShape/src/Interactions/mitkBoundingShapeInteractor.cpp b/Modules/BoundingShape/src/Interactions/mitkBoundingShapeInteractor.cpp index 6b7c381207..bde8116d47 100644 --- a/Modules/BoundingShape/src/Interactions/mitkBoundingShapeInteractor.cpp +++ b/Modules/BoundingShape/src/Interactions/mitkBoundingShapeInteractor.cpp @@ -1,613 +1,613 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "../DataManagement/mitkBoundingShapeUtil.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "usGetModuleContext.h" #include "usModuleRegistry.h" // Properties to allow the user to interact with the base data const char *selectedColorPropertyName = "Bounding Shape.Selected Color"; const char *deselectedColorPropertyName = "Bounding Shape.Deselected Color"; const char *activeHandleIdPropertyName = "Bounding Shape.Active Handle ID"; const char *boundingShapePropertyName = "Bounding Shape"; namespace mitk { class BoundingShapeInteractor::Impl { public: Impl() : ScrollEnabled(false), RotationEnabled(false) { Point3D initialPoint; initialPoint.Fill(0.0); for (int i = 0; i < 6; ++i) Handles.push_back(Handle(initialPoint, i, GetHandleIndices(i))); } ~Impl() {} bool ScrollEnabled; Point3D InitialPickedWorldPoint; Point3D LastPickedWorldPoint; Point2D InitialPickedDisplayPoint; std::vector Handles; Handle ActiveHandle; Geometry3D::Pointer OriginalGeometry; bool RotationEnabled; std::map DisplayInteractorConfigs; }; } mitk::BoundingShapeInteractor::BoundingShapeInteractor() : m_Impl(new Impl) { } mitk::BoundingShapeInteractor::~BoundingShapeInteractor() { this->RestoreNodeProperties(); delete m_Impl; } void mitk::BoundingShapeInteractor::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually // executing an action CONNECT_CONDITION("isHoveringOverObject", CheckOverObject); CONNECT_CONDITION("isHoveringOverHandles", CheckOverHandles); // **Function** in the statemachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectObject", SelectObject); CONNECT_FUNCTION("deselectObject", DeselectObject); CONNECT_FUNCTION("deselectHandles", DeselectHandles); CONNECT_FUNCTION("initInteraction", InitInteraction); CONNECT_FUNCTION("translateObject", TranslateObject); CONNECT_FUNCTION("selectHandle", SelectHandle); CONNECT_FUNCTION("scaleObject", ScaleObject); // CONNECT_FUNCTION("rotateObject",RotateObject); } // RotateObject(StateMachineAction*, InteractionEvent* interactionEvent) // void mitk::BoundingShapeInteractor::RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry* // geometry) //{ // mitk::Vector3D rotationAxis = geometry->GetAxisVector(rotationaxis); // float pointX = 0.0f; // float pointY = 0.0f; // float pointZ = 0.0f; // mitk::Point3D pointOfRotation; // pointOfRotation.Fill(0.0); // this->GetDataNode()->GetFloatProperty(anchorPointX, pointX); // this->GetDataNode()->GetFloatProperty(anchorPointY, pointY); // this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ); // pointOfRotation[0] = pointX; // pointOfRotation[1] = pointY; // pointOfRotation[2] = pointZ; // // mitk::RotationOperation* doOp = new mitk::RotationOperation(OpROTATE, pointOfRotation, rotationAxis, angle); // // geometry->ExecuteOperation(doOp); // delete doOp; //} void mitk::BoundingShapeInteractor::SetRotationEnabled(bool rotationEnabled) { m_Impl->RotationEnabled = rotationEnabled; } void mitk::BoundingShapeInteractor::DataNodeChanged() { mitk::DataNode::Pointer newInputNode = this->GetDataNode(); if (newInputNode == nullptr) return; // add color properties mitk::ColorProperty::Pointer selectedColor = dynamic_cast(newInputNode->GetProperty(selectedColorPropertyName)); mitk::ColorProperty::Pointer deselectedColor = dynamic_cast(newInputNode->GetProperty(deselectedColorPropertyName)); if (selectedColor.IsNull()) newInputNode->AddProperty(selectedColorPropertyName, mitk::ColorProperty::New(0.0, 1.0, 0.0)); if (deselectedColor.IsNull()) newInputNode->AddProperty(deselectedColorPropertyName, mitk::ColorProperty::New(1.0, 1.0, 1.0)); newInputNode->SetProperty(boundingShapePropertyName, mitk::BoolProperty::New(true)); newInputNode->AddProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1)); newInputNode->SetProperty("layer", mitk::IntProperty::New(101)); newInputNode->SetBoolProperty("fixedLayer", mitk::BoolProperty::New(true)); newInputNode->SetBoolProperty("pickable", true); mitk::ColorProperty::Pointer initialColor = dynamic_cast(newInputNode->GetProperty(deselectedColorPropertyName)); if (initialColor.IsNotNull()) { newInputNode->SetColor(initialColor->GetColor()); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::BoundingShapeInteractor::HandlePositionChanged(const InteractionEvent *interactionEvent, Point3D ¢er) { GeometryData::Pointer geometryData = dynamic_cast(this->GetDataNode()->GetData()); int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); mitk::BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep); std::vector cornerPoints = GetCornerPoints(geometry, true); if (m_Impl->Handles.size() == 6) { // set handle positions Point3D pointLeft = CalcAvgPoint(cornerPoints[5], cornerPoints[6]); Point3D pointRight = CalcAvgPoint(cornerPoints[1], cornerPoints[2]); Point3D pointTop = CalcAvgPoint(cornerPoints[0], cornerPoints[6]); Point3D pointBottom = CalcAvgPoint(cornerPoints[7], cornerPoints[1]); Point3D pointFront = CalcAvgPoint(cornerPoints[2], cornerPoints[7]); Point3D pointBack = CalcAvgPoint(cornerPoints[4], cornerPoints[1]); m_Impl->Handles[0].SetPosition(pointLeft); m_Impl->Handles[1].SetPosition(pointRight); m_Impl->Handles[2].SetPosition(pointTop); m_Impl->Handles[3].SetPosition(pointBottom); m_Impl->Handles[4].SetPosition(pointFront); m_Impl->Handles[5].SetPosition(pointBack); // calculate center based on half way of the distance between two opposing cornerpoints center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]); } } void mitk::BoundingShapeInteractor::SetDataNode(DataNode *node) { this->RestoreNodeProperties(); // if there is another node set, restore it's color if (node == nullptr) return; DataInteractor::SetDataNode(node); // calls DataNodeChanged internally this->DataNodeChanged(); } bool mitk::BoundingShapeInteractor::CheckOverObject(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; GeometryData::Pointer geometryData = dynamic_cast(this->GetDataNode()->GetData()); int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep); // calculates translation based on offset+extent not on the transformation matrix (because the cube is located in the // center not in the origin) vtkSmartPointer imageTransform = geometry->GetVtkTransform()->GetMatrix(); Point3D center = geometry->GetCenter(); auto translation = vtkSmartPointer::New(); auto transform = vtkSmartPointer::New(); translation->Translate(center[0] - imageTransform->GetElement(0, 3), center[1] - imageTransform->GetElement(1, 3), center[2] - imageTransform->GetElement(2, 3)); transform->SetMatrix(imageTransform); transform->PostMultiply(); transform->Concatenate(translation); transform->Update(); mitk::Vector3D extent; for (unsigned int i = 0; i < 3; ++i) extent[i] = (geometry->GetExtent(i)); Point3D currentWorldPosition; Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen(); interactionEvent->GetSender()->DisplayToWorld(currentDisplayPosition, currentWorldPosition); ScalarType transformedPosition[4]; transformedPosition[0] = currentWorldPosition[0]; transformedPosition[1] = currentWorldPosition[1]; transformedPosition[2] = currentWorldPosition[2]; transformedPosition[3] = 1; // transform point from world to object coordinates transform->GetInverse()->TransformPoint(transformedPosition, transformedPosition); // check if the world point is within bounds bool isInside = (transformedPosition[0] >= (-extent[0] / 2.0)) && (transformedPosition[0] <= (extent[0] / 2.0)) && (transformedPosition[1] >= (-extent[1] / 2.0)) && (transformedPosition[1] <= (extent[1] / 2.0)) && (transformedPosition[2] >= (-extent[2] / 2.0)) && (transformedPosition[2] <= (extent[2] / 2.0)); return isInside; } bool mitk::BoundingShapeInteractor::CheckOverHandles(const InteractionEvent *interactionEvent) { Point3D boundingBoxCenter; HandlePositionChanged(interactionEvent, boundingBoxCenter); const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; Point2D displayCenterPoint; // to do: change to actual time step (currently not necessary because geometry remains the same for each timestep int timeStep = 0; GeometryData::Pointer geometryData = dynamic_cast(this->GetDataNode()->GetData()); BaseGeometry::Pointer geometry = geometryData->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep); std::vector cornerPoints = GetCornerPoints(geometry, true); interactionEvent->GetSender()->WorldToDisplay(boundingBoxCenter, displayCenterPoint); double scale = interactionEvent->GetSender()->GetScaleFactorMMPerDisplayUnit(); // GetDisplaySizeInMM mitk::DoubleProperty::Pointer handleSizeProperty = dynamic_cast(this->GetDataNode()->GetProperty("Bounding Shape.Handle Size Factor")); ScalarType initialHandleSize; if (handleSizeProperty != nullptr) initialHandleSize = handleSizeProperty->GetValue(); else initialHandleSize = 1.0 / 40.0; mitk::Point2D displaysize = interactionEvent->GetSender()->GetDisplaySizeInMM(); ScalarType handlesize = ((displaysize[0] + displaysize[1]) / 2.0) * initialHandleSize; unsigned int handleNum = 0; for (auto &handle : m_Impl->Handles) { Point2D centerpoint; interactionEvent->GetSender()->WorldToDisplay(handle.GetPosition(), centerpoint); Point2D currentDisplayPosition = positionEvent->GetPointerPositionOnScreen(); if ((currentDisplayPosition.EuclideanDistanceTo(centerpoint) < (handlesize / scale)) && (currentDisplayPosition.EuclideanDistanceTo(displayCenterPoint) > (handlesize / scale))) // check if mouse is hovering over center point { handle.SetActive(true); m_Impl->ActiveHandle = handle; this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName, mitk::IntProperty::New(handleNum++)); this->GetDataNode()->GetData()->Modified(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return true; } else { handleNum++; handle.SetActive(false); } this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1)); } return false; } -void mitk::BoundingShapeInteractor::SelectHandle(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::BoundingShapeInteractor::SelectHandle(StateMachineAction *, InteractionEvent *) { this->DisableCrosshairNavigation(); DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(deselectedColorPropertyName)); if (selectedColor.IsNotNull()) { this->GetDataNode()->GetPropertyList()->SetProperty("color", selectedColor); } this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return; } -void mitk::BoundingShapeInteractor::DeselectHandles(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::BoundingShapeInteractor::DeselectHandles(StateMachineAction *, InteractionEvent *) { this->DisableCrosshairNavigation(); DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; this->GetDataNode()->GetPropertyList()->SetProperty(activeHandleIdPropertyName, mitk::IntProperty::New(-1)); this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::BoundingShapeInteractor::SelectObject(StateMachineAction *, InteractionEvent *) { this->DisableCrosshairNavigation(); // disable crosshair interaction and scolling if user is hovering over the object DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(selectedColorPropertyName)); if (selectedColor.IsNotNull()) { node->GetPropertyList()->SetProperty("color", selectedColor); } this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } -void mitk::BoundingShapeInteractor::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::BoundingShapeInteractor::DeselectObject(StateMachineAction *, InteractionEvent *) { this->EnableCrosshairNavigation(); // enable crosshair interaction and scolling if user is hovering over the object DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; mitk::ColorProperty::Pointer deselectedColor = dynamic_cast(node->GetProperty(deselectedColorPropertyName)); if (deselectedColor.IsNotNull()) { node->GetPropertyList()->SetProperty("color", deselectedColor); } this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::BoundingShapeInteractor::InitInteraction(StateMachineAction *, InteractionEvent *interactionEvent) { InitMembers(interactionEvent); } bool mitk::BoundingShapeInteractor::InitMembers(InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; // get initial position coordinates m_Impl->InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); m_Impl->InitialPickedWorldPoint = positionEvent->GetPositionInWorld(); m_Impl->LastPickedWorldPoint = positionEvent->GetPositionInWorld(); return true; } void mitk::BoundingShapeInteractor::TranslateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); mitk::BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep); Vector3D spacing = geometry->GetSpacing(); Point3D currentPickedPoint; interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint); Vector3D interactionMove; // pixel aligned shifting of the bounding box interactionMove[0] = std::round((currentPickedPoint[0] - m_Impl->LastPickedWorldPoint[0]) / spacing[0]) * spacing[0]; interactionMove[1] = std::round((currentPickedPoint[1] - m_Impl->LastPickedWorldPoint[1]) / spacing[1]) * spacing[1]; interactionMove[2] = std::round((currentPickedPoint[2] - m_Impl->LastPickedWorldPoint[2]) / spacing[2]) * spacing[2]; if ((interactionMove[0] + interactionMove[1] + interactionMove[2]) != 0.0) // only update current position if a movement occured { m_Impl->LastPickedWorldPoint = currentPickedPoint; geometry->SetOrigin(geometry->GetOrigin() + interactionMove); this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } return; } void mitk::BoundingShapeInteractor::ScaleObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; GeometryData::Pointer geometryData = dynamic_cast(this->GetDataNode()->GetData()); Point3D handlePickedPoint = m_Impl->ActiveHandle.GetPosition(); Point3D currentPickedPoint; interactionEvent->GetSender()->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), currentPickedPoint); int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); mitk::BaseGeometry::Pointer geometry = geometryData->GetGeometry(timeStep); Vector3D spacing = geometry->GetSpacing(); // pixel aligned bounding box Vector3D interactionMove; interactionMove[0] = (currentPickedPoint[0] - m_Impl->LastPickedWorldPoint[0]); interactionMove[1] = (currentPickedPoint[1] - m_Impl->LastPickedWorldPoint[1]); interactionMove[2] = (currentPickedPoint[2] - m_Impl->LastPickedWorldPoint[2]); std::vector faces = m_Impl->ActiveHandle.GetFaceIndices(); auto pointscontainer = mitk::BoundingBox::PointsContainer::New(); // calculate cornerpoints from geometry plus visualization offset std::vector cornerPoints = GetCornerPoints(geometry, true); unsigned int num = 0; for (auto point : cornerPoints) { pointscontainer->InsertElement(num++, point); } // calculate center based on half way of the distance between two opposing cornerpoints mitk::Point3D center = CalcAvgPoint(cornerPoints[7], cornerPoints[0]); Vector3D faceNormal; faceNormal[0] = handlePickedPoint[0] - center[0]; faceNormal[1] = handlePickedPoint[1] - center[1]; faceNormal[2] = handlePickedPoint[2] - center[2]; Vector3D faceShift = ((faceNormal * interactionMove) / (faceNormal.GetNorm() * faceNormal.GetNorm())) * faceNormal; // calculate cornerpoints from geometry without visualization offset to update actual geometry cornerPoints = GetCornerPoints(geometry, false); num = 0; for (auto point : cornerPoints) { pointscontainer->InsertElement(num++, point); } bool positionChangeThreshold = true; for (int numFaces = 0; numFaces < 8; numFaces++) // estimate the corresponding face and shift its assigned points { if ((numFaces != faces[0]) && (numFaces != faces[1]) && (numFaces != faces[2]) && (numFaces != faces[3])) { Point3D point = pointscontainer->GetElement(numFaces); if (m_Impl->RotationEnabled) // apply if geometry is rotated at a pixel aligned shift is not possible { point[0] += faceShift[0]; point[1] += faceShift[1]; point[2] += faceShift[2]; } else // shift pixelwise { point[0] += std::round(faceShift[0] / spacing[0]) * spacing[0]; point[1] += std::round(faceShift[1] / spacing[1]) * spacing[1]; point[2] += std::round(faceShift[2] / spacing[2]) * spacing[2]; } if (point == pointscontainer->GetElement(numFaces)) positionChangeThreshold = false; else m_Impl->LastPickedWorldPoint = point; pointscontainer->InsertElement(numFaces, point); } } if (positionChangeThreshold) // update only if bounding box is shifted at least by one pixel { auto inverse = mitk::AffineTransform3D::New(); geometry->GetIndexToWorldTransform()->GetInverse(inverse); for (unsigned int pointid = 0; pointid < 8; pointid++) { pointscontainer->InsertElement(pointid, inverse->TransformPoint(pointscontainer->GetElement(pointid))); } auto bbox = mitk::BoundingBox::New(); bbox->SetPoints(pointscontainer); bbox->ComputeBoundingBox(); mitk::Point3D BBmin = bbox->GetMinimum(); mitk::Point3D BBmax = bbox->GetMaximum(); if (std::abs(BBmin[0] - BBmax[0]) > 0.01 && std::abs(BBmin[1] - BBmax[1]) > 0.01 && std::abs(BBmin[2] - BBmax[2]) > 0.01) // TODO: check if the extent is greater than zero { geometry->SetBounds(bbox->GetBounds()); geometry->Modified(); this->GetDataNode()->GetData()->UpdateOutputInformation(); // Geometry is up-to-date this->GetDataNode()->GetData()->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return; } void mitk::BoundingShapeInteractor::RestoreNodeProperties() { mitk::DataNode::Pointer inputNode = this->GetDataNode(); if (inputNode.IsNull()) return; mitk::ColorProperty::Pointer color = (mitk::ColorProperty::New(1.0, 1.0, 1.0)); if (color.IsNotNull()) { inputNode->GetPropertyList()->SetProperty("color", color); } inputNode->SetProperty("layer", mitk::IntProperty::New(99)); inputNode->SetProperty(boundingShapePropertyName, mitk::BoolProperty::New(false)); inputNode->GetPropertyList()->DeleteProperty(activeHandleIdPropertyName); EnableCrosshairNavigation(); // update rendering mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::BoundingShapeInteractor::EnableCrosshairNavigation() { // enable the crosshair navigation // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools // in new interaction framework for (auto it = m_Impl->DisplayInteractorConfigs.begin(); it != m_Impl->DisplayInteractorConfigs.end(); ++it) { if (it->first) { mitk::DisplayInteractor *displayInteractor = static_cast( us::GetModuleContext()->GetService(it->first)); if (displayInteractor != nullptr) { // here the regular configuration is loaded again displayInteractor->SetEventConfig(it->second); // MITK_INFO << "restore config"; } } } m_Impl->DisplayInteractorConfigs.clear(); m_Impl->ScrollEnabled = true; } void mitk::BoundingShapeInteractor::DisableCrosshairNavigation() { // dont deactivate twice, else we will clutter the config list ... if (m_Impl->ScrollEnabled == false) return; // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts // with tools // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction // will still be enabled m_Impl->DisplayInteractorConfigs.clear(); std::vector> listEventObserver = us::GetModuleContext()->GetServiceReferences(); for (auto it = listEventObserver.begin(); it != listEventObserver.end(); ++it) { auto *displayInteractor = dynamic_cast(us::GetModuleContext()->GetService(*it)); if (displayInteractor != nullptr) { // remember the original configuration m_Impl->DisplayInteractorConfigs.insert(std::make_pair(*it, displayInteractor->GetEventConfig())); // here the alternative configuration is loaded displayInteractor->SetEventConfig("DisplayConfigMITKNoCrosshair.xml"); // MITK_INFO << "change config"; } } m_Impl->ScrollEnabled = false; } diff --git a/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h b/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h index ee679cf6a2..5b59101b07 100644 --- a/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h +++ b/Modules/Core/TestingHelper/include/mitkRenderingTestHelper.h @@ -1,225 +1,225 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRenderingTestHelper_h #define mitkRenderingTestHelper_h #include #include #include #include #include class vtkRenderWindow; class vtkRenderer; namespace mitk { class MITKTESTINGHELPER_EXPORT RenderingTestHelper { public: /** @brief Generate a rendering test helper object including a render window of the size width * height (in pixel). @param argc Number of parameters. (here: Images) "Usage: [filename1 filenam2 -V referenceScreenshot (optional -T /directory/to/save/differenceImage)] @param argv Given parameters. If no data is inserted via commandline, you can add data later via AddNodeToDataStorage(). @param renderingMode The rendering mode. **/ RenderingTestHelper( int width, int height, int argc, char *argv[], - BaseRenderer::RenderingMode renderingMode = BaseRenderer::RenderingMode::NoAntiAliasing); + AntiAliasing antiAliasing = AntiAliasing::None); /** @brief Generate a rendering test helper object including a render window of the size width * height (in * pixel).*/ RenderingTestHelper( int width, int height, - BaseRenderer::RenderingMode renderingMode = BaseRenderer::RenderingMode::NoAntiAliasing); + AntiAliasing antiAliasing = AntiAliasing::None); /** Default destructor */ ~RenderingTestHelper(); /** @brief Getter for the vtkRenderer. **/ vtkRenderer *GetVtkRenderer(); /** @brief Getter for the vtkRenderWindow which should be used to call vtkRegressionTestImage. **/ vtkRenderWindow *GetVtkRenderWindow(); /** @brief Method can be used to save a screenshot (e.g. reference screenshot as a .png file. @param fileName The filename of the new screenshot (including path). **/ void SaveAsPNG(std::string fileName); /** * @brief SetStopRenderWindow Convenience method to make the renderwindow hold after rendering. Usefull for * debugging. * @param flag Flag indicating whether the renderwindow should automatically close (false, default) or stay open * (true). Usefull for debugging. */ void SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow); /** @brief This method set the property of the member datastorage @param property Set a property for each image in the datastorage m_DataStorage. If you want to set the property for a single data node, use GetDataStorage() and set the property yourself for the destinct node. **/ void SetImageProperty(const char *propertyKey, mitk::BaseProperty *property); /** @brief Set the view direction of the renderwindow (e.g. sagittal, coronal, axial) **/ void SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection); /** @brief Reorient the slice (e.g. rotation and translation like the swivel mode). **/ void ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation); /** @brief Render everything into an mitkRenderWindow. Call SetViewDirection() and SetProperty() before this method. **/ void Render(); /** @brief Returns the datastorage, in order to modify the data inside a rendering test. **/ mitk::DataStorage::Pointer GetDataStorage(); /** * @brief SetMapperID Change between Standard2D and 3D mappers. * @param id Enum mitk::BaseRenderer::StandardMapperSlot which defines the mapper. */ void SetMapperID(mitk::BaseRenderer::StandardMapperSlot id); /** * @brief AddNodeToStorage Add a node to the datastorage and perform a reinit which is necessary for rendering. * @param node The data you want to add. */ void AddNodeToStorage(mitk::DataNode::Pointer node); /** * @brief SetMapperIDToRender3D Convenience method to render in a 3D renderwindow. * @warning Does not add helper objects like the image planes to render images in 3D. */ void SetMapperIDToRender3D(); /** * @brief SetMapperIDToRender2D Convenience method to render in a 2D renderwindow. */ void SetMapperIDToRender2D(); /** * @brief SaveReferenceScreenShot Convenience method to save a reference screen shot. * @param fileName Path/to/save/the/png/file. */ void SaveReferenceScreenShot(std::string fileName); /** * @brief CompareRenderWindowAgainstReference Convenience method to compare the image rendered in the internal renderwindow against a reference screen shot. * Usage of vtkTesting::Test: vtkTesting::Test( argc, argv, vtkRenderWindow, threshold ) Set a vtkRenderWindow containing the desired scene. This is automatically rendered. vtkTesting::Test() automatically searches in argc and argv[] for a path a valid image with -V. If the test failed with the first image (foo.png) it checks if there are images of the form foo_N.png (where N=1,2,3...) and compare against them. This allows for multiple valid images. * @param argc Number of arguments. * @param argv Arguments must(!) contain the term "-V Path/To/Valid/Image.png" * @param threshold Allowed difference between two images. Default = 10.0 and was taken from VTK. * @return True if the images are equal regarding the threshold. False in all other cases. */ bool CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold = 10.0); /** @brief Returns true if the opengl context is compatible for advanced vtk effects **/ bool IsAdvancedOpenGL(); /** * @brief The ArgcHelperClass class is a convinience class to convert a vector * of strings to the standard c++ argv and argc arguments. This is necessary for * the vtkTesting::Test, since is requires the reference image (and other * optional parameters) via command line. */ class ArgcHelperClass { private: /** * Members for conversion. */ std::vector argv; std::vector> argvec; public: ArgcHelperClass(const std::vector &argstrings) : argv(argstrings.size() + 1), argvec(argstrings.size() + 1) { std::vector cmdArgs; cmdArgs.push_back(mitk::IOUtil::GetProgramPath()); cmdArgs.insert(cmdArgs.end(), argstrings.begin(), argstrings.end()); for (std::size_t i = 0; i < cmdArgs.size(); ++i) { argvec[i].assign(cmdArgs[i].begin(), cmdArgs[i].end()); argvec[i].push_back('\0'); argv[i] = &argvec[i][0]; } } char **GetArgv() { return &argv[0]; } int GetArgc() { return argv.size(); } }; protected: /** * @brief Initialize Internal method to initialize the renderwindow and set the datastorage. * @param width Height of renderwindow. * @param height Width of renderwindow. * @param renderingMode The rendering mode. */ void Initialize( int width, int height, - BaseRenderer::RenderingMode renderingMode = BaseRenderer::RenderingMode::NoAntiAliasing); + AntiAliasing antiAliasing = AntiAliasing::None); /** @brief Prints the opengl information, e.g. version, vendor and extensions, * This function can only be called after an opengl context is active. * It only prints the context after the vtkRenderwindow is fully initialized. **/ void PrintGLInfo(); /** @brief This method tries to load the given file into a member datastorage, in order to render it. @param fileName The filename of the file to be loaded (including path). **/ void AddToStorage(const std::string &filename); /** @brief This method tries to parse the given argv for files (e.g. images) and load them into a member datastorage, in order to render it. @param argc Number of parameters. @param argv Given parameters. **/ void SetInputFileNames(int argc, char *argv[]); mitk::RenderWindow::Pointer m_RenderWindow; //<< Contains the mitkRenderWindow into which the test renders the data mitk::DataStorage::Pointer m_DataStorage; //<< Contains the mitkDataStorage which contains the data to be rendered bool m_AutomaticallyCloseRenderWindow; //<< Flag indicating whether the renderwindow should automatically close (true, // default) or stay open (false). Usefull for debugging. }; } // namespace mitk #endif diff --git a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp index 811b768609..931e84b449 100644 --- a/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkInteractionTestHelper.cpp @@ -1,437 +1,436 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK #include #include #include #include #include // VTK #include #include // us #include #include mitk::InteractionTestHelper::InteractionTestHelper(const std::string &interactionXmlFilePath) : m_InteractionFilePath(interactionXmlFilePath) { this->Initialize(interactionXmlFilePath); } void mitk::InteractionTestHelper::Initialize(const std::string &interactionXmlFilePath) { // TiXmlDocument document(interactionXmlPath.c_str()); TiXmlDocument document(interactionXmlFilePath); bool loadOkay = document.LoadFile(); if (loadOkay) { // get RenderingManager instance - mitk::RenderingManager *rm = mitk::RenderingManager::GetInstance(); + auto rm = mitk::RenderingManager::GetInstance(); // create data storage m_DataStorage = mitk::StandaloneDataStorage::New(); // for each renderer found create a render window and configure for (TiXmlElement *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer()); element != nullptr; element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get view direction mitk::SliceNavigationController::ViewDirection viewDirection = mitk::SliceNavigationController::Axial; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection()) != nullptr) { int viewDirectionNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyViewDirection())->c_str()); viewDirection = static_cast(viewDirectionNum); } // get mapper slot id mitk::BaseRenderer::MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID()) != nullptr) { int mapperIDNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID())->c_str()); mapperID = static_cast(mapperIDNum); } // Get Size of Render Windows int size[3]; size[0] = size[1] = size[2] = 0; if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX()) != nullptr) { size[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeX())->c_str()); } if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY()) != nullptr) { size[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeY())->c_str()); } if (element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ()) != nullptr) { size[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlRenderSizeZ())->c_str()); } // create renderWindow, renderer and dispatcher - mitk::RenderWindow::Pointer rw = - mitk::RenderWindow::New(nullptr, rendererName, rm); // VtkRenderWindow is created within constructor if nullptr + auto rw = RenderWindow::New(nullptr, rendererName); // VtkRenderWindow is created within constructor if nullptr if (size[0] != 0 && size[1] != 0) { rw->SetSize(size[0], size[1]); rw->GetRenderer()->Resize(size[0], size[1]); } // set storage of renderer rw->GetRenderer()->SetDataStorage(m_DataStorage); // set view direction to axial rw->GetSliceNavigationController()->SetDefaultViewDirection(viewDirection); // set renderer to render 2D rw->GetRenderer()->SetMapperID(mapperID); rw->GetRenderer()->PrepareRender(); // Some more magic for the 3D render window case: // Camera view direction, position and focal point if (mapperID == mitk::BaseRenderer::Standard3D) { if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX())->c_str()); cameraFocalPoint[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY())->c_str()); cameraFocalPoint[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ())->c_str()); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX()) != nullptr) { double cameraPosition[3]; cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX())->c_str()); cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY())->c_str()); cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ())->c_str()); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX()) != nullptr) { double viewUp[3]; viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX())->c_str()); viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY())->c_str()); viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ())->c_str()); rw->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } } rw->GetVtkRenderWindow()->Render(); rw->GetVtkRenderWindow()->WaitForCompletion(); // connect SliceNavigationControllers to timestep changed event of TimeNavigationController rw->GetSliceNavigationController()->ConnectGeometryTimeEvent(rm->GetTimeNavigationController(), false); rm->GetTimeNavigationController()->ConnectGeometryTimeEvent(rw->GetSliceNavigationController(), false); // add to list of kown render windows m_RenderWindowList.push_back(rw); } // TODO: check the following lines taken from QmitkStdMultiWidget and adapt them to be executed in our code here. // mitkWidget1->GetSliceNavigationController() // ->ConnectGeometrySendEvent(mitk::BaseRenderer::GetInstance(mitkWidget4->GetRenderWindow())); //########### register display interactor to handle scroll events ################## // use MouseModeSwitcher to ensure that the statemachine of DisplayInteractor is loaded correctly m_MouseModeSwitcher = mitk::MouseModeSwitcher::New(); } else { mitkThrow() << "Can not load interaction xml file <" << m_InteractionFilePath << ">"; } // WARNING assumes a 3D window exists !!!! this->AddDisplayPlaneSubTree(); } mitk::InteractionTestHelper::~InteractionTestHelper() { mitk::RenderingManager *rm = mitk::RenderingManager::GetInstance(); // unregister renderers auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { rm->GetTimeNavigationController()->Disconnect((*it)->GetSliceNavigationController()); (*it)->GetSliceNavigationController()->Disconnect(rm->GetTimeNavigationController()); mitk::BaseRenderer::RemoveInstance((*it)->GetVtkRenderWindow()); } rm->RemoveAllObservers(); } mitk::DataStorage::Pointer mitk::InteractionTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::InteractionTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); this->Set3dCameraSettings(); } void mitk::InteractionTestHelper::PlaybackInteraction() { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); // load events if not loaded yet if (m_Events.empty()) this->LoadInteraction(); auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { (*it)->GetRenderer()->PrepareRender(); (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); it = m_RenderWindowList.begin(); for (; it != end; ++it) { (*it)->GetVtkRenderWindow()->Render(); (*it)->GetVtkRenderWindow()->WaitForCompletion(); } // mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); // playback all events in queue for (unsigned long i = 0; i < m_Events.size(); ++i) { // let dispatcher of sending renderer process the event m_Events.at(i)->GetSender()->GetDispatcher()->ProcessEvent(m_Events.at(i)); } if (false) { it--; (*it)->GetVtkRenderWindow()->GetInteractor()->Start(); } } void mitk::InteractionTestHelper::LoadInteraction() { // load interaction pattern from xml file std::ifstream xmlStream(m_InteractionFilePath.c_str()); mitk::XML2EventParser parser(xmlStream); m_Events = parser.GetInteractions(); xmlStream.close(); // Avoid VTK warning: Trying to delete object with non-zero reference count. parser.SetReferenceCount(0); } void mitk::InteractionTestHelper::SetTimeStep(int newTimeStep) { mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(m_DataStorage); bool timeStepIsvalid = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetCreatedWorldGeometry()->IsValidTimeStep( newTimeStep); if (timeStepIsvalid) { mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->SetPos(newTimeStep); } } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByName(const std::string &name) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (name.compare((*it)->GetRenderer()->GetName()) == 0) return (*it).GetPointer(); } return nullptr; } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindowByDefaultViewDirection( mitk::SliceNavigationController::ViewDirection viewDirection) { auto it = m_RenderWindowList.begin(); auto end = m_RenderWindowList.end(); for (; it != end; ++it) { if (viewDirection == (*it)->GetSliceNavigationController()->GetDefaultViewDirection()) return (*it).GetPointer(); } return nullptr; } mitk::RenderWindow *mitk::InteractionTestHelper::GetRenderWindow(unsigned int index) { if (index < m_RenderWindowList.size()) { return m_RenderWindowList.at(index).GetPointer(); } else { return nullptr; } } void mitk::InteractionTestHelper::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; mitk::IntProperty::Pointer layer = mitk::IntProperty::New(1000); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetProperty("name", mitk::StringProperty::New("Widgets")); node->SetProperty("helper object", mitk::BoolProperty::New(true)); m_DataStorage->Add(node); for (auto it : m_RenderWindowList) { if (it->GetRenderer()->GetMapperID() == BaseRenderer::Standard3D) continue; // ... of widget 1 mitk::DataNode::Pointer planeNode1 = (mitk::BaseRenderer::GetInstance(it->GetVtkRenderWindow()))->GetCurrentWorldPlaneGeometryNode(); planeNode1->SetProperty("visible", mitk::BoolProperty::New(true)); planeNode1->SetProperty("name", mitk::StringProperty::New("widget1Plane")); planeNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); planeNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); planeNode1->SetProperty("layer", layer); planeNode1->SetColor(1.0, 0.0, 0.0); mapper = mitk::PlaneGeometryDataMapper2D::New(); planeNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_DataStorage->Add(planeNode1, node); } } void mitk::InteractionTestHelper::Set3dCameraSettings() { TiXmlDocument document(m_InteractionFilePath); bool loadOkay = document.LoadFile(); if (loadOkay) { // for each renderer found create a render window and configure for (TiXmlElement *element = document.FirstChildElement(mitk::InteractionEventConst::xmlTagInteractions()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagConfigRoot()) ->FirstChildElement(mitk::InteractionEventConst::xmlTagRenderer()); element != nullptr; element = element->NextSiblingElement(mitk::InteractionEventConst::xmlTagRenderer())) { // get name of renderer const char *rendererName = element->Attribute(mitk::InteractionEventConst::xmlEventPropertyRendererName().c_str()); // get mapper slot id mitk::BaseRenderer::MapperSlotId mapperID = mitk::BaseRenderer::Standard2D; if (element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID()) != nullptr) { int mapperIDNum = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlEventPropertyMapperID())->c_str()); mapperID = static_cast(mapperIDNum); } if (mapperID == mitk::BaseRenderer::Standard3D) { RenderWindow *namedRenderer = nullptr; for (auto it : m_RenderWindowList) { if (strcmp(it->GetRenderer()->GetName(), rendererName) == 0) { namedRenderer = it.GetPointer(); break; } } if (namedRenderer == nullptr) { MITK_ERROR << "No match for render window was found."; return; } namedRenderer->GetRenderer()->PrepareRender(); if (element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX()) != nullptr) { double cameraFocalPoint[3]; cameraFocalPoint[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointX())->c_str()); cameraFocalPoint[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointY())->c_str()); cameraFocalPoint[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraFocalPointZ())->c_str()); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(cameraFocalPoint); } if (element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX()) != nullptr) { double cameraPosition[3]; cameraPosition[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionX())->c_str()); cameraPosition[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionY())->c_str()); cameraPosition[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlCameraPositionZ())->c_str()); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(cameraPosition); } if (element->Attribute(mitk::InteractionEventConst::xmlViewUpX()) != nullptr) { double viewUp[3]; viewUp[0] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpX())->c_str()); viewUp[1] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpY())->c_str()); viewUp[2] = std::atoi(element->Attribute(mitk::InteractionEventConst::xmlViewUpZ())->c_str()); namedRenderer->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(viewUp); } namedRenderer->GetVtkRenderWindow()->Render(); } } } } diff --git a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp index 9a66290a77..0045414a44 100644 --- a/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp +++ b/Modules/Core/TestingHelper/src/mitkRenderingTestHelper.cpp @@ -1,315 +1,317 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // VTK #include #include #include #include #include // MITK #include #include #include #include #include #include #include #include // include gl to read out properties #include #include #if defined _MSC_VER #if _MSC_VER >= 1700 #define RESIZE_WORKAROUND #endif #endif #ifdef RESIZE_WORKAROUND #include "vtkWin32OpenGLRenderWindow.h" #endif // VTK Testing to compare the rendered image pixel-wise against a reference screen shot #include "vtkTesting.h" mitk::RenderingTestHelper::RenderingTestHelper(int width, int height, - BaseRenderer::RenderingMode renderingMode) + AntiAliasing antiAliasing) : m_AutomaticallyCloseRenderWindow(true) { - this->Initialize(width, height, renderingMode); + this->Initialize(width, height, antiAliasing); } mitk::RenderingTestHelper::RenderingTestHelper( - int width, int height, int argc, char *argv[], BaseRenderer::RenderingMode renderingMode) + int width, int height, int argc, char *argv[], AntiAliasing antiAliasing) : m_AutomaticallyCloseRenderWindow(true) { - this->Initialize(width, height, renderingMode); + this->Initialize(width, height, antiAliasing); this->SetInputFileNames(argc, argv); } -void mitk::RenderingTestHelper::Initialize(int width, int height, BaseRenderer::RenderingMode renderingMode) +void mitk::RenderingTestHelper::Initialize(int width, int height, AntiAliasing antiAliasing) { + RenderingManager::GetInstance()->SetAntiAliasing(antiAliasing); + mitk::UIDGenerator uidGen = mitk::UIDGenerator("UnnamedRenderer_", 8); - m_RenderWindow = mitk::RenderWindow::New(nullptr, uidGen.GetUID().c_str(), nullptr, renderingMode); + m_RenderWindow = mitk::RenderWindow::New(nullptr, uidGen.GetUID().c_str()); m_DataStorage = mitk::StandaloneDataStorage::New(); m_RenderWindow->GetRenderer()->SetDataStorage(m_DataStorage); this->SetMapperIDToRender2D(); this->GetVtkRenderWindow()->SetSize(width, height); if (!IsAdvancedOpenGL()) { mitkThrowException(mitk::TestNotRunException) << "Insufficient OpenGL version"; } #ifdef RESIZE_WORKAROUND HWND hWnd = static_cast(this->GetVtkRenderWindow())->GetWindowId(); RECT r; r.left = 10; r.top = 10; r.right = r.left + width; r.bottom = r.top + height; LONG style = GetWindowLong(hWnd, GWL_STYLE); AdjustWindowRect(&r, style, FALSE); MITK_INFO << "WANTED:"; MITK_INFO << r.right - r.left; MITK_INFO << r.bottom - r.top; RECT rect; if (GetWindowRect(hWnd, &rect)) { int width = rect.right - rect.left; int height = rect.bottom - rect.top; MITK_INFO << "ACTUAL:"; MITK_INFO << width; MITK_INFO << height; } SetWindowPos(hWnd, HWND_TOP, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOZORDER); GetWindowRect(hWnd, &rect); int width2 = rect.right - rect.left; int height2 = rect.bottom - rect.top; MITK_INFO << "ACTUAL2:"; MITK_INFO << width2; MITK_INFO << height2; SetWindowPos(hWnd, HWND_TOP, 0, 0, 2 * (r.right - r.left) - width2, 2 * (r.bottom - r.top) - height2, SWP_NOZORDER); #endif m_RenderWindow->GetRenderer()->Resize(width, height); // Prints the glinfo after creation of the vtkrenderwindow, we always want to do this for debugging. this->PrintGLInfo(); } mitk::RenderingTestHelper::~RenderingTestHelper() { } bool mitk::RenderingTestHelper::IsAdvancedOpenGL() { const GLubyte *version = glGetString(GL_VERSION); if (!version) return false; return *version >= '2'; } void mitk::RenderingTestHelper::PrintGLInfo() { GLint maxTextureSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); ; //MITK_INFO << "OpenGL Render Context Information: \n" // << "- GL_VENDOR: " << glGetString(GL_VENDOR) << "\n" // << "- GL_RENDERER: " << glGetString(GL_RENDERER) << "\n" // << "- GL_VERSION: " << glGetString(GL_VERSION) << "\n" // << "- GL_MAX_TEXTURE_SIZE: " << maxTextureSize << "\n" // << "- GL_EXTENSIONS: " << glGetString(GL_EXTENSIONS); } void mitk::RenderingTestHelper::SetMapperID(mitk::BaseRenderer::StandardMapperSlot id) { m_RenderWindow->GetRenderer()->SetMapperID(id); } void mitk::RenderingTestHelper::SetMapperIDToRender3D() { this->SetMapperID(mitk::BaseRenderer::Standard3D); mitk::RenderingManager::GetInstance()->InitializeViews( this->GetDataStorage()->ComputeBoundingGeometry3D(this->GetDataStorage()->GetAll())); } void mitk::RenderingTestHelper::SetMapperIDToRender2D() { this->SetMapperID(mitk::BaseRenderer::Standard2D); } void mitk::RenderingTestHelper::Render() { // if the datastorage is initialized and at least 1 image is loaded render it if (m_DataStorage.IsNotNull() || m_DataStorage->GetAll()->Size() >= 1) { // Prepare the VTK camera before rendering. m_RenderWindow->GetRenderer()->PrepareRender(); this->GetVtkRenderWindow()->Render(); this->GetVtkRenderWindow()->WaitForCompletion(); if (m_AutomaticallyCloseRenderWindow == false) { // Use interaction to stop the test this->GetVtkRenderWindow()->GetInteractor()->Start(); } } else { MITK_ERROR << "No images loaded in data storage!"; } } mitk::DataStorage::Pointer mitk::RenderingTestHelper::GetDataStorage() { return m_DataStorage; } void mitk::RenderingTestHelper::SetInputFileNames(int argc, char *argv[]) { // i is set 1, because 0 is the testname as string // parse parameters for (int i = 1; i < argc; ++i) { // add everything to a list but -T and -V std::string tmp = argv[i]; if ((tmp.compare("-T")) && (tmp.compare("-V"))) { this->AddToStorage(tmp); } else { break; } } } void mitk::RenderingTestHelper::SetViewDirection(mitk::SliceNavigationController::ViewDirection viewDirection) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow()) ->GetSliceNavigationController() ->SetDefaultViewDirection(viewDirection); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } void mitk::RenderingTestHelper::ReorientSlices(mitk::Point3D origin, mitk::Vector3D rotation) { mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::BaseRenderer::GetInstance(m_RenderWindow->GetVtkRenderWindow())->GetSliceNavigationController(); sliceNavigationController->ReorientSlices(origin, rotation); } vtkRenderer *mitk::RenderingTestHelper::GetVtkRenderer() { return m_RenderWindow->GetRenderer()->GetVtkRenderer(); } void mitk::RenderingTestHelper::SetImageProperty(const char *propertyKey, mitk::BaseProperty *property) { this->m_DataStorage->GetNode(mitk::NodePredicateDataType::New("Image"))->SetProperty(propertyKey, property); } vtkRenderWindow *mitk::RenderingTestHelper::GetVtkRenderWindow() { return m_RenderWindow->GetVtkRenderWindow(); } bool mitk::RenderingTestHelper::CompareRenderWindowAgainstReference(int argc, char *argv[], double threshold) { this->Render(); // retVal meanings: (see VTK/Rendering/vtkTesting.h) // 0 = test failed // 1 = test passed // 2 = test not run // 3 = something with vtkInteraction if (vtkTesting::Test(argc, argv, this->GetVtkRenderWindow(), threshold) == 1) return true; else return false; } // method to save a screenshot of the renderwindow (e.g. create a reference screenshot) void mitk::RenderingTestHelper::SaveAsPNG(std::string fileName) { vtkSmartPointer renderer = this->GetVtkRenderer(); bool doubleBuffering(renderer->GetRenderWindow()->GetDoubleBuffer()); renderer->GetRenderWindow()->DoubleBufferOff(); vtkSmartPointer magnifier = vtkSmartPointer::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(1); vtkSmartPointer fileWriter = vtkSmartPointer::New(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.c_str()); fileWriter->Write(); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void mitk::RenderingTestHelper::SetAutomaticallyCloseRenderWindow(bool automaticallyCloseRenderWindow) { m_AutomaticallyCloseRenderWindow = automaticallyCloseRenderWindow; } void mitk::RenderingTestHelper::SaveReferenceScreenShot(std::string fileName) { this->SaveAsPNG(fileName); } void mitk::RenderingTestHelper::AddToStorage(const std::string &filename) { try { mitk::IOUtil::Load(filename, *m_DataStorage.GetPointer()); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } catch ( const itk::ExceptionObject &e ) { MITK_ERROR << "Failed loading test data '" << filename << "': " << e.what(); } } void mitk::RenderingTestHelper::AddNodeToStorage(mitk::DataNode::Pointer node) { this->m_DataStorage->Add(node); mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll())); } diff --git a/Modules/Core/include/mitkAntiAliasing.h b/Modules/Core/include/mitkAntiAliasing.h new file mode 100644 index 0000000000..7eae9828a2 --- /dev/null +++ b/Modules/Core/include/mitkAntiAliasing.h @@ -0,0 +1,29 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkAntiAliasing_h +#define mitkAntiAliasing_h + +namespace mitk +{ + enum class AntiAliasing : int + { + None, + FastApproximate // FXAA + }; +} + +#endif diff --git a/Modules/Core/include/mitkBaseRenderer.h b/Modules/Core/include/mitkBaseRenderer.h index 591da19453..f830b018af 100644 --- a/Modules/Core/include/mitkBaseRenderer.h +++ b/Modules/Core/include/mitkBaseRenderer.h @@ -1,565 +1,536 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #define BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 #include "mitkCameraRotationController.h" #include "mitkDataStorage.h" #include "mitkPlaneGeometry.h" #include "mitkPlaneGeometryData.h" #include "mitkSliceNavigationController.h" #include "mitkTimeGeometry.h" #include "mitkBindDispatcherInteractor.h" #include "mitkDispatcher.h" #include #include #include #include // DEPRECATED #include namespace mitk { class NavigationController; class SliceNavigationController; class CameraRotationController; class CameraController; class DataStorage; class Mapper; class BaseLocalStorageHandler; class KeyEvent; //##Documentation //## @brief Organizes the rendering process //## //## Organizes the rendering process. A Renderer contains a reference to a //## DataStorage and asks the mappers of the data objects to render //## the data into the renderwindow it is associated to. //## //## \#Render() checks if rendering is currently allowed by calling //## RenderWindow::PrepareRendering(). Initialization of a rendering context //## can also be performed in this method. //## //## The actual rendering code has been moved to \#Repaint() //## Both \#Repaint() and \#Update() are declared protected now. //## //## Note: Separation of the Repaint and Update processes (rendering vs //## creating a vtk prop tree) still needs to be worked on. The whole //## rendering process also should be reworked to use VTK based classes for //## both 2D and 3D rendering. //## @ingroup Renderer class MITKCORE_EXPORT BaseRenderer : public itk::Object { public: - /** \brief This rendering mode enumeration is specified at various constructors - * of the Renderer and RenderWindow classes, which autoconfigures the - * respective VTK objects. This has to be done at construction time because later - * configuring turns out to be not working on most platforms. - */ - enum class RenderingMode : int - { - NoAntiAliasing = 0, - FastApproximateAntiAliasing = 1 // In contrast to MSAA, FXAA works with depth peeling as it is - // applied in a post-processing pass. - }; - typedef std::map BaseRendererMapType; static BaseRendererMapType baseRendererMap; static BaseRenderer *GetInstance(vtkRenderWindow *renWin); static void AddInstance(vtkRenderWindow *renWin, BaseRenderer *baseRenderer); static void RemoveInstance(vtkRenderWindow *renWin); static BaseRenderer *GetByName(const std::string &name); static vtkRenderWindow *GetRenderWindowByName(const std::string &name); #pragma GCC visibility push(default) itkEventMacro(RendererResetEvent, itk::AnyEvent); #pragma GCC visibility pop /** Standard class typedefs. */ mitkClassMacroItkParent(BaseRenderer, itk::Object); - BaseRenderer(const char *name = nullptr, - vtkRenderWindow *renWin = nullptr, - mitk::RenderingManager *rm = nullptr, - RenderingMode mode = RenderingMode::FastApproximateAntiAliasing); + BaseRenderer(const char *name = nullptr, vtkRenderWindow *renWin = nullptr); //##Documentation //## @brief MapperSlotId defines which kind of mapper (e.g. 2D or 3D) should be used. typedef int MapperSlotId; enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; //##Documentation //## @brief Possible view directions for render windows. enum class ViewDirection { AXIAL = 0, SAGITTAL, CORONAL, THREE_D }; virtual void SetDataStorage(DataStorage *storage); ///< set the datastorage that will be used for rendering //##Documentation //## return the DataStorage that is used for rendering virtual DataStorage::Pointer GetDataStorage() const { return m_DataStorage.GetPointer(); } //##Documentation //## @brief Access the RenderWindow into which this renderer renders. vtkRenderWindow *GetRenderWindow() const { return m_RenderWindow; } vtkRenderer *GetVtkRenderer() const { return m_VtkRenderer; } //##Documentation //## @brief Returns the Dispatcher which handles Events for this BaseRenderer Dispatcher::Pointer GetDispatcher() const; //##Documentation //## @brief Default mapper id to use. static const MapperSlotId defaultMapper; //##Documentation //## @brief Do the rendering and flush the result. virtual void Paint(); //##Documentation //## @brief Initialize the RenderWindow. Should only be called from RenderWindow. virtual void Initialize(); //##Documentation //## @brief Called to inform the renderer that the RenderWindow has been resized. virtual void Resize(int w, int h); //##Documentation //## @brief Initialize the renderer with a RenderWindow (@a renderwindow). virtual void InitRenderer(vtkRenderWindow *renderwindow); //##Documentation //## @brief Set the initial size. Called by RenderWindow after it has become //## visible for the first time. virtual void InitSize(int w, int h); //##Documentation //## @brief Draws a point on the widget. //## Should be used during conferences to show the position of the remote mouse virtual void DrawOverlayMouse(Point2D &p2d); //##Documentation //## @brief Set/Get the WorldGeometry (m_WorldGeometry) for 3D and 2D rendering, that describing the //## (maximal) area to be rendered. //## //## Depending of the type of the passed BaseGeometry more or less information can be extracted: //## \li if it is a PlaneGeometry (which is a sub-class of BaseGeometry), m_CurrentWorldPlaneGeometry is //## also set to point to it. m_WorldTimeGeometry is set to nullptr. //## \li if it is a TimeGeometry, m_WorldTimeGeometry is also set to point to it. //## If m_WorldTimeGeometry contains instances of SlicedGeometry3D, m_CurrentWorldPlaneGeometry is set to //## one of geometries stored in the SlicedGeometry3D according to the value of m_Slice; otherwise //## a PlaneGeometry describing the top of the bounding-box of the BaseGeometry is set as the //## m_CurrentWorldPlaneGeometry. //## \li otherwise a PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## is set as the m_CurrentWorldPlaneGeometry. m_WorldTimeGeometry is set to nullptr. //## @todo add calculation of PlaneGeometry describing the top of the bounding-box of the BaseGeometry //## when the passed BaseGeometry is not sliced. //## \sa m_WorldGeometry //## \sa m_WorldTimeGeometry //## \sa m_CurrentWorldPlaneGeometry virtual void SetWorldGeometry3D(const BaseGeometry *geometry); virtual void SetWorldTimeGeometry(const mitk::TimeGeometry *geometry); /** * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void SetWorldGeometry3D(TimeSlicedGeometry *geometry)); itkGetConstObjectMacro(WorldTimeGeometry, TimeGeometry) //##Documentation //## @brief Get the current 3D-worldgeometry (m_CurrentWorldGeometry) used for 3D-rendering itkGetConstObjectMacro(CurrentWorldGeometry, BaseGeometry) //##Documentation //## @brief Get the current 2D-worldgeometry (m_CurrentWorldPlaneGeometry) used for 2D-rendering itkGetConstObjectMacro(CurrentWorldPlaneGeometry, PlaneGeometry) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometry */ DEPRECATED(const PlaneGeometry *GetCurrentWorldGeometry2D()) { return GetCurrentWorldPlaneGeometry(); }; //##Documentation //## Calculates the bounds of the DataStorage (if it contains any valid data), //## creates a geometry from these bounds and sets it as world geometry of the renderer. //## //## Call this method to re-initialize the renderer to the current DataStorage //## (e.g. after loading an additional dataset), to ensure that the view is //## aligned correctly. //## \warn This is not implemented yet. virtual bool SetWorldGeometryToDataStorageBounds() { return false; } //##Documentation //## @brief Set/Get m_Slice which defines together with m_TimeStep the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_Slice virtual void SetSlice(unsigned int slice); itkGetConstMacro(Slice, unsigned int) //##Documentation //## @brief Set/Get m_TimeStep which defines together with m_Slice the 2D geometry //## stored in m_WorldTimeGeometry used as m_CurrentWorldPlaneGeometry //## //## \sa m_TimeStep virtual void SetTimeStep(unsigned int timeStep); itkGetConstMacro(TimeStep, unsigned int) //##Documentation //## @brief Get the time-step of a BaseData object which //## exists at the time of the currently displayed content //## //## Returns -1 or mitk::BaseData::m_TimeSteps if there //## is no data at the current time. //## \sa GetTimeStep, m_TimeStep int GetTimeStep(const BaseData *data) const; //##Documentation //## @brief Get the time in ms of the currently displayed content //## //## \sa GetTimeStep, m_TimeStep ScalarType GetTime() const; //##Documentation //## @brief SetWorldGeometry is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySendEvent virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief UpdateWorldGeometry is called to re-read the 2D geometry from the //## slice navigation controller virtual void UpdateGeometry(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief SetSlice is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometrySliceEvent virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); //##Documentation //## @brief SetTimeStep is called according to the geometrySliceEvent, //## which is supposed to be a SliceNavigationController::GeometryTimeEvent virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); //##Documentation //## @brief Get a DataNode pointing to a data object containing the current 2D-worldgeometry // m_CurrentWorldPlaneGeometry (for 2D rendering) itkGetObjectMacro(CurrentWorldPlaneGeometryNode, DataNode) /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryNode */ DEPRECATED(DataNode *GetCurrentWorldGeometry2DNode()) { return GetCurrentWorldPlaneGeometryNode(); }; //##Documentation //## @brief Sets timestamp of CurrentWorldPlaneGeometry and forces so reslicing in that renderwindow void SendUpdateSlice(); //##Documentation //## @brief Get timestamp of last call of SetCurrentWorldPlaneGeometry unsigned long GetCurrentWorldPlaneGeometryUpdateTime() { return m_CurrentWorldPlaneGeometryUpdateTime; } /** * \deprecatedSince{2014_10} Please use GetCurrentWorldPlaneGeometryUpdateTime */ DEPRECATED(unsigned long GetCurrentWorldGeometry2DUpdateTime()) { return GetCurrentWorldPlaneGeometryUpdateTime(); }; //##Documentation //## @brief Get timestamp of last change of current TimeStep unsigned long GetTimeStepUpdateTime() { return m_TimeStepUpdateTime; } //##Documentation //## @brief Perform a picking: find the x,y,z world coordinate of a //## display x,y coordinate. //## @warning Has to be overwritten in subclasses for the 3D-case. //## //## Implemented here only for 2D-rendering virtual void PickWorldPoint(const Point2D &diplayPosition, Point3D &worldPosition) const = 0; /** \brief Determines the object (mitk::DataNode) closest to the current * position by means of picking * * \warning Implementation currently empty for 2D rendering; intended to be * implemented for 3D renderers */ virtual DataNode *PickObject(const Point2D & /*displayPosition*/, Point3D & /*worldPosition*/) const { return nullptr; } //##Documentation //## @brief Get the MapperSlotId to use. itkGetMacro(MapperID, MapperSlotId) itkGetConstMacro(MapperID, MapperSlotId) //##Documentation //## @brief Set the MapperSlotId to use. itkSetMacro(MapperID, MapperSlotId) virtual int *GetSize() const; virtual int *GetViewportSize() const; void SetSliceNavigationController(SliceNavigationController *SlicenavigationController); itkGetObjectMacro(CameraController, CameraController) itkGetObjectMacro(SliceNavigationController, SliceNavigationController) itkGetObjectMacro(CameraRotationController, CameraRotationController) itkGetMacro(EmptyWorldGeometry, bool) //##Documentation //## @brief Tells if the displayed region is shifted and rescaled if the render window is resized. itkGetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief Tells if the displayed region should be shifted and rescaled if the render window is resized. itkSetMacro(KeepDisplayedRegion, bool) //##Documentation //## @brief get the name of the Renderer //## @note const char *GetName() const { return m_Name.c_str(); } //##Documentation //## @brief get the x_size of the RendererWindow //## @note int GetSizeX() const { return GetSize()[0]; } //##Documentation //## @brief get the y_size of the RendererWindow //## @note int GetSizeY() const { return GetSize()[1]; } const double *GetBounds() const; void RequestUpdate(); void ForceImmediateUpdate(); /** Returns number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int GetNumberOfVisibleLODEnabledMappers() const; - ///** - //* \brief Setter for the RenderingManager that handles this instance of BaseRenderer - //*/ - // void SetRenderingManager( mitk::RenderingManager* ); - - /** - * \brief Getter for the RenderingManager that handles this instance of BaseRenderer - */ - virtual mitk::RenderingManager *GetRenderingManager() const; - //##Documentation //## @brief This method converts a display point to the 3D world index //## using the geometry of the renderWindow. void DisplayToWorld(const Point2D &displayPoint, Point3D &worldIndex) const; //##Documentation //## @brief This method converts a display point to the 2D world index, mapped onto the display plane //## using the geometry of the renderWindow. void DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const; //##Documentation //## @brief This method converts a 3D world index to the display point //## using the geometry of the renderWindow. void WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const; //##Documentation //## @brief This method converts a 3D world index to the point on the viewport //## using the geometry of the renderWindow. void WorldToView(const Point3D &worldIndex, Point2D &viewPoint) const; //##Documentation //## @brief This method converts a 2D plane coordinate to the display point //## using the geometry of the renderWindow. void PlaneToDisplay(const Point2D &planePointInMM, Point2D &displayPoint) const; //##Documentation //## @brief This method converts a 2D plane coordinate to the point on the viewport //## using the geometry of the renderWindow. void PlaneToView(const Point2D &planePointInMM, Point2D &viewPoint) const; double GetScaleFactorMMPerDisplayUnit() const; Point2D GetDisplaySizeInMM() const; Point2D GetViewportSizeInMM() const; Point2D GetOriginInMM() const; itkGetConstMacro(ConstrainZoomingAndPanning, bool) virtual void SetConstrainZoomingAndPanning(bool constrain); /** * \brief Provides (1) world coordinates for a given mouse position and (2) * translates mousePosition to Display coordinates * \deprecated Map2DRendererPositionTo3DWorldPosition is deprecated. Please use DisplayToWorld instead. */ DEPRECATED(virtual Point3D Map2DRendererPositionTo3DWorldPosition(const Point2D &mousePosition) const); protected: ~BaseRenderer() override; //##Documentation //## @brief Call update of all mappers. To be implemented in subclasses. virtual void Update() = 0; vtkRenderWindow *m_RenderWindow; vtkRenderer *m_VtkRenderer; //##Documentation //## @brief MapperSlotId to use. Defines which kind of mapper (e.g., 2D or 3D) shoud be used. MapperSlotId m_MapperID; //##Documentation //## @brief The DataStorage that is used for rendering. DataStorage::Pointer m_DataStorage; - //##Documentation - //## @brief The RenderingManager that manages this instance - RenderingManager::Pointer m_RenderingManager; - //##Documentation //## @brief Timestamp of last call of Update(). unsigned long m_LastUpdateTime; //##Documentation //## @brief CameraController for 3D rendering //## @note preliminary. itk::SmartPointer m_CameraController; SliceNavigationController::Pointer m_SliceNavigationController; CameraRotationController::Pointer m_CameraRotationController; //##Documentation //## @brief Sets m_CurrentWorldPlaneGeometry virtual void SetCurrentWorldPlaneGeometry(const PlaneGeometry *geometry2d); /** * \deprecatedSince{2014_10} Please use SetCurrentWorldPlaneGeometry */ DEPRECATED(void SetCurrentWorldGeometry2D(PlaneGeometry *geometry2d)) { SetCurrentWorldPlaneGeometry(geometry2d); }; //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(const BaseGeometry *geometry); private: //##Documentation //## m_WorldTimeGeometry is set by SetWorldGeometry if the passed BaseGeometry is a //## TimeGeometry (or a sub-class of it). If it contains instances of SlicedGeometry3D, //## m_Slice and m_TimeStep (set via SetSlice and SetTimeStep, respectively) define //## which 2D geometry stored in m_WorldTimeGeometry (if available) //## is used as m_CurrentWorldPlaneGeometry. //## \sa m_CurrentWorldPlaneGeometry TimeGeometry::ConstPointer m_WorldTimeGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. BaseGeometry::ConstPointer m_CurrentWorldGeometry; //##Documentation //## Pointer to the current 2D-worldgeometry. The 2D-worldgeometry //## describes the maximal area (2D manifold) to be rendered in case we //## are doing 2D-rendering. //## It is const, since we are not allowed to change it (it may be taken //## directly from the geometry of an image-slice and thus it would be //## very strange when suddenly the image-slice changes its geometry). PlaneGeometry::Pointer m_CurrentWorldPlaneGeometry; //##Documentation //## Defines together with m_Slice which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_Slice; //##Documentation //## Defines together with m_TimeStep which 2D geometry stored in m_WorldTimeGeometry //## is used as m_CurrentWorldPlaneGeometry: m_WorldTimeGeometry->GetPlaneGeometry(m_Slice, m_TimeStep). //## \sa m_WorldTimeGeometry unsigned int m_TimeStep; //##Documentation //## @brief timestamp of last call of SetWorldGeometry itk::TimeStamp m_CurrentWorldPlaneGeometryUpdateTime; //##Documentation //## @brief timestamp of last change of the current time step itk::TimeStamp m_TimeStepUpdateTime; //##Documentation //## @brief Helper class which establishes connection between Interactors and Dispatcher via a common DataStorage. BindDispatcherInteractor *m_BindDispatcherInteractor; //##Documentation //## @brief Tells if the displayed region should be shifted or rescaled if the render window is resized. bool m_KeepDisplayedRegion; protected: void PrintSelf(std::ostream &os, itk::Indent indent) const override; //##Documentation //## Data object containing the m_CurrentWorldPlaneGeometry defined above. PlaneGeometryData::Pointer m_CurrentWorldPlaneGeometryData; //##Documentation //## DataNode objects containing the m_CurrentWorldPlaneGeometryData defined above. DataNode::Pointer m_CurrentWorldPlaneGeometryNode; //##Documentation //## @brief test only unsigned long m_CurrentWorldPlaneGeometryTransformTime; std::string m_Name; double m_Bounds[6]; bool m_EmptyWorldGeometry; typedef std::set LODEnabledMappersType; /** Number of mappers which are visible and have level-of-detail * rendering enabled */ unsigned int m_NumberOfVisibleLODEnabledMappers; // Local Storage Handling for mappers protected: std::list m_RegisteredLocalStorageHandlers; bool m_ConstrainZoomingAndPanning; public: void RemoveAllLocalStorages(); void RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); void UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh); }; } // namespace mitk #endif /* BASERENDERER_H_HEADER_INCLUDED_C1CCA0F4 */ diff --git a/Modules/Core/include/mitkRenderWindow.h b/Modules/Core/include/mitkRenderWindow.h index 29fe7911ac..c844e09bd1 100644 --- a/Modules/Core/include/mitkRenderWindow.h +++ b/Modules/Core/include/mitkRenderWindow.h @@ -1,99 +1,95 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66ASDF #define MITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66ASDF #include #include "mitkRenderWindowBase.h" namespace mitk { class vtkEventProvider; /** * \brief mitkRenderWindow integrates the MITK rendering mechanism into VTK and * is NOT QT dependent * * * \ingroup Renderer */ class MITKCORE_EXPORT RenderWindow : public mitk::RenderWindowBase, public itk::Object { public: mitkClassMacroItkParent(RenderWindow, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, vtkRenderWindow *); mitkNewMacro2Param(Self, vtkRenderWindow *, const char *); - mitkNewMacro3Param(Self, vtkRenderWindow *, const char *, RenderingManager *); - mitkNewMacro4Param(Self, vtkRenderWindow *, const char *, RenderingManager *, BaseRenderer::RenderingMode); ~RenderWindow() override; vtkRenderWindow *GetVtkRenderWindow() override; vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() override; // Set Layout Index to define the Layout Type void SetLayoutIndex(unsigned int layoutIndex); // Get Layout Index to define the Layout Type unsigned int GetLayoutIndex(); // MenuWidget need to update the Layout Design List when Layout had changed void LayoutDesignListChanged(int layoutDesignIndex); void FullScreenMode(bool state); /** * \brief Convenience method to set the size of an mitkRenderWindow. * * This method sets the size of the vtkRenderWindow and tells the * rendering that the size has changed -> adapts displayGeometry, etc. */ void SetSize(int width, int height); /** * \brief Initializes the mitkVtkEventProvider to listen to the * currently used vtkInteractorStyle. * * This method makes sure that the internal mitkVtkEventProvider * listens to the correct vtkInteractorStyle. * This makes sure that VTK-Events are correctly translated into * MITK-Events. * * \warn This method needs to be called MANUALLY as soon as the MapperID * for this RenderWindow is changed or the vtkInteractorStyle is modified * somehow else! */ void ReinitEventProvider(); protected: RenderWindow(vtkRenderWindow *existingRenderWindow = nullptr, - const char *name = "unnamed renderer", - RenderingManager *rm = nullptr, - BaseRenderer::RenderingMode rmtype = BaseRenderer::RenderingMode::FastApproximateAntiAliasing); + const char *name = "unnamed renderer"); void ResetView(); vtkRenderWindow *m_vtkRenderWindow; vtkRenderWindowInteractor *m_vtkRenderWindowInteractor; vtkEventProvider *m_vtkMitkEventProvider; private: }; } // namespace #endif /* MITKRENDERWINDOW_H_HEADER_INCLUDED_C1C40D66ASDF */ diff --git a/Modules/Core/include/mitkRenderWindowBase.h b/Modules/Core/include/mitkRenderWindowBase.h index a56f2b6b42..cb40bfd305 100644 --- a/Modules/Core/include/mitkRenderWindowBase.h +++ b/Modules/Core/include/mitkRenderWindowBase.h @@ -1,83 +1,80 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKRENDERWINDOWBASE_H_HEADER_INCLUDED_C1C40D66ASDF #define MITKRENDERWINDOWBASE_H_HEADER_INCLUDED_C1C40D66ASDF #include #include "mitkCameraRotationController.h" #include "mitkSliceNavigationController.h" #include "mitkVtkPropRenderer.h" #include "vtkMitkRenderProp.h" #include "mitkInteractionEvent.h" namespace mitk { /** * \brief Base class of MITK RenderWindows * * This class sets up the MITK rendering mechanism and it's integration into VTK. * * Currently, there are two specific implementations of this abstract class: * QmitkRenderWindow, inerhits from the QVTKWidget and is the matured way for MITK rendering * mitkRenderWindow is a new, QT-independent RenderWindow implementation * * \ingroup Renderer */ class MITKCORE_EXPORT RenderWindowBase { public: // mitkClassMacroItkParent(RenderWindowBase,itk::Object); // itkFactorylessNewMacro(Self) // itkCloneMacro(Self) virtual ~RenderWindowBase(); void InitRenderer(); virtual mitk::SliceNavigationController *GetSliceNavigationController(); virtual mitk::CameraRotationController *GetCameraRotationController(); virtual mitk::BaseController *GetController(); virtual mitk::VtkPropRenderer *GetRenderer(); virtual vtkRenderWindow *GetVtkRenderWindow() = 0; virtual vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() = 0; virtual bool HandleEvent(InteractionEvent *interactionEvent); protected: RenderWindowBase(); // helper functions: within constructors and destructors classes are not polymorph. - void Initialize( - RenderingManager *renderingManager = nullptr, - const char *name = "unnamed renderer", - BaseRenderer::RenderingMode renderingMode = BaseRenderer::RenderingMode::FastApproximateAntiAliasing); + void Initialize(const char *name = "unnamed renderer"); void Destroy(); mitk::VtkPropRenderer::Pointer m_Renderer; vtkMitkRenderProp *m_RenderProp; bool m_InResize; private: }; } #endif /* MITKRENDERWINDOWBASE_H_HEADER_INCLUDED_C1C40D66ASDF */ diff --git a/Modules/Core/include/mitkRenderingManager.h b/Modules/Core/include/mitkRenderingManager.h index d013a62635..6d5c0357b4 100644 --- a/Modules/Core/include/mitkRenderingManager.h +++ b/Modules/Core/include/mitkRenderingManager.h @@ -1,399 +1,405 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 #define MITKRENDERINGMANAGER_H_HEADER_INCLUDED_C135A197 #include #include #include #include #include #include "mitkProperties.h" #include "mitkPropertyList.h" #include "mitkTimeGeometry.h" +#include class vtkRenderWindow; class vtkObject; namespace mitk { class RenderingManager; class RenderingManagerFactory; class BaseGeometry; class SliceNavigationController; class BaseRenderer; class DataStorage; /** * \brief Manager for coordinating the rendering process. * * RenderingManager is a central instance retrieving and executing * RenderWindow update requests. Its main purpose is to coordinate * distributed requests which cannot be aware of each other - lacking the * knowledge of whether they are really necessary or not. For example, two * objects might determine that a specific RenderWindow needs to be updated. * This would result in one unnecessary update, if both executed the update * on their own. * * The RenderingManager addresses this by letting each such object * request an update, and waiting for other objects to possibly * issue the same request. The actual update will then only be executed at a * well-defined point in the main event loop (this may be each time after * event processing is done). * * Convinience methods for updating all RenderWindows which have been * registered with the RenderingManager exist. If theses methods are not * used, it is not required to register (add) RenderWindows prior to using * the RenderingManager. * * The methods #ForceImmediateUpdate() and #ForceImmediateUpdateAll() can * be used to force the RenderWindow update execution without any delay, * bypassing the request functionality. * * The interface of RenderingManager is platform independent. Platform * specific subclasses have to be implemented, though, to supply an * appropriate event issueing for controlling the update execution process. * See method documentation for a description of how this can be done. * * \sa TestingRenderingManager An "empty" RenderingManager implementation which * can be used in tests etc. * */ class MITKCORE_EXPORT RenderingManager : public itk::Object { public: mitkClassMacroItkParent(RenderingManager, itk::Object); typedef std::vector RenderWindowVector; typedef std::vector FloatVector; typedef std::vector BoolVector; typedef itk::SmartPointer DataStoragePointer; enum RequestType { REQUEST_UPDATE_ALL = 0, REQUEST_UPDATE_2DWINDOWS, REQUEST_UPDATE_3DWINDOWS }; static Pointer New(); /** Set the object factory which produces the desired platform specific * RenderingManager singleton instance. */ static void SetFactory(RenderingManagerFactory *factory); /** Get the object factory which produces the platform specific * RenderingManager instances. */ static const RenderingManagerFactory *GetFactory(); /** Returns true if a factory has already been set. */ static bool HasFactory(); /** Get the RenderingManager singleton instance. */ static RenderingManager *GetInstance(); /** Returns true if the singleton instance does already exist. */ static bool IsInstantiated(); /** Adds a RenderWindow. This is required if the methods #RequestUpdateAll * or #ForceImmediateUpdate are to be used. */ void AddRenderWindow(vtkRenderWindow *renderWindow); /** Removes a RenderWindow. */ void RemoveRenderWindow(vtkRenderWindow *renderWindow); /** Get a list of all registered RenderWindows */ const RenderWindowVector &GetAllRegisteredRenderWindows(); /** Requests an update for the specified RenderWindow, to be executed as * soon as the main loop is ready for rendering. */ void RequestUpdate(vtkRenderWindow *renderWindow); /** Immediately executes an update of the specified RenderWindow. */ void ForceImmediateUpdate(vtkRenderWindow *renderWindow); /** Requests all currently registered RenderWindows to be updated. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void RequestUpdateAll(RequestType type = REQUEST_UPDATE_ALL); /** Immediately executes an update of all registered RenderWindows. * If only 2D or 3D windows should be updated, this can be specified * via the parameter requestType. */ void ForceImmediateUpdateAll(RequestType type = REQUEST_UPDATE_ALL); /** Initializes the windows specified by requestType to the geometry of the * given DataStorage. */ // virtual bool InitializeViews( const DataStorage *storage, const DataNode* node = nullptr, // RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false ); /** Initializes the windows specified by requestType to the given * geometry. PLATFORM SPECIFIC. TODO: HOW IS THIS PLATFORM SPECIFIC? * Throws an exception if bounding box has 0 extent due to exceeding * double precision range. */ virtual bool InitializeViews(const BaseGeometry *geometry, RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false); virtual bool InitializeViews(const TimeGeometry *geometry, RequestType type = REQUEST_UPDATE_ALL, bool preserveRoughOrientationInWorldSpace = false); /** Initializes the windows to the default viewing direction * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ virtual bool InitializeViews(RequestType type = REQUEST_UPDATE_ALL); /** Initializes the specified window to the geometry of the given * DataNode. Set "initializeGlobalTimeSNC" to true in order to use this * geometry as global TimeGeometry. PLATFORM SPECIFIC. */ // virtual bool InitializeView( vtkRenderWindow *renderWindow, const DataStorage* ds, const DataNode* node = nullptr, // bool initializeGlobalTimeSNC = false ); /** Initializes the specified window to the given geometry. Set * "initializeGlobalTimeSNC" to true in order to use this geometry as * global TimeGeometry. PLATFORM SPECIFIC. */ virtual bool InitializeView(vtkRenderWindow *renderWindow, const BaseGeometry *geometry, bool initializeGlobalTimeSNC = false); virtual bool InitializeView(vtkRenderWindow *renderWindow, const TimeGeometry *geometry, bool initializeGlobalTimeSNC = false); /** Initializes the specified window to the default viewing direction * (geomtry information is NOT changed). PLATFORM SPECIFIC. */ virtual bool InitializeView(vtkRenderWindow *renderWindow); /** * @brief Initializes the renderwindows by the aggregated geometry of * all objects that are held in the data storage. * This is basically a global reinit * @param The data storage from which the bounding object can be retrieved */ virtual void InitializeViewsByBoundingObjects(const DataStorage *); /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ const SliceNavigationController *GetTimeNavigationController() const; /** Gets the (global) SliceNavigationController responsible for * time-slicing. */ SliceNavigationController *GetTimeNavigationController(); ~RenderingManager() override; /** Executes all pending requests. This method has to be called by the * system whenever a RenderingManager induced request event occurs in * the system pipeline (see concrete RenderingManager implementations). */ virtual void ExecutePendingRequests(); bool IsRendering() const; void AbortRendering(); /** En-/Disable LOD increase globally. */ itkSetMacro(LODIncreaseBlocked, bool); /** En-/Disable LOD increase globally. */ itkGetMacro(LODIncreaseBlocked, bool); /** En-/Disable LOD increase globally. */ itkBooleanMacro(LODIncreaseBlocked); /** En-/Disable LOD abort mechanism. */ itkSetMacro(LODAbortMechanismEnabled, bool); /** En-/Disable LOD abort mechanism. */ itkGetMacro(LODAbortMechanismEnabled, bool); /** En-/Disable LOD abort mechanism. */ itkBooleanMacro(LODAbortMechanismEnabled); /** Force a sub-class to start a timer for a pending hires-rendering request */ virtual void StartOrResetTimer(){}; /** To be called by a sub-class from a timer callback */ void ExecutePendingHighResRenderingRequest(); virtual void DoStartRendering(){}; virtual void DoMonitorRendering(){}; virtual void DoFinishAbortRendering(){}; int GetNextLOD(BaseRenderer *renderer); /** Set current LOD (nullptr means all renderers)*/ void SetMaximumLOD(unsigned int max); void SetShading(bool state, unsigned int lod); bool GetShading(unsigned int lod); void SetClippingPlaneStatus(bool status); bool GetClippingPlaneStatus(); void SetShadingValues(float ambient, float diffuse, float specular, float specpower); FloatVector &GetShadingValues(); /** Returns a property list */ PropertyList::Pointer GetPropertyList() const; /** Returns a property from m_PropertyList */ BaseProperty *GetProperty(const char *propertyKey) const; /** Sets or adds (if not present) a property in m_PropertyList */ void SetProperty(const char *propertyKey, BaseProperty *propertyValue); /** * \brief Setter / Getter for internal DataStorage * * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are * rendered by the registered BaseRenderers. * * If this DataStorage is changed at runtime by calling SetDataStorage(), * all currently registered BaseRenderers are automatically given the correct instance. * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ void SetDataStorage(mitk::DataStorage *storage); /** * \brief Setter / Getter for internal DataStorage * * Sets / returns the mitk::DataStorage that is used internally. This instance holds all mitk::DataNodes that are * rendered by the registered BaseRenderers. * * If this DataStorage is changed at runtime by calling SetDataStorage(), * all currently registered BaseRenderers are automatically given the correct instance. * When a new BaseRenderer is added, it is automatically initialized with the currently active DataStorage. */ mitk::DataStorage *GetDataStorage(); /** * @brief Sets a flag to the given renderwindow to indicated that it has the focus e.g. has been clicked recently. * @param focusWindow */ void SetRenderWindowFocus(vtkRenderWindow *focusWindow); itkGetMacro(FocusedRenderWindow, vtkRenderWindow *) - itkSetMacro(ConstrainedPanningZooming, bool); + itkSetMacro(ConstrainedPanningZooming, bool); + + itkGetMacro(AntiAliasing, AntiAliasing) + + void SetAntiAliasing(AntiAliasing antiAliasing); protected: enum { RENDERING_INACTIVE = 0, RENDERING_REQUESTED, RENDERING_INPROGRESS }; RenderingManager(); /** Abstract method for generating a system specific event for rendering * request. This method is called whenever an update is requested */ virtual void GenerateRenderingRequestEvent() = 0; virtual void InitializePropertyList(); bool m_UpdatePending; typedef std::map RendererIntMap; typedef std::map RendererBoolMap; RendererBoolMap m_RenderingAbortedMap; RendererIntMap m_NextLODMap; unsigned int m_MaxLOD; bool m_LODIncreaseBlocked; bool m_LODAbortMechanismEnabled; BoolVector m_ShadingEnabled; bool m_ClippingPlaneEnabled; FloatVector m_ShadingValues; static void RenderingStartCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); static void RenderingProgressCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); static void RenderingEndCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); typedef std::map RenderWindowList; RenderWindowList m_RenderWindowList; RenderWindowVector m_AllRenderWindows; struct RenderWindowCallbacks { vtkCallbackCommand *commands[3u]; }; typedef std::map RenderWindowCallbacksList; RenderWindowCallbacksList m_RenderWindowCallbacksList; itk::SmartPointer m_TimeNavigationController; static RenderingManager::Pointer s_Instance; static RenderingManagerFactory *s_RenderingManagerFactory; PropertyList::Pointer m_PropertyList; DataStoragePointer m_DataStorage; bool m_ConstrainedPanningZooming; private: void InternalViewInitialization(mitk::BaseRenderer *baseRenderer, const mitk::TimeGeometry *geometry, bool boundingBoxInitialized, int mapperID); vtkRenderWindow *m_FocusedRenderWindow; + AntiAliasing m_AntiAliasing; }; #pragma GCC visibility push(default) itkEventMacro(RenderingManagerEvent, itk::AnyEvent); itkEventMacro(RenderingManagerViewsInitializedEvent, RenderingManagerEvent); #pragma GCC visibility pop itkEventMacroDeclaration(FocusChangedEvent, itk::AnyEvent) /** * Generic RenderingManager implementation for "non-rendering-plattform", * e.g. for tests. Its factory (TestingRenderingManagerFactory) is * automatically on start-up and is used by default if not other * RenderingManagerFactory is instantiated explicitly thereafter. * (see mitkRenderingManager.cpp) */ class MITKCORE_EXPORT TestingRenderingManager : public RenderingManager { public: mitkClassMacro(TestingRenderingManager, RenderingManager); itkFactorylessNewMacro(Self) itkCloneMacro(Self) protected : void GenerateRenderingRequestEvent() override{ // ForceImmediateUpdateAll(); }; }; } // namespace mitk #endif /* MITKRenderingManager_H_HEADER_INCLUDED_C135A197 */ diff --git a/Modules/Core/include/mitkSliceNavigationController.h b/Modules/Core/include/mitkSliceNavigationController.h index 89f122fe2a..a37c86e2ef 100644 --- a/Modules/Core/include/mitkSliceNavigationController.h +++ b/Modules/Core/include/mitkSliceNavigationController.h @@ -1,518 +1,510 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #define SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F #include "mitkBaseController.h" #include "mitkMessage.h" #include "mitkRenderingManager.h" #include "mitkTimeGeometry.h" #include #pragma GCC visibility push(default) #include #pragma GCC visibility pop #include "mitkDataStorage.h" #include "mitkRestorePlanePositionOperation.h" #include #include // DEPRECATED #include namespace mitk { #define mitkTimeSlicedGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT DEPRECATED(classname) : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } #define mitkTimeGeometryEventMacro(classname, super) \ class MITKCORE_EXPORT classname : public super \ { \ public: \ typedef classname Self; \ typedef super Superclass; \ classname(TimeGeometry *aTimeGeometry, unsigned int aPos) : Superclass(aTimeGeometry, aPos) {} \ virtual ~classname() {} \ virtual const char *GetEventName() const { return #classname; } \ virtual bool CheckEvent(const ::itk::EventObject *e) const { return dynamic_cast(e); } \ virtual ::itk::EventObject *MakeObject() const { return new Self(GetTimeGeometry(), GetPos()); } \ private: \ void operator=(const Self &); \ } class PlaneGeometry; class BaseGeometry; class BaseRenderer; /** * \brief Controls the selection of the slice the associated BaseRenderer * will display * * A SliceNavigationController takes a BaseGeometry or a TimeGeometry as input world geometry * (TODO what are the exact requirements?) and generates a TimeGeometry * as output. The TimeGeometry holds a number of SlicedGeometry3Ds and * these in turn hold a series of PlaneGeometries. One of these PlaneGeometries is * selected as world geometry for the BaseRenderers associated to 2D views. * * The SliceNavigationController holds has Steppers (one for the slice, a * second for the time step), which control the selection of a single * PlaneGeometry from the TimeGeometry. SliceNavigationController generates * ITK events to tell observers, like a BaseRenderer, when the selected slice * or timestep changes. * * Example: * \code * // Initialization * sliceCtrl = mitk::SliceNavigationController::New(); * * // Tell the navigator the geometry to be sliced (with geometry a * // BaseGeometry::ConstPointer) * sliceCtrl->SetInputWorldGeometry(geometry.GetPointer()); * * // Tell the navigator in which direction it shall slice the data * sliceCtrl->SetViewDirection(mitk::SliceNavigationController::Axial); * * // Connect one or more BaseRenderer to this navigator, i.e.: events sent * // by the navigator when stepping through the slices (e.g. by * // sliceCtrl->GetSlice()->Next()) will be received by the BaseRenderer * // (in this example only slice-changes, see also ConnectGeometryTimeEvent * // and ConnectGeometryEvents.) * sliceCtrl->ConnectGeometrySliceEvent(renderer.GetPointer()); * * //create a world geometry and send the information to the connected renderer(s) * sliceCtrl->Update(); * \endcode * * * You can connect visible navigators to a SliceNavigationController, e.g., a * QmitkSliderNavigator (for Qt): * * \code * // Create the visible navigator (a slider with a spin-box) * QmitkSliderNavigator* navigator = * new QmitkSliderNavigator(parent, "slidernavigator"); * * // Connect the navigator to the slice-stepper of the * // SliceNavigationController. For initialization (position, mininal and * // maximal values) the values of the SliceNavigationController are used. * // Thus, accessing methods of a navigator is normally not necessary, since * // everything can be set via the (Qt-independent) SliceNavigationController. * // The QmitkStepperAdapter converts the Qt-signals to Qt-independent * // itk-events. * new QmitkStepperAdapter(navigator, sliceCtrl->GetSlice(), "navigatoradaptor"); * \endcode * * If you do not want that all renderwindows are updated when a new slice is * selected, you can use a specific RenderingManager, which updates only those * renderwindows that should be updated. This is sometimes useful when a 3D view * does not need to be updated when the slices in some 2D views are changed. * QmitkSliderNavigator (for Qt): * * \code * // create a specific RenderingManager * mitk::RenderingManager::Pointer myManager = mitk::RenderingManager::New(); * * // tell the RenderingManager to update only renderwindow1 and renderwindow2 * myManager->AddRenderWindow(renderwindow1); * myManager->AddRenderWindow(renderwindow2); * * // tell the SliceNavigationController of renderwindow1 and renderwindow2 * // to use the specific RenderingManager instead of the global one * renderwindow1->GetSliceNavigationController()->SetRenderingManager(myManager); * renderwindow2->GetSliceNavigationController()->SetRenderingManager(myManager); * \endcode * * \todo implement for non-evenly-timed geometry! * \ingroup NavigationControl */ class MITKCORE_EXPORT SliceNavigationController : public BaseController { public: mitkClassMacro(SliceNavigationController, BaseController); // itkFactorylessNewMacro(Self) // mitkNewMacro1Param(Self, const char *); itkNewMacro(Self); // itkCloneMacro(Self) /** * \brief Possible view directions, \a Original will uses * the PlaneGeometry instances in a SlicedGeometry3D provided * as input world geometry (by SetInputWorldGeometry). */ enum ViewDirection { Axial, Sagittal, Frontal, Original }; /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. */ void SetInputWorldGeometry3D(const mitk::BaseGeometry *geometry); itkGetConstObjectMacro(InputWorldGeometry3D, mitk::BaseGeometry); /** * \brief Set the input world geometry3D out of which the * geometries for slicing will be created. * * Any previous previous set input geometry (3D or Time) will * be ignored in future. * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(void SetInputWorldGeometry(const mitk::TimeSlicedGeometry *geometry)); /** * \deprecatedSince{2013_09} Please use TimeGeometry instead of TimeSlicedGeometry. For more information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(TimeSlicedGeometry *GetInputWorldGeometry()); void SetInputWorldTimeGeometry(const mitk::TimeGeometry *geometry); itkGetConstObjectMacro(InputWorldTimeGeometry, mitk::TimeGeometry); /** * \brief Access the created geometry */ itkGetConstObjectMacro(CreatedWorldGeometry, mitk::TimeGeometry); /** * \brief Set the desired view directions * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(ViewDirection, ViewDirection); itkGetEnumMacro(ViewDirection, ViewDirection); /** * \brief Set the default view direction * * This is used to re-initialize the view direction of the SNC to the * default value with SetViewDirectionToDefault() * * \sa ViewDirection * \sa Update(ViewDirection viewDirection, bool top = true, * bool frontside = true, bool rotated = false) */ itkSetEnumMacro(DefaultViewDirection, ViewDirection); itkGetEnumMacro(DefaultViewDirection, ViewDirection); const char *GetViewDirectionAsString() const; virtual void SetViewDirectionToDefault(); /** * \brief Do the actual creation and send it to the connected * observers (renderers) * */ virtual void Update(); /** * \brief Extended version of Update, additionally allowing to * specify the direction/orientation of the created geometry. * */ virtual void Update(ViewDirection viewDirection, bool top = true, bool frontside = true, bool rotated = false); /** * \brief Send the created geometry to the connected * observers (renderers) * * Called by Update(). */ virtual void SendCreatedWorldGeometry(); /** * \brief Tell observers to re-read the currently selected 2D geometry * */ virtual void SendCreatedWorldGeometryUpdate(); /** * \brief Send the currently selected slice to the connected * observers (renderers) * * Called by Update(). */ virtual void SendSlice(); /** * \brief Send the currently selected time to the connected * observers (renderers) * * Called by Update(). */ virtual void SendTime(); - /** - * \brief Set the RenderingManager to be used - * - * If \a nullptr, the default RenderingManager will be used. - */ - itkSetObjectMacro(RenderingManager, RenderingManager); - mitk::RenderingManager *GetRenderingManager() const; - #pragma GCC visibility push(default) itkEventMacro(UpdateEvent, itk::AnyEvent); #pragma GCC visibility pop class MITKCORE_EXPORT TimeGeometryEvent : public itk::AnyEvent { public: typedef TimeGeometryEvent Self; typedef itk::AnyEvent Superclass; TimeGeometryEvent(TimeGeometry *aTimeGeometry, unsigned int aPos) : m_TimeGeometry(aTimeGeometry), m_Pos(aPos) {} ~TimeGeometryEvent() override {} const char *GetEventName() const override { return "TimeGeometryEvent"; } bool CheckEvent(const ::itk::EventObject *e) const override { return dynamic_cast(e); } ::itk::EventObject *MakeObject() const override { return new Self(m_TimeGeometry, m_Pos); } TimeGeometry *GetTimeGeometry() const { return m_TimeGeometry; } unsigned int GetPos() const { return m_Pos; } private: TimeGeometry::Pointer m_TimeGeometry; unsigned int m_Pos; // TimeGeometryEvent(const Self&); void operator=(const Self &); // just hide }; /** * \deprecatedSince{2013_09} Please use TimeGeometryEvent instead: For additional information see * http://www.mitk.org/Development/Refactoring%20of%20the%20Geometry%20Classes%20-%20Part%201 */ DEPRECATED(typedef TimeGeometryEvent TimeSlicedGeometryEvent); mitkTimeGeometryEventMacro(GeometrySendEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryUpdateEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometryTimeEvent, TimeGeometryEvent); mitkTimeGeometryEventMacro(GeometrySliceEvent, TimeGeometryEvent); template void ConnectGeometrySendEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometry); unsigned long tag = AddObserver(GeometrySendEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometryUpdateEvent(T *receiver) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::UpdateGeometry); unsigned long tag = AddObserver(GeometryUpdateEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); } template void ConnectGeometrySliceEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometrySlice); unsigned long tag = AddObserver(GeometrySliceEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryTimeEvent(T *receiver, bool connectSendEvent = true) { typedef typename itk::ReceptorMemberCommand::Pointer ReceptorMemberCommandPointer; ReceptorMemberCommandPointer eventReceptorCommand = itk::ReceptorMemberCommand::New(); eventReceptorCommand->SetCallbackFunction(receiver, &T::SetGeometryTime); unsigned long tag = AddObserver(GeometryTimeEvent(nullptr, 0), eventReceptorCommand); m_ReceiverToObserverTagsMap[static_cast(receiver)].push_back(tag); if (connectSendEvent) ConnectGeometrySendEvent(receiver); } template void ConnectGeometryEvents(T *receiver) { // connect sendEvent only once ConnectGeometrySliceEvent(receiver, false); ConnectGeometryTimeEvent(receiver); } // use a templated method to get the right offset when casting to void* template void Disconnect(T *receiver) { auto i = m_ReceiverToObserverTagsMap.find(static_cast(receiver)); if (i == m_ReceiverToObserverTagsMap.end()) return; const std::list &tags = i->second; for (auto tagIter = tags.begin(); tagIter != tags.end(); ++tagIter) { RemoveObserver(*tagIter); } m_ReceiverToObserverTagsMap.erase(i); } Message1 SetCrosshairEvent; /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface * \warning not implemented */ virtual void SetGeometry(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometrySlice(const itk::EventObject &geometrySliceEvent); /** * \brief To connect multiple SliceNavigationController, we can * act as an observer ourselves: implemented interface */ virtual void SetGeometryTime(const itk::EventObject &geometryTimeEvent); /** \brief Positions the SNC according to the specified point */ void SelectSliceByPoint(const mitk::Point3D &point); /** \brief Returns the TimeGeometry created by the SNC. */ mitk::TimeGeometry *GetCreatedWorldGeometry(); /** \brief Returns the BaseGeometry of the currently selected time step. */ const mitk::BaseGeometry *GetCurrentGeometry3D(); /** \brief Returns the currently selected Plane in the current * BaseGeometry (if existent). */ const mitk::PlaneGeometry *GetCurrentPlaneGeometry(); /** \brief Sets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. */ void SetRenderer(BaseRenderer *renderer); /** \brief Gets the BaseRenderer associated with this SNC (if any). While * the BaseRenderer is not directly used by SNC, this is a convenience * method to enable BaseRenderer access via the SNC. Returns nullptr if no * BaseRenderer has been specified*/ BaseRenderer *GetRenderer() const; /** \brief Re-orients the slice stack. All slices will be oriented to the given normal vector. The given point (world coordinates) defines the selected slice. Careful: The resulting axis vectors are not clearly defined this way. If you want to define them clearly, use ReorientSlices (const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1). */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &normal); /** \brief Re-orients the slice stack so that all planes are oriented according to the * given axis vectors. The given Point eventually defines selected slice. */ void ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1); void ExecuteOperation(Operation *operation) override; /** * \brief Feature option to lock planes during mouse interaction. * This option flag disables the mouse event which causes the center * cross to move near by. */ itkSetMacro(SliceLocked, bool); itkGetMacro(SliceLocked, bool); itkBooleanMacro(SliceLocked); /** * \brief Feature option to lock slice rotation. * * This option flag disables separately the rotation of a slice which is * implemented in mitkSliceRotator. */ itkSetMacro(SliceRotationLocked, bool); itkGetMacro(SliceRotationLocked, bool); itkBooleanMacro(SliceRotationLocked); /** * \brief Adjusts the numerical range of the slice stepper according to * the current geometry orientation of this SNC's SlicedGeometry. */ void AdjustSliceStepperRange(); protected: SliceNavigationController(); ~SliceNavigationController() override; mitk::BaseGeometry::ConstPointer m_InputWorldGeometry3D; mitk::TimeGeometry::ConstPointer m_InputWorldTimeGeometry; mitk::TimeGeometry::Pointer m_CreatedWorldGeometry; ViewDirection m_ViewDirection; ViewDirection m_DefaultViewDirection; mitk::RenderingManager::Pointer m_RenderingManager; mitk::BaseRenderer *m_Renderer; itkSetMacro(Top, bool); itkGetMacro(Top, bool); itkBooleanMacro(Top); itkSetMacro(FrontSide, bool); itkGetMacro(FrontSide, bool); itkBooleanMacro(FrontSide); itkSetMacro(Rotated, bool); itkGetMacro(Rotated, bool); itkBooleanMacro(Rotated); bool m_Top; bool m_FrontSide; bool m_Rotated; bool m_BlockUpdate; bool m_SliceLocked; bool m_SliceRotationLocked; unsigned int m_OldPos; typedef std::map> ObserverTagsMapType; ObserverTagsMapType m_ReceiverToObserverTagsMap; }; } // namespace mitk #endif /* SLICENAVIGATIONCONTROLLER_H_HEADER_INCLUDED_C1C55A2F */ diff --git a/Modules/Core/include/mitkVtkPropRenderer.h b/Modules/Core/include/mitkVtkPropRenderer.h index 28b7738229..1deca69172 100644 --- a/Modules/Core/include/mitkVtkPropRenderer.h +++ b/Modules/Core/include/mitkVtkPropRenderer.h @@ -1,258 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkVtkPropRenderer_h #define mitkVtkPropRenderer_h #include "mitkBaseRenderer.h" #include #include #include #include #include #include class vtkRenderWindow; class vtkLight; class vtkLightKit; class vtkWorldPointPicker; class vtkPointPicker; class vtkCellPicker; class vtkTextActor; class vtkTextProperty; class vtkAssemblyPath; #include #include namespace mitk { class Mapper; /*! \brief VtkPropRenderer VtkPropRenderer organizes the MITK rendering process. The MITK rendering process is completely integrated into the VTK rendering pipeline. The vtkMitkRenderProp is a custom vtkProp derived class, which implements the rendering interface between MITK and VTK. It redirects render() calls to the VtkPropRenderer, which is responsible for rendering of the datatreenodes. VtkPropRenderer replaces the old OpenGLRenderer. \sa rendering \ingroup rendering */ class MITKCORE_EXPORT VtkPropRenderer : public BaseRenderer { // Workaround for Displaylistbug private: bool didCount; void checkState(); // Workaround END public: mitkClassMacro(VtkPropRenderer, BaseRenderer); - mitkNewMacro3Param(VtkPropRenderer, const char *, vtkRenderWindow *, mitk::RenderingManager *); - mitkNewMacro4Param(VtkPropRenderer, - const char *, - vtkRenderWindow *, - mitk::RenderingManager *, - mitk::BaseRenderer::RenderingMode); + mitkNewMacro2Param(VtkPropRenderer, const char*, vtkRenderWindow*); typedef std::map MappersMapType; // Render - called by vtkMitkRenderProp, returns the number of props rendered enum RenderType { Opaque, Translucent, Overlay, Volumetric }; /** \brief Store/propagate vtkInformation during rendering */ void SetPropertyKeys(vtkInformation *info); int Render(RenderType type); /** \brief This methods contains all method neceassary before a VTK Render() call */ virtual void PrepareRender(); // Active current renderwindow virtual void MakeCurrent(); void SetDataStorage( mitk::DataStorage *storage) override; ///< set the datastorage that will be used for rendering void InitRenderer(vtkRenderWindow *renderwindow) override; virtual void Update(mitk::DataNode *datatreenode); void SetMapperID(const MapperSlotId mapperId) override; // Size void InitSize(int w, int h) override; void Resize(int w, int h) override; // Picking enum PickingMode { WorldPointPicking, PointPicking, CellPicking }; /** \brief Set the picking mode. This method is used to set the picking mode for 3D object picking. The user can select one of the three options WorldPointPicking, PointPicking and CellPicking. The first option uses the zBuffer from graphics rendering, the second uses the 3D points from the closest surface mesh, and the third option uses the cells of that mesh. The last option is the slowest, the first one the fastest. However, the first option cannot use transparent data object and the tolerance of the picked position to the selected point should be considered. PointPicking also need a tolerance around the picking position to select the closest point in the mesh. The CellPicker performs very well, if the foreground surface part (i.e. the surfacepart that is closest to the scene's cameras) needs to be picked. */ itkSetEnumMacro(PickingMode, PickingMode); itkGetEnumMacro(PickingMode, PickingMode); void PickWorldPoint(const Point2D &displayPoint, Point3D &worldPoint) const override; mitk::DataNode *PickObject(const Point2D &displayPosition, Point3D &worldPosition) const override; /** * @brief WriteSimpleText Write a text in a renderwindow. * * Writes some 2D text as overlay. Function returns an unique int Text_ID for each call, which can be used via the GetTextLabelProperty(int text_id) function in order to get a vtkTextProperty. This property enables the setup of font, font size, etc. * * @deprecatedSince{2015_05} Please use mitkTextOverlay2D instead. * See mitkTextOverlay2DRenderingTest for an example. */ DEPRECATED(int WriteSimpleText(std::string text, double posX, double posY, double color1 = 0.0, double color2 = 1.0, double color3 = 0.0, float opacity = 1.0)); /** * @brief CGetTextLabelProperty an be used in order to get a vtkTextProperty for * a specific text_id. This property enables the setup of font, font size, etc. * @param text_id the id of the text property. * @deprecatedSince{2015_05} Please use mitkTextOverlay2D instead. * See mitkTextOverlay2DRenderingTest for an example. */ DEPRECATED(vtkTextProperty *GetTextLabelProperty(int text_id)); /** This method calculates the bounds of the DataStorage (if it contains any * valid data), creates a geometry from these bounds and sets it as world * geometry of the renderer. * * Call this method to re-initialize the renderer to the current DataStorage * (e.g. after loading an additional dataset), to ensure that the view is * aligned correctly. */ bool SetWorldGeometryToDataStorageBounds() override; /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ void InitPathTraversal(); /** * \brief Used by vtkPointPicker/vtkPicker. * This will query a list of all objects in MITK and provide every vtk based mapper to the picker. */ vtkAssemblyPath *GetNextPath(); int GetNumberOfPaths(); const vtkWorldPointPicker *GetWorldPointPicker() const; const vtkPointPicker *GetPointPicker() const; const vtkCellPicker *GetCellPicker() const; /** * \brief Release vtk-based graphics resources. Called by * vtkMitkRenderProp::ReleaseGraphicsResources. */ virtual void ReleaseGraphicsResources(vtkWindow *renWin); MappersMapType GetMappersMap() const; static bool useImmediateModeRendering(); protected: - VtkPropRenderer( - const char *name = "VtkPropRenderer", - vtkRenderWindow *renWin = nullptr, - mitk::RenderingManager *rm = nullptr, - mitk::BaseRenderer::RenderingMode renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing); + VtkPropRenderer(const char *name = "VtkPropRenderer", vtkRenderWindow *renWin = nullptr); ~VtkPropRenderer() override; void Update() override; static void RenderingCallback(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); virtual void UpdatePaths(); // apply transformations and properties recursively private: vtkSmartPointer m_Paths; vtkTimeStamp m_PathTime; // prepare all mitk::mappers for rendering void PrepareMapperQueue(); /** \brief Propagate vtkInformation object to all VTK-based mappers */ void PropagateRenderInfoToMappers(); /** \brief Set parallel projection, remove the interactor and the lights of VTK. */ bool Initialize2DvtkCamera(); bool m_InitNeeded; bool m_ResizeNeeded; MapperSlotId m_CameraInitializedForMapperID; // Picking vtkWorldPointPicker *m_WorldPointPicker; vtkPointPicker *m_PointPicker; vtkCellPicker *m_CellPicker; PickingMode m_PickingMode; // Explicit use of SmartPointer to avoid circular #includes itk::SmartPointer m_CurrentWorldPlaneGeometryMapper; vtkLightKit *m_LightKit; // sorted list of mappers MappersMapType m_MappersMap; // rendering of text vtkRenderer *m_TextRenderer; typedef std::map TextMapType; TextMapType m_TextCollection; /** \brief Information passed from VTK's rendering to props. Used e.g. by vtkDualDepthPeelingPass to pass information. Not passing this to all the MITK generated vktProps will essentially break VTK's depth peeling / transparency. */ vtkInformation* m_VtkRenderInfo = nullptr; }; } // namespace mitk #endif /* mitkVtkPropRenderer_h */ diff --git a/Modules/Core/src/Controllers/mitkCameraController.cpp b/Modules/Core/src/Controllers/mitkCameraController.cpp index 1556cb09f2..8c2fdf5e71 100644 --- a/Modules/Core/src/Controllers/mitkCameraController.cpp +++ b/Modules/Core/src/Controllers/mitkCameraController.cpp @@ -1,351 +1,350 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCameraController.h" #include "mitkRenderingManager.h" #include "mitkVtkPropRenderer.h" #include "vtkCommand.h" #include #include "vtkCamera.h" #include "vtkRenderer.h" #include #include mitk::CameraController::CameraController() : BaseController(), m_Renderer(nullptr) { } mitk::CameraController::~CameraController() { } mitk::ScalarType mitk::CameraController::ComputeMaxParallelScale() { double widthInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0); double heightInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1); double dispHeight = this->GetRenderer()->GetViewportSize()[1]; // in pixel! double dispWidth = this->GetRenderer()->GetViewportSize()[0]; // To get the right zooming factor, we need to set the (half) height to the vtk camera using SetParallelScale. // However, it could be, that our picture is so wide or the display so small, that we cannot take the height of the // picture. // For a wide picture, we have to take the width and adapt the width so that our image fits to the screen. // But we can only set the height. Therefore, if the width is the limiting factor, we need to get the ratio of scaling // for the width and multiply it with the height, so that we have a modified height and set this one. Believe us, we // figured it out... if ((dispWidth / widthInMM) < (dispHeight / heightInMM)) { heightInMM = widthInMM / dispWidth * dispHeight; } return heightInMM * 0.5; } void mitk::CameraController::AdjustConstrainedCameraPosition(mitk::Point2D &planePoint) { // TODO: GetExtentInMM is calculated wrong for rotated planes, e.g. crosshair rotation (bug 19105) double widthInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0); double heightInMM = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1); mitk::Point2D dispSizeInMM = this->GetRenderer()->GetViewportSizeInMM(); double xMin, xMax, yMin, yMax; // different calculation of min/max if display is lager/smaller than image. // note, that the plane Position defines the middle of the display but is in image coordinates //([0,0] is defined by the image, so planePosition can sometimes be negative). if (dispSizeInMM[0] > widthInMM) { xMin = widthInMM - 0.5 * dispSizeInMM[0]; xMax = 0.5 * dispSizeInMM[0]; } else { xMin = 0.5 * dispSizeInMM[0]; xMax = widthInMM - 0.5 * dispSizeInMM[0]; } if (dispSizeInMM[1] > heightInMM) { yMin = heightInMM - 0.5 * dispSizeInMM[1]; yMax = 0.5 * dispSizeInMM[1]; } else { yMin = 0.5 * dispSizeInMM[1]; yMax = heightInMM - 0.5 * dispSizeInMM[1]; } if (planePoint[0] < xMin) { planePoint[0] = xMin; } if (planePoint[1] < yMin) { planePoint[1] = yMin; } if (planePoint[0] > xMax) { planePoint[0] = xMax; } if (planePoint[1] > yMax) { planePoint[1] = yMax; } } void mitk::CameraController::SetViewToAnterior() { this->SetStandardView(ANTERIOR); } void mitk::CameraController::SetViewToPosterior() { this->SetStandardView(POSTERIOR); } void mitk::CameraController::SetViewToSinister() { this->SetStandardView(SINISTER); } void mitk::CameraController::SetViewToDexter() { this->SetStandardView(DEXTER); } void mitk::CameraController::SetViewToCranial() { this->SetStandardView(CRANIAL); } void mitk::CameraController::SetViewToCaudal() { this->SetStandardView(CAUDAL); } void mitk::CameraController::SetStandardView(mitk::CameraController::StandardView view) { const auto *glRenderer = dynamic_cast(m_Renderer); if (glRenderer == nullptr) return; vtkRenderer *vtkRenderer = glRenderer->GetVtkRenderer(); assert(vtkRenderer); mitk::BoundingBox::Pointer bb; mitk::DataStorage *ds = m_Renderer->GetDataStorage(); if (ds != nullptr) bb = ds->ComputeBoundingBox(); else return; if (m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D) { // set up the view for the 3D render window. The views for 2D are set up in the mitkVtkPropRenderer mitk::Point3D middle = bb->GetCenter(); vtkRenderer->GetActiveCamera()->SetFocalPoint(middle[0], middle[1], middle[2]); switch (view) { case ANTERIOR: case POSTERIOR: case SINISTER: case DEXTER: vtkRenderer->GetActiveCamera()->SetViewUp(0, 0, 1); break; case CRANIAL: case CAUDAL: vtkRenderer->GetActiveCamera()->SetViewUp(0, -1, 0); break; } switch (view) { case ANTERIOR: vtkRenderer->GetActiveCamera()->SetPosition(middle[0], -100000, middle[2]); break; case POSTERIOR: vtkRenderer->GetActiveCamera()->SetPosition(middle[0], +100000, middle[2]); break; case SINISTER: vtkRenderer->GetActiveCamera()->SetPosition(+100000, middle[1], middle[2]); break; case DEXTER: vtkRenderer->GetActiveCamera()->SetPosition(-100000, middle[1], middle[2]); break; case CRANIAL: vtkRenderer->GetActiveCamera()->SetPosition(middle[0], middle[1], 100000); break; case CAUDAL: vtkRenderer->GetActiveCamera()->SetPosition(middle[0], middle[1], -100000); break; } vtkRenderer->ResetCamera(); vtkRenderer->ResetCameraClippingRange(); } - mitk::RenderingManager *rm = m_Renderer->GetRenderingManager(); - rm->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::CameraController::MoveCameraToPoint(const mitk::Point2D &planePoint) { Point2D moveToPoint = planePoint; AdjustCameraToPlane(moveToPoint); this->Modified(); } void mitk::CameraController::MoveBy(const mitk::Vector2D &moveVectorInMM) { MoveCameraToPoint(GetCameraPositionOnPlane() + moveVectorInMM); } void mitk::CameraController::Zoom(ScalarType factor, const Point2D &zoomPointInMM) { if (factor <= 0.0) return; if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D) { double parallelScale = this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->GetParallelScale() / factor; if (this->GetRenderer()->GetConstrainZoomingAndPanning() && factor < 1.0) { double maxParallelScale = ComputeMaxParallelScale(); if (maxParallelScale - parallelScale * factor < mitk::eps) // this is not the famous 05-bug... Return if already near max zooming return; if (parallelScale > maxParallelScale) { parallelScale = maxParallelScale; } } this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(parallelScale); // Move camera in a way that the clicked point stays visible on the display where it was. Point2D planePoint = GetCameraPositionOnPlane(); MoveCameraToPoint(planePoint + ((zoomPointInMM - planePoint) * (factor - 1))); } } mitk::Point2D mitk::CameraController::GetCameraPositionOnPlane() { Point2D CamPosOnPlane; CamPosOnPlane[0] = this->GetRenderer()->GetVtkRenderer()->GetCenter()[0]; CamPosOnPlane[1] = this->GetRenderer()->GetVtkRenderer()->GetCenter()[1]; this->GetRenderer()->DisplayToPlane(CamPosOnPlane, CamPosOnPlane); return CamPosOnPlane; } void mitk::CameraController::AdjustCameraToPlane() { if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D) { AdjustCameraToPlane(GetCameraPositionOnPlane()); } } void mitk::CameraController::AdjustCameraToPlane(const Point2D &PlanePoint) { if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D) { Point2D _planePoint = PlanePoint; // PlanePoint is const... if (this->GetRenderer()->GetConstrainZoomingAndPanning()) { double parallelScale = this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->GetParallelScale(); double maxParallelScale = ComputeMaxParallelScale(); if (parallelScale > maxParallelScale) { this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(maxParallelScale); } AdjustConstrainedCameraPosition(_planePoint); } const PlaneGeometry *planeGeometry = this->GetRenderer()->GetCurrentWorldPlaneGeometry(); if (planeGeometry != nullptr) { this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetViewUp(0, 1, 0); // set the view-up for the camera this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetPosition(_planePoint[0], _planePoint[1], 900000); this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetFocalPoint(_planePoint[0], _planePoint[1], 0); // Transform the camera to the current position (transversal, coronal and sagittal plane). // This is necessary, because the SetUserTransform() method does not manipulate the vtkCamera. //(Without not all three planes would be visible). vtkSmartPointer trans = vtkSmartPointer::New(); vtkSmartPointer matrix = vtkSmartPointer::New(); Point3D origin; Vector3D right, bottom, normal; origin = planeGeometry->GetOrigin(); right = planeGeometry->GetAxisVector(0); // right = Extent of Image in mm (worldspace) bottom = planeGeometry->GetAxisVector(1); normal = planeGeometry->GetNormal(); right.Normalize(); bottom.Normalize(); normal.Normalize(); matrix->SetElement(0, 0, right[0]); matrix->SetElement(1, 0, right[1]); matrix->SetElement(2, 0, right[2]); matrix->SetElement(0, 1, bottom[0]); matrix->SetElement(1, 1, bottom[1]); matrix->SetElement(2, 1, bottom[2]); matrix->SetElement(0, 2, normal[0]); matrix->SetElement(1, 2, normal[1]); matrix->SetElement(2, 2, normal[2]); matrix->SetElement(0, 3, origin[0]); matrix->SetElement(1, 3, origin[1]); matrix->SetElement(2, 3, origin[2]); matrix->SetElement(3, 0, 0.0); matrix->SetElement(3, 1, 0.0); matrix->SetElement(3, 2, 0.0); matrix->SetElement(3, 3, 1.0); trans->SetMatrix(matrix); // Transform the camera to the current position (transversal, coronal and sagittal plane). this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->ApplyTransform(trans); } } } void mitk::CameraController::Fit() { if (this->GetRenderer()->GetMapperID() == BaseRenderer::Standard2D) { this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(ComputeMaxParallelScale()); this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetClippingRange(0.1, 1000000); // Reason for huge range: VTK seems to calculate the clipping planes wrong for small values. See VTK bug (id #7823) // in VTK bugtracker. Point2D planePoint; planePoint[0] = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(0) * 0.5; planePoint[1] = this->GetRenderer()->GetCurrentWorldPlaneGeometry()->GetExtentInMM(1) * 0.5; MoveCameraToPoint(planePoint); } } void mitk::CameraController::SetScaleFactorInMMPerDisplayUnit(ScalarType scale) { if (this->GetRenderer()->GetMapperID() != BaseRenderer::Standard2D) { return; } this->GetRenderer()->GetVtkRenderer()->GetActiveCamera()->SetParallelScale(this->GetRenderer()->GetViewportSize()[1] * scale * 0.5); this->Modified(); } diff --git a/Modules/Core/src/Controllers/mitkRenderingManager.cpp b/Modules/Core/src/Controllers/mitkRenderingManager.cpp index a92142ac93..6cb919246b 100644 --- a/Modules/Core/src/Controllers/mitkRenderingManager.cpp +++ b/Modules/Core/src/Controllers/mitkRenderingManager.cpp @@ -1,744 +1,771 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRenderingManager.h" #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateProperty.h" #include "mitkProportionalTimeGeometry.h" #include "mitkRenderingManagerFactory.h" #include +#include #include "mitkNumericTypes.h" #include #include #include #include #include namespace mitk { itkEventMacroDefinition(FocusChangedEvent, itk::AnyEvent) RenderingManager::Pointer RenderingManager::s_Instance = nullptr; RenderingManagerFactory *RenderingManager::s_RenderingManagerFactory = nullptr; RenderingManager::RenderingManager() : m_UpdatePending(false), m_MaxLOD(1), m_LODIncreaseBlocked(false), m_LODAbortMechanismEnabled(false), m_ClippingPlaneEnabled(false), m_TimeNavigationController(SliceNavigationController::New()), m_DataStorage(nullptr), m_ConstrainedPanningZooming(true), - m_FocusedRenderWindow(nullptr) + m_FocusedRenderWindow(nullptr), + m_AntiAliasing(AntiAliasing::FastApproximate) { m_ShadingEnabled.assign(3, false); m_ShadingValues.assign(4, 0.0); InitializePropertyList(); } RenderingManager::~RenderingManager() { // Decrease reference counts of all registered vtkRenderWindows for // proper destruction RenderWindowVector::iterator it; for (it = m_AllRenderWindows.begin(); it != m_AllRenderWindows.end(); ++it) { (*it)->UnRegister(nullptr); auto callbacks_it = this->m_RenderWindowCallbacksList.find(*it); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { (*it)->RemoveObserver(callbacks_it->second.commands[0u]); (*it)->RemoveObserver(callbacks_it->second.commands[1u]); (*it)->RemoveObserver(callbacks_it->second.commands[2u]); } } } void RenderingManager::SetFactory(RenderingManagerFactory *factory) { s_RenderingManagerFactory = factory; } const RenderingManagerFactory *RenderingManager::GetFactory() { return s_RenderingManagerFactory; } bool RenderingManager::HasFactory() { if (RenderingManager::s_RenderingManagerFactory) { return true; } else { return false; } } RenderingManager::Pointer RenderingManager::New() { const RenderingManagerFactory *factory = GetFactory(); if (factory == nullptr) return nullptr; return factory->CreateRenderingManager(); } RenderingManager *RenderingManager::GetInstance() { if (!RenderingManager::s_Instance) { if (s_RenderingManagerFactory) { s_Instance = s_RenderingManagerFactory->CreateRenderingManager(); } } return s_Instance; } bool RenderingManager::IsInstantiated() { if (RenderingManager::s_Instance) return true; else return false; } void RenderingManager::AddRenderWindow(vtkRenderWindow *renderWindow) { if (renderWindow && (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.end())) { m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_AllRenderWindows.push_back(renderWindow); if (m_DataStorage.IsNotNull()) mitk::BaseRenderer::GetInstance(renderWindow)->SetDataStorage(m_DataStorage.GetPointer()); // Register vtkRenderWindow instance renderWindow->Register(nullptr); // Add callbacks for rendering abort mechanism // BaseRenderer *renderer = BaseRenderer::GetInstance( renderWindow ); vtkCallbackCommand *startCallbackCommand = vtkCallbackCommand::New(); startCallbackCommand->SetCallback(RenderingManager::RenderingStartCallback); renderWindow->AddObserver(vtkCommand::StartEvent, startCallbackCommand); vtkCallbackCommand *progressCallbackCommand = vtkCallbackCommand::New(); progressCallbackCommand->SetCallback(RenderingManager::RenderingProgressCallback); renderWindow->AddObserver(vtkCommand::AbortCheckEvent, progressCallbackCommand); vtkCallbackCommand *endCallbackCommand = vtkCallbackCommand::New(); endCallbackCommand->SetCallback(RenderingManager::RenderingEndCallback); renderWindow->AddObserver(vtkCommand::EndEvent, endCallbackCommand); RenderWindowCallbacks callbacks; callbacks.commands[0u] = startCallbackCommand; callbacks.commands[1u] = progressCallbackCommand; callbacks.commands[2u] = endCallbackCommand; this->m_RenderWindowCallbacksList[renderWindow] = callbacks; // Delete vtk variables correctly startCallbackCommand->Delete(); progressCallbackCommand->Delete(); endCallbackCommand->Delete(); } } void RenderingManager::RemoveRenderWindow(vtkRenderWindow *renderWindow) { if (m_RenderWindowList.erase(renderWindow)) { auto callbacks_it = this->m_RenderWindowCallbacksList.find(renderWindow); if (callbacks_it != this->m_RenderWindowCallbacksList.end()) { renderWindow->RemoveObserver(callbacks_it->second.commands[0u]); renderWindow->RemoveObserver(callbacks_it->second.commands[1u]); renderWindow->RemoveObserver(callbacks_it->second.commands[2u]); this->m_RenderWindowCallbacksList.erase(callbacks_it); } auto rw_it = std::find(m_AllRenderWindows.begin(), m_AllRenderWindows.end(), renderWindow); if (rw_it != m_AllRenderWindows.cend()) { // Decrease reference count for proper destruction (*rw_it)->UnRegister(nullptr); m_AllRenderWindows.erase(rw_it); } } } const RenderingManager::RenderWindowVector &RenderingManager::GetAllRegisteredRenderWindows() { return m_AllRenderWindows; } void RenderingManager::RequestUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } m_RenderWindowList[renderWindow] = RENDERING_REQUESTED; if (!m_UpdatePending) { m_UpdatePending = true; this->GenerateRenderingRequestEvent(); } } void RenderingManager::ForceImmediateUpdate(vtkRenderWindow *renderWindow) { // If the renderWindow is not valid, we do not want to inadvertantly create // an entry in the m_RenderWindowList map. It is possible if the user is // regularly calling AddRenderer and RemoveRenderer for a rendering update // to come into this method with a renderWindow pointer that is valid in the // sense that the window does exist within the application, but that // renderWindow has been temporarily removed from this RenderingManager for // performance reasons. if (m_RenderWindowList.find(renderWindow) == m_RenderWindowList.cend()) { return; } // Erase potentially pending requests for this window m_RenderWindowList[renderWindow] = RENDERING_INACTIVE; m_UpdatePending = false; // Immediately repaint this window (implementation platform specific) // If the size is 0 it crashes int *size = renderWindow->GetSize(); if (0 != size[0] && 0 != size[1]) { // prepare the camera etc. before rendering // Note: this is a very important step which should be called before the VTK render! // If you modify the camera anywhere else or after the render call, the scene cannot be seen. auto *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance(renderWindow)); if (vPR) vPR->PrepareRender(); // Execute rendering renderWindow->Render(); } } void RenderingManager::RequestUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { this->RequestUpdate(it->first); } } } void RenderingManager::ForceImmediateUpdateAll(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { int id = BaseRenderer::GetInstance(it->first)->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { // Immediately repaint this window (implementation platform specific) // If the size is 0, it crashes this->ForceImmediateUpdate(it->first); } } } void RenderingManager::InitializeViewsByBoundingObjects(const DataStorage *ds) { if (!ds) return; // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New( mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = ds->GetSubset(pred); // calculate bounding geometry of these nodes auto bounds = ds->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry this->InitializeViews(bounds); } // TODO_GOETZ // Remove old function, so only this one is working. bool RenderingManager::InitializeViews(const BaseGeometry *dataGeometry, RequestType type, bool preserveRoughOrientationInWorldSpace) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(dataGeometry->Clone().GetPointer()), 1); return InitializeViews(propTimeGeometry, type, preserveRoughOrientationInWorldSpace); } bool RenderingManager::InitializeViews(const TimeGeometry *dataGeometry, RequestType type, bool /*preserveRoughOrientationInWorldSpace*/) { MITK_DEBUG << "initializing views"; bool boundingBoxInitialized = false; TimeGeometry::ConstPointer timeGeometry = dataGeometry; TimeGeometry::Pointer modifiedGeometry = nullptr; if (dataGeometry != nullptr) { modifiedGeometry = dataGeometry->Clone(); } int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ((timeGeometry.IsNotNull()) && (timeGeometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps)) { boundingBoxInitialized = true; } if (timeGeometry.IsNotNull()) { // make sure bounding box has an extent bigger than zero in any direction // clone the input geometry // Old Geometry3D::Pointer modifiedGeometry = dynamic_cast( dataGeometry->Clone().GetPointer() ); assert(modifiedGeometry.IsNotNull()); for (TimeStepType step = 0; step < modifiedGeometry->CountTimeSteps(); ++step) { BaseGeometry::BoundsArrayType newBounds = modifiedGeometry->GetGeometryForTimeStep(step)->GetBounds(); for (unsigned int dimension = 0; (2 * dimension) < newBounds.Size(); dimension++) { // check for equality but for an epsilon if (Equal(newBounds[2 * dimension], newBounds[2 * dimension + 1])) { newBounds[2 * dimension + 1] += 1; if (Equal( newBounds[2 * dimension], newBounds[2 * dimension + 1])) // newBounds will still be equal if values are beyond double precision { mitkThrow() << "One dimension of object data has zero length, please make sure you're not using numbers " "beyond double precision as coordinates."; } } } modifiedGeometry->GetGeometryForTimeStep(step)->SetBounds(newBounds); } } timeGeometry = modifiedGeometry; RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); baseRenderer->SetConstrainZoomingAndPanning(m_ConstrainedPanningZooming); int id = baseRenderer->GetMapperID(); if (((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2)))) { this->InternalViewInitialization(baseRenderer, timeGeometry, boundingBoxInitialized, id); } } if (boundingBoxInitialized) { m_TimeNavigationController->SetInputWorldTimeGeometry(timeGeometry); } m_TimeNavigationController->Update(); this->RequestUpdateAll(type); vtkObject::SetGlobalWarningDisplay(warningLevel); // Inform listeners that views have been initialized this->InvokeEvent(mitk::RenderingManagerViewsInitializedEvent()); return boundingBoxInitialized; } bool RenderingManager::InitializeViews(RequestType type) { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(it->first); int id = baseRenderer->GetMapperID(); if ((type == REQUEST_UPDATE_ALL) || ((type == REQUEST_UPDATE_2DWINDOWS) && (id == 1)) || ((type == REQUEST_UPDATE_3DWINDOWS) && (id == 2))) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); } } this->RequestUpdateAll(type); return true; } bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, const BaseGeometry *geometry, bool initializeGlobalTimeSNC) { ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(dynamic_cast(geometry->Clone().GetPointer()), 1); return InitializeView(renderWindow, propTimeGeometry, initializeGlobalTimeSNC); } bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow, const TimeGeometry *geometry, bool initializeGlobalTimeSNC) { bool boundingBoxInitialized = false; int warningLevel = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); if ((geometry != nullptr) && (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() > mitk::eps)) { boundingBoxInitialized = true; } mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); int id = baseRenderer->GetMapperID(); this->InternalViewInitialization(baseRenderer, geometry, boundingBoxInitialized, id); if (boundingBoxInitialized && initializeGlobalTimeSNC) { m_TimeNavigationController->SetInputWorldTimeGeometry(geometry); } m_TimeNavigationController->Update(); this->RequestUpdate(renderWindow); vtkObject::SetGlobalWarningDisplay(warningLevel); return boundingBoxInitialized; } bool RenderingManager::InitializeView(vtkRenderWindow *renderWindow) { mitk::BaseRenderer *baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); // Update the SNC nc->Update(); this->RequestUpdate(renderWindow); return true; } void RenderingManager::InternalViewInitialization(mitk::BaseRenderer *baseRenderer, const mitk::TimeGeometry *geometry, bool boundingBoxInitialized, int mapperID) { mitk::SliceNavigationController *nc = baseRenderer->GetSliceNavigationController(); // Re-initialize view direction nc->SetViewDirectionToDefault(); if (boundingBoxInitialized) { // Set geometry for NC nc->SetInputWorldTimeGeometry(geometry); nc->Update(); if (mapperID == BaseRenderer::Standard2D) { // For 2D SNCs, steppers are set so that the cross is centered // in the image nc->GetSlice()->SetPos(nc->GetSlice()->GetSteps() / 2); } baseRenderer->GetCameraController()->SetViewToAnterior(); baseRenderer->GetCameraController()->Fit(); } else { nc->Update(); } } const SliceNavigationController *RenderingManager::GetTimeNavigationController() const { return m_TimeNavigationController.GetPointer(); } SliceNavigationController *RenderingManager::GetTimeNavigationController() { return m_TimeNavigationController.GetPointer(); } void RenderingManager::ExecutePendingRequests() { m_UpdatePending = false; // Satisfy all pending update requests RenderWindowList::const_iterator it; int i = 0; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it, ++i) { if (it->second == RENDERING_REQUESTED) { this->ForceImmediateUpdate(it->first); } } } void RenderingManager::RenderingStartCallback(vtkObject *caller, unsigned long, void *, void *) { - auto *renderWindow = dynamic_cast(caller); - mitk::RenderingManager *renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); - RenderWindowList &renderWindowList = renman->m_RenderWindowList; + auto renderingManager = RenderingManager::GetInstance(); + auto renderWindow = dynamic_cast(caller); - if (renderWindow) - { - renderWindowList[renderWindow] = RENDERING_INPROGRESS; - } + if (nullptr != renderWindow) + renderingManager->m_RenderWindowList[renderWindow] = RENDERING_INPROGRESS; - renman->m_UpdatePending = false; + renderingManager->m_UpdatePending = false; } void RenderingManager::RenderingProgressCallback(vtkObject *caller, unsigned long, void *, void *) { - auto *renderWindow = dynamic_cast(caller); - mitk::RenderingManager *renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); + auto renderingManager = RenderingManager::GetInstance(); - if (renman->m_LODAbortMechanismEnabled) + if (renderingManager->m_LODAbortMechanismEnabled) { - auto *renderWindow = dynamic_cast(caller); - if (renderWindow) + auto renderWindow = dynamic_cast(caller); + + if (nullptr != renderWindow) { - BaseRenderer *renderer = BaseRenderer::GetInstance(renderWindow); - if (renderer && (renderer->GetNumberOfVisibleLODEnabledMappers() > 0)) - { - renman->DoMonitorRendering(); - } + auto renderer = BaseRenderer::GetInstance(renderWindow); + + if (nullptr != renderer && 0 < renderer->GetNumberOfVisibleLODEnabledMappers()) + renderingManager->DoMonitorRendering(); } } } void RenderingManager::RenderingEndCallback(vtkObject *caller, unsigned long, void *, void *) { - auto *renderWindow = dynamic_cast(caller); - - mitk::RenderingManager *renman = mitk::BaseRenderer::GetInstance(renderWindow)->GetRenderingManager(); - - RenderWindowList &renderWindowList = renman->m_RenderWindowList; + auto renderWindow = dynamic_cast(caller); - RendererIntMap &nextLODMap = renman->m_NextLODMap; - - if (renderWindow) + if (nullptr != renderWindow) { - BaseRenderer *renderer = BaseRenderer::GetInstance(renderWindow); - if (renderer) + auto renderer = BaseRenderer::GetInstance(renderWindow); + + if (nullptr != renderer) { - renderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; + auto renderingManager = RenderingManager::GetInstance(); + renderingManager->m_RenderWindowList[renderer->GetRenderWindow()] = RENDERING_INACTIVE; - // Level-of-Detail handling - if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) + if (0 < renderer->GetNumberOfVisibleLODEnabledMappers()) { - if (nextLODMap[renderer] == 0) - renman->StartOrResetTimer(); + if (0 == renderingManager->m_NextLODMap[renderer]) + { + renderingManager->StartOrResetTimer(); + } else - nextLODMap[renderer] = 0; + { + renderingManager->m_NextLODMap[renderer] = 0; + } } } } } bool RenderingManager::IsRendering() const { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { return true; } } return false; } void RenderingManager::AbortRendering() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { if (it->second == RENDERING_INPROGRESS) { it->first->SetAbortRender(true); m_RenderingAbortedMap[BaseRenderer::GetInstance(it->first)] = true; } } } int RenderingManager::GetNextLOD(BaseRenderer *renderer) { if (renderer != nullptr) { return m_NextLODMap[renderer]; } else { return 0; } } void RenderingManager::ExecutePendingHighResRenderingRequest() { RenderWindowList::const_iterator it; for (it = m_RenderWindowList.cbegin(); it != m_RenderWindowList.cend(); ++it) { BaseRenderer *renderer = BaseRenderer::GetInstance(it->first); if (renderer->GetNumberOfVisibleLODEnabledMappers() > 0) { if (m_NextLODMap[renderer] == 0) { m_NextLODMap[renderer] = 1; RequestUpdate(it->first); } } } } void RenderingManager::SetMaximumLOD(unsigned int max) { m_MaxLOD = max; } // enable/disable shading void RenderingManager::SetShading(bool state, unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return; } m_ShadingEnabled[lod] = state; } bool RenderingManager::GetShading(unsigned int lod) { if (lod > m_MaxLOD) { itkWarningMacro(<< "LOD out of range requested: " << lod << " maxLOD: " << m_MaxLOD); return false; } return m_ShadingEnabled[lod]; } // enable/disable the clipping plane void RenderingManager::SetClippingPlaneStatus(bool status) { m_ClippingPlaneEnabled = status; } bool RenderingManager::GetClippingPlaneStatus() { return m_ClippingPlaneEnabled; } void RenderingManager::SetShadingValues(float ambient, float diffuse, float specular, float specpower) { m_ShadingValues[0] = ambient; m_ShadingValues[1] = diffuse; m_ShadingValues[2] = specular; m_ShadingValues[3] = specpower; } RenderingManager::FloatVector &RenderingManager::GetShadingValues() { return m_ShadingValues; } void RenderingManager::InitializePropertyList() { if (m_PropertyList.IsNull()) { m_PropertyList = PropertyList::New(); } this->SetProperty("coupled-zoom", BoolProperty::New(false)); this->SetProperty("coupled-plane-rotation", BoolProperty::New(false)); this->SetProperty("MIP-slice-rendering", BoolProperty::New(false)); } PropertyList::Pointer RenderingManager::GetPropertyList() const { return m_PropertyList; } BaseProperty *RenderingManager::GetProperty(const char *propertyKey) const { return m_PropertyList->GetProperty(propertyKey); } void RenderingManager::SetProperty(const char *propertyKey, BaseProperty *propertyValue) { m_PropertyList->SetProperty(propertyKey, propertyValue); } void RenderingManager::SetDataStorage(DataStorage *storage) { if (storage != nullptr) { m_DataStorage = storage; RenderingManager::RenderWindowVector::const_iterator iter; for (iter = m_AllRenderWindows.cbegin(); iter < m_AllRenderWindows.cend(); ++iter) { mitk::BaseRenderer::GetInstance((*iter))->SetDataStorage(m_DataStorage.GetPointer()); } } } mitk::DataStorage *RenderingManager::GetDataStorage() { return m_DataStorage; } void RenderingManager::SetRenderWindowFocus(vtkRenderWindow *focusWindow) { if (focusWindow != m_FocusedRenderWindow) { if (!focusWindow || (m_RenderWindowList.find(focusWindow) != m_RenderWindowList.cend())) { m_FocusedRenderWindow = focusWindow; this->InvokeEvent(FocusChangedEvent()); return; } MITK_ERROR << "Tried to set a RenderWindow that does not exist."; } } + void RenderingManager::SetAntiAliasing(AntiAliasing antiAliasing) + { + if (m_AntiAliasing != antiAliasing) + { + auto renderingManager = mitk::RenderingManager::GetInstance(); + auto renderWindows = renderingManager->GetAllRegisteredRenderWindows(); + + for (auto renderWindow : renderWindows) + { + auto renderers = renderWindow->GetRenderers(); + + if (nullptr != renderers) + { + renderers->InitTraversal(); + auto renderer = renderers->GetNextItem(); + + while (nullptr != renderer) + { + renderer->SetUseFXAA(AntiAliasing::FastApproximate == antiAliasing); + renderer = renderers->GetNextItem(); + } + + renderingManager->RequestUpdate(renderWindow); + } + } + + m_AntiAliasing = antiAliasing; + } + } + // Create and register generic RenderingManagerFactory. TestingRenderingManagerFactory renderingManagerFactory; } // namespace diff --git a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp index 5fd526aab0..912fd74648 100644 --- a/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp +++ b/Modules/Core/src/Controllers/mitkSliceNavigationController.cpp @@ -1,658 +1,636 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSliceNavigationController.h" #include "mitkAction.h" #include "mitkBaseRenderer.h" #include "mitkCrosshairPositionEvent.h" #include "mitkInteractionConst.h" #include "mitkOperation.h" #include "mitkOperationActor.h" #include "mitkPlaneGeometry.h" #include "mitkProportionalTimeGeometry.h" #include "mitkArbitraryTimeGeometry.h" #include "mitkRenderingManager.h" #include "mitkSlicedGeometry3D.h" #include "mitkVtkPropRenderer.h" #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkInteractionConst.h" #include "mitkNodePredicateDataType.h" #include "mitkOperationEvent.h" #include "mitkPixelTypeMultiplex.h" #include "mitkPlaneOperation.h" #include "mitkPointOperation.h" #include "mitkStatusBar.h" #include "mitkUndoController.h" #include "mitkApplyTransformMatrixOperation.h" #include "mitkMemoryUtilities.h" #include namespace mitk { SliceNavigationController::SliceNavigationController() : BaseController(), m_InputWorldGeometry3D( mitk::BaseGeometry::ConstPointer() ), m_InputWorldTimeGeometry( mitk::TimeGeometry::ConstPointer() ), m_CreatedWorldGeometry( mitk::TimeGeometry::Pointer() ), m_ViewDirection(Axial), m_DefaultViewDirection(Axial), m_RenderingManager( mitk::RenderingManager::Pointer() ), m_Renderer( nullptr ), m_Top(false), m_FrontSide(false), m_Rotated(false), m_BlockUpdate(false), m_SliceLocked(false), m_SliceRotationLocked(false), m_OldPos(0) { typedef itk::SimpleMemberCommand SNCCommandType; SNCCommandType::Pointer sliceStepperChangedCommand, timeStepperChangedCommand; sliceStepperChangedCommand = SNCCommandType::New(); timeStepperChangedCommand = SNCCommandType::New(); sliceStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendSlice); timeStepperChangedCommand->SetCallbackFunction(this, &SliceNavigationController::SendTime); m_Slice->AddObserver(itk::ModifiedEvent(), sliceStepperChangedCommand); m_Time->AddObserver(itk::ModifiedEvent(), timeStepperChangedCommand); m_Slice->SetUnitName("mm"); m_Time->SetUnitName("ms"); m_Top = false; m_FrontSide = false; m_Rotated = false; } SliceNavigationController::~SliceNavigationController() {} void SliceNavigationController::SetInputWorldGeometry3D(const BaseGeometry *geometry) { if ( geometry != nullptr ) { if (geometry->GetBoundingBox()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldGeometry3D != geometry) { m_InputWorldGeometry3D = geometry; m_InputWorldTimeGeometry = mitk::TimeGeometry::ConstPointer(); this->Modified(); } } void SliceNavigationController::SetInputWorldTimeGeometry(const TimeGeometry *geometry) { if ( geometry != nullptr ) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() < eps) { itkWarningMacro("setting an empty bounding-box"); geometry = nullptr; } } if (m_InputWorldTimeGeometry != geometry) { m_InputWorldTimeGeometry = geometry; m_InputWorldGeometry3D = mitk::BaseGeometry::ConstPointer(); this->Modified(); } } - RenderingManager *SliceNavigationController::GetRenderingManager() const - { - mitk::RenderingManager *renderingManager = m_RenderingManager.GetPointer(); - - if (renderingManager != nullptr) - return renderingManager; - - if ( m_Renderer != nullptr ) - { - renderingManager = m_Renderer->GetRenderingManager(); - - if (renderingManager != nullptr) - return renderingManager; - } - - return mitk::RenderingManager::GetInstance(); - } - void SliceNavigationController::SetViewDirectionToDefault() { m_ViewDirection = m_DefaultViewDirection; } const char *SliceNavigationController::GetViewDirectionAsString() const { const char *viewDirectionString; switch (m_ViewDirection) { case SliceNavigationController::Axial: viewDirectionString = "Axial"; break; case SliceNavigationController::Sagittal: viewDirectionString = "Sagittal"; break; case SliceNavigationController::Frontal: viewDirectionString = "Coronal"; break; case SliceNavigationController::Original: viewDirectionString = "Original"; break; default: viewDirectionString = "No View Direction Available"; break; } return viewDirectionString; } void SliceNavigationController::Update() { if (!m_BlockUpdate) { if (m_ViewDirection == Sagittal) { this->Update(Sagittal, true, true, false); } else if (m_ViewDirection == Frontal) { this->Update(Frontal, false, true, false); } else if (m_ViewDirection == Axial) { this->Update(Axial, false, false, true); } else { this->Update(m_ViewDirection); } } } void SliceNavigationController::Update(SliceNavigationController::ViewDirection viewDirection, bool top, bool frontside, bool rotated) { TimeGeometry::ConstPointer worldTimeGeometry = m_InputWorldTimeGeometry; if (m_BlockUpdate || (m_InputWorldTimeGeometry.IsNull() && m_InputWorldGeometry3D.IsNull()) || ((worldTimeGeometry.IsNotNull()) && (worldTimeGeometry->CountTimeSteps() == 0))) { return; } m_BlockUpdate = true; if (m_InputWorldTimeGeometry.IsNotNull() && m_LastUpdateTime < m_InputWorldTimeGeometry->GetMTime()) { Modified(); } if (m_InputWorldGeometry3D.IsNotNull() && m_LastUpdateTime < m_InputWorldGeometry3D->GetMTime()) { Modified(); } this->SetViewDirection(viewDirection); this->SetTop(top); this->SetFrontSide(frontside); this->SetRotated(rotated); if (m_LastUpdateTime < GetMTime()) { m_LastUpdateTime = GetMTime(); // initialize the viewplane SlicedGeometry3D::Pointer slicedWorldGeometry = SlicedGeometry3D::Pointer(); BaseGeometry::ConstPointer currentGeometry = BaseGeometry::ConstPointer(); if (m_InputWorldTimeGeometry.IsNotNull()) if (m_InputWorldTimeGeometry->IsValidTimeStep(GetTime()->GetPos())) currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(GetTime()->GetPos()); else currentGeometry = m_InputWorldTimeGeometry->GetGeometryForTimeStep(0); else currentGeometry = m_InputWorldGeometry3D; m_CreatedWorldGeometry = mitk::TimeGeometry::Pointer(); switch (viewDirection) { case Original: if (worldTimeGeometry.IsNotNull()) { m_CreatedWorldGeometry = worldTimeGeometry->Clone(); worldTimeGeometry = m_CreatedWorldGeometry.GetPointer(); slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry.IsNotNull()) { break; } } else { const auto *worldSlicedGeometry = dynamic_cast(currentGeometry.GetPointer()); if ( worldSlicedGeometry != nullptr ) { slicedWorldGeometry = static_cast(currentGeometry->Clone().GetPointer()); break; } } slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::None, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Axial: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Axial, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Frontal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Frontal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; case Sagittal: slicedWorldGeometry = SlicedGeometry3D::New(); slicedWorldGeometry->InitializePlanes(currentGeometry, PlaneGeometry::Sagittal, top, frontside, rotated); slicedWorldGeometry->SetSliceNavigationController(this); break; default: itkExceptionMacro("unknown ViewDirection"); } m_Slice->SetPos(0); m_Slice->SetSteps((int)slicedWorldGeometry->GetSlices()); if ( worldTimeGeometry.IsNull() ) { auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, 1 ); m_CreatedWorldGeometry = createdTimeGeometry; m_Time->SetSteps(0); m_Time->SetPos(0); m_Time->InvalidateRange(); } else { m_BlockUpdate = true; m_Time->SetSteps(worldTimeGeometry->CountTimeSteps()); m_Time->SetPos(0); const TimeBounds &timeBounds = worldTimeGeometry->GetTimeBounds(); m_Time->SetRange(timeBounds[0], timeBounds[1]); m_BlockUpdate = false; const auto currentTemporalPosition = this->GetTime()->GetPos(); assert( worldTimeGeometry->GetGeometryForTimeStep( currentTemporalPosition ).IsNotNull() ); if ( dynamic_cast( worldTimeGeometry.GetPointer() ) != nullptr ) { const TimePointType minimumTimePoint = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition ); const TimePointType stepDuration = worldTimeGeometry->TimeStepToTimePoint( currentTemporalPosition + 1 ) - minimumTimePoint; auto createdTimeGeometry = ProportionalTimeGeometry::New(); createdTimeGeometry->Initialize( slicedWorldGeometry, worldTimeGeometry->CountTimeSteps() ); createdTimeGeometry->SetFirstTimePoint( minimumTimePoint ); createdTimeGeometry->SetStepDuration( stepDuration ); m_CreatedWorldGeometry = createdTimeGeometry; } else { auto createdTimeGeometry = mitk::ArbitraryTimeGeometry::New(); const TimeStepType numberOfTimeSteps = worldTimeGeometry->CountTimeSteps(); createdTimeGeometry->ReserveSpaceForGeometries( numberOfTimeSteps ); for ( TimeStepType i = 0; i < numberOfTimeSteps; ++i ) { const BaseGeometry::Pointer clonedGeometry = slicedWorldGeometry->Clone().GetPointer(); const auto bounds = worldTimeGeometry->GetTimeBounds( i ); createdTimeGeometry->AppendNewTimeStep( clonedGeometry, bounds[0], bounds[1]); } createdTimeGeometry->Update(); m_CreatedWorldGeometry = createdTimeGeometry; } } } // unblock update; we may do this now, because if m_BlockUpdate was already // true before this method was entered, then we will never come here. m_BlockUpdate = false; // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry and time/slice data. this->SendCreatedWorldGeometry(); this->SendSlice(); this->SendTime(); // Adjust the stepper range of slice stepper according to geometry this->AdjustSliceStepperRange(); } void SliceNavigationController::SendCreatedWorldGeometry() { // Send the geometry. Do this even if nothing was changed, because maybe // Update() was only called to re-send the old geometry. if (!m_BlockUpdate) { this->InvokeEvent(GeometrySendEvent(m_CreatedWorldGeometry, 0)); } } void SliceNavigationController::SendCreatedWorldGeometryUpdate() { if (!m_BlockUpdate) { this->InvokeEvent(GeometryUpdateEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); } } void SliceNavigationController::SendSlice() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometrySliceEvent(m_CreatedWorldGeometry, m_Slice->GetPos())); - - // Request rendering update for all views - this->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } } void SliceNavigationController::SendTime() { if (!m_BlockUpdate) { if (m_CreatedWorldGeometry.IsNotNull()) { this->InvokeEvent(GeometryTimeEvent(m_CreatedWorldGeometry, m_Time->GetPos())); - - // Request rendering update for all views - this->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } } void SliceNavigationController::SetGeometry(const itk::EventObject &) {} void SliceNavigationController::SetGeometryTime(const itk::EventObject &geometryTimeEvent) { if (m_CreatedWorldGeometry.IsNull()) { return; } const auto *timeEvent = dynamic_cast< const SliceNavigationController::GeometryTimeEvent * >(&geometryTimeEvent); assert( timeEvent != nullptr ); TimeGeometry *timeGeometry = timeEvent->GetTimeGeometry(); assert( timeGeometry != nullptr ); auto timeStep = (int)timeEvent->GetPos(); ScalarType timeInMS; timeInMS = timeGeometry->TimeStepToTimePoint(timeStep); timeStep = m_CreatedWorldGeometry->TimePointToTimeStep(timeInMS); this->GetTime()->SetPos(timeStep); } void SliceNavigationController::SetGeometrySlice(const itk::EventObject &geometrySliceEvent) { const auto *sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent!=nullptr); this->GetSlice()->SetPos(sliceEvent->GetPos()); } void SliceNavigationController::SelectSliceByPoint(const Point3D &point) { if (m_CreatedWorldGeometry.IsNull()) { return; } //@todo add time to PositionEvent and use here!! SlicedGeometry3D *slicedWorldGeometry = dynamic_cast( m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()).GetPointer()); if (slicedWorldGeometry) { int bestSlice = -1; double bestDistance = itk::NumericTraits::max(); int s, slices; slices = slicedWorldGeometry->GetSlices(); if (slicedWorldGeometry->GetEvenlySpaced()) { mitk::PlaneGeometry *plane = slicedWorldGeometry->GetPlaneGeometry(0); const Vector3D &direction = slicedWorldGeometry->GetDirectionVector(); Point3D projectedPoint; plane->Project(point, projectedPoint); // Check whether the point is somewhere within the slice stack volume; // otherwise, the default slice (0) will be selected if (direction[0] * (point[0] - projectedPoint[0]) + direction[1] * (point[1] - projectedPoint[1]) + direction[2] * (point[2] - projectedPoint[2]) >= 0) { bestSlice = (int)(plane->Distance(point) / slicedWorldGeometry->GetSpacing()[2] + 0.5); } } else { Point3D projectedPoint; for (s = 0; s < slices; ++s) { slicedWorldGeometry->GetPlaneGeometry(s)->Project(point, projectedPoint); const Vector3D distance = projectedPoint - point; ScalarType currentDistance = distance.GetSquaredNorm(); if (currentDistance < bestDistance) { bestDistance = currentDistance; bestSlice = s; } } } if (bestSlice >= 0) { this->GetSlice()->SetPos(bestSlice); } else { this->GetSlice()->SetPos(0); } this->SendCreatedWorldGeometryUpdate(); // send crosshair event SetCrosshairEvent.Send(point); } } void SliceNavigationController::ReorientSlices(const Point3D &point, const Vector3D &normal) { if (m_CreatedWorldGeometry.IsNull()) { return; } PlaneOperation op(OpORIENT, point, normal); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } void SliceNavigationController::ReorientSlices(const mitk::Point3D &point, const mitk::Vector3D &axisVec0, const mitk::Vector3D &axisVec1) { if (m_CreatedWorldGeometry) { PlaneOperation op(OpORIENT, point, axisVec0, axisVec1); m_CreatedWorldGeometry->ExecuteOperation(&op); this->SendCreatedWorldGeometryUpdate(); } } mitk::TimeGeometry *SliceNavigationController::GetCreatedWorldGeometry() { return m_CreatedWorldGeometry; } const mitk::BaseGeometry *SliceNavigationController::GetCurrentGeometry3D() { if (m_CreatedWorldGeometry.IsNotNull()) { return m_CreatedWorldGeometry->GetGeometryForTimeStep(this->GetTime()->GetPos()); } else { return nullptr; } } const mitk::PlaneGeometry *SliceNavigationController::GetCurrentPlaneGeometry() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); if (slicedGeometry) { const mitk::PlaneGeometry *planeGeometry = (slicedGeometry->GetPlaneGeometry(this->GetSlice()->GetPos())); return planeGeometry; } else { return nullptr; } } void SliceNavigationController::SetRenderer(BaseRenderer *renderer) { m_Renderer = renderer; } BaseRenderer *SliceNavigationController::GetRenderer() const { return m_Renderer; } void SliceNavigationController::AdjustSliceStepperRange() { const auto *slicedGeometry = dynamic_cast(this->GetCurrentGeometry3D()); const Vector3D &direction = slicedGeometry->GetDirectionVector(); int c = 0; int i, k = 0; for (i = 0; i < 3; ++i) { if (fabs(direction[i]) < 0.000000001) { ++c; } else { k = i; } } if (c == 2) { ScalarType min = slicedGeometry->GetOrigin()[k]; ScalarType max = min + slicedGeometry->GetExtentInMM(k); m_Slice->SetRange(min, max); } else { m_Slice->InvalidateRange(); } } void SliceNavigationController::ExecuteOperation(Operation *operation) { // switch on type // - select best slice for a given point // - rotate created world geometry according to Operation->SomeInfo() if (!operation || m_CreatedWorldGeometry.IsNull()) { return; } switch (operation->GetOperationType()) { case OpMOVE: // should be a point operation { if (!m_SliceLocked) // do not move the cross position { // select a slice auto *po = dynamic_cast(operation); if (po && po->GetIndex() == -1) { this->SelectSliceByPoint(po->GetPoint()); } else if (po && po->GetIndex() != -1) // undo case because index != -1, index holds the old position of this slice { this->GetSlice()->SetPos(po->GetIndex()); } } break; } case OpRESTOREPLANEPOSITION: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } case OpAPPLYTRANSFORMMATRIX: { m_CreatedWorldGeometry->ExecuteOperation(operation); this->SendCreatedWorldGeometryUpdate(); break; } default: { // do nothing break; } } } } // namespace diff --git a/Modules/Core/src/Interactions/mitkDispatcher.cpp b/Modules/Core/src/Interactions/mitkDispatcher.cpp index 1683621cf8..eec8a48ad3 100644 --- a/Modules/Core/src/Interactions/mitkDispatcher.cpp +++ b/Modules/Core/src/Interactions/mitkDispatcher.cpp @@ -1,284 +1,284 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDispatcher.h" #include "mitkInteractionEvent.h" #include "mitkInteractionEventObserver.h" #include "mitkInternalEvent.h" #include "usGetModuleContext.h" namespace { struct cmp { bool operator()(mitk::WeakPointer d1, mitk::WeakPointer d2) { return (d1.Lock()->GetLayer() > d2.Lock()->GetLayer()); } }; } mitk::Dispatcher::Dispatcher(const std::string &rendererName) : m_ProcessingMode(REGULAR) { // LDAP filter string to find all listeners specific for the renderer // corresponding to this dispatcher std::string specificRenderer = "(rendererName=" + rendererName + ")"; // LDAP filter string to find all listeners that are not specific // to any renderer std::string anyRenderer = "(!(rendererName=*))"; // LDAP filter string to find only instances of InteractionEventObserver std::string classInteractionEventObserver = "(" + us::ServiceConstants::OBJECTCLASS() + "=" + us_service_interface_iid() + ")"; // Configure the LDAP filter to find all instances of InteractionEventObserver // that are specific to this dispatcher or unspecific to any dispatchers (real global listener) us::LDAPFilter filter("(&(|" + specificRenderer + anyRenderer + ")" + classInteractionEventObserver + ")"); // Give the filter to the ObserverTracker m_EventObserverTracker = new us::ServiceTracker(us::GetModuleContext(), filter); m_EventObserverTracker->Open(); } void mitk::Dispatcher::AddDataInteractor(const DataNode *dataNode) { RemoveDataInteractor(dataNode); RemoveOrphanedInteractors(); auto dataInteractor = dataNode->GetDataInteractor().GetPointer(); if (dataInteractor != nullptr) m_Interactors.push_back(dataInteractor); } /* * Note: One DataInteractor can only have one DataNode and vice versa, * BUT the m_Interactors list may contain another DataInteractor that is still connected to this DataNode, * in this case we have to remove >1 DataInteractor. (Some special case of switching DataNodes between DataInteractors * and registering a * DataNode to a DataStorage after assigning it to an DataInteractor) */ void mitk::Dispatcher::RemoveDataInteractor(const DataNode *dataNode) { for (auto it = m_Interactors.begin(); it != m_Interactors.end();) { if ((*it).IsExpired() || (*it).Lock()->GetDataNode() == nullptr || (*it).Lock()->GetDataNode() == dataNode) { it = m_Interactors.erase(it); } else { ++it; } } } size_t mitk::Dispatcher::GetNumberOfInteractors() { return m_Interactors.size(); } mitk::Dispatcher::~Dispatcher() { m_EventObserverTracker->Close(); delete m_EventObserverTracker; m_Interactors.clear(); } bool mitk::Dispatcher::ProcessEvent(InteractionEvent *event) { InteractionEvent::Pointer p = event; bool eventIsHandled = false; /* Filter out and handle Internal Events separately */ auto *internalEvent = dynamic_cast(event); if (internalEvent != nullptr) { eventIsHandled = HandleInternalEvent(internalEvent); // InternalEvents that are handled are not sent to the listeners if (eventIsHandled) { return true; } } switch (m_ProcessingMode) { case CONNECTEDMOUSEACTION: // finished connected mouse action if (std::strcmp(p->GetNameOfClass(), "MouseReleaseEvent") == 0) { m_ProcessingMode = REGULAR; if (!m_SelectedInteractor.IsExpired()) eventIsHandled = m_SelectedInteractor.Lock()->HandleEvent(event, m_SelectedInteractor.Lock()->GetDataNode()); m_SelectedInteractor = nullptr; } // give event to selected interactor if (eventIsHandled == false && !m_SelectedInteractor.IsExpired()) eventIsHandled = m_SelectedInteractor.Lock()->HandleEvent(event, m_SelectedInteractor.Lock()->GetDataNode()); break; case GRABINPUT: if (!m_SelectedInteractor.IsExpired()) { eventIsHandled = m_SelectedInteractor.Lock()->HandleEvent(event, m_SelectedInteractor.Lock()->GetDataNode()); SetEventProcessingMode(m_SelectedInteractor.Lock()); } break; case PREFERINPUT: if (!m_SelectedInteractor.IsExpired() && m_SelectedInteractor.Lock()->HandleEvent(event, m_SelectedInteractor.Lock()->GetDataNode()) == true) { SetEventProcessingMode(m_SelectedInteractor.Lock()); eventIsHandled = true; } break; case REGULAR: break; } // Standard behavior. Is executed in STANDARD mode and PREFERINPUT mode, if preferred interactor rejects event. if (m_ProcessingMode == REGULAR || (m_ProcessingMode == PREFERINPUT && eventIsHandled == false)) { if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0) - event->GetSender()->GetRenderingManager()->SetRenderWindowFocus(event->GetSender()->GetRenderWindow()); + RenderingManager::GetInstance()->SetRenderWindowFocus(event->GetSender()->GetRenderWindow()); m_Interactors.sort(cmp()); // sorts interactors by layer (descending); // copy the list to prevent iterator invalidation as executing actions // in HandleEvent() can cause the m_Interactors list to be updated const ListInteractorType tmpInteractorList(m_Interactors); ListInteractorType::const_iterator it; for (it = tmpInteractorList.cbegin(); it != tmpInteractorList.cend(); ++it) { if (!(*it).IsExpired() && (*it).Lock()->HandleEvent(event, (*it).Lock()->GetDataNode())) { // Interactor can be deleted during HandleEvent(), so check it again if (!(*it).IsExpired()) { // if an event is handled several properties are checked, in order to determine the processing mode of the // dispatcher SetEventProcessingMode((*it).Lock()); } if (std::strcmp(p->GetNameOfClass(), "MousePressEvent") == 0 && m_ProcessingMode == REGULAR) { m_SelectedInteractor = *it; m_ProcessingMode = CONNECTEDMOUSEACTION; } eventIsHandled = true; break; } } } /* Notify InteractionEventObserver */ const std::vector> listEventObserver = m_EventObserverTracker->GetServiceReferences(); for (auto it = listEventObserver.cbegin(); it != listEventObserver.cend(); ++it) { InteractionEventObserver *interactionEventObserver = m_EventObserverTracker->GetService(*it); if (interactionEventObserver != nullptr) { if (interactionEventObserver->IsEnabled()) { interactionEventObserver->Notify(event, eventIsHandled); } } } // Process event queue if (!m_QueuedEvents.empty()) { InteractionEvent::Pointer e = m_QueuedEvents.front(); m_QueuedEvents.pop_front(); ProcessEvent(e); } return eventIsHandled; } /* * Checks if DataNodes associated with DataInteractors point back to them. * If not remove the DataInteractors. (This can happen when s.o. tries to set DataNodes to multiple DataInteractors) */ void mitk::Dispatcher::RemoveOrphanedInteractors() { for (auto it = m_Interactors.begin(); it != m_Interactors.end();) { if ((*it).IsExpired()) { it = m_Interactors.erase(it); } else { DataNode::Pointer node = (*it).Lock()->GetDataNode(); if (node.IsNull()) { it = m_Interactors.erase(it); } else { DataInteractor::Pointer interactor = node->GetDataInteractor(); if (interactor != it->Lock().GetPointer()) { it = m_Interactors.erase(it); } else { ++it; } } } } } void mitk::Dispatcher::QueueEvent(InteractionEvent *event) { m_QueuedEvents.push_back(event); } void mitk::Dispatcher::SetEventProcessingMode(DataInteractor *dataInteractor) { m_ProcessingMode = dataInteractor->GetMode(); if (dataInteractor->GetMode() != REGULAR) { m_SelectedInteractor = dataInteractor; } } bool mitk::Dispatcher::HandleInternalEvent(InternalEvent *internalEvent) { if (internalEvent->GetSignalName() == DataInteractor::IntDeactivateMe && internalEvent->GetTargetInteractor() != nullptr) { internalEvent->GetTargetInteractor()->GetDataNode()->SetDataInteractor(nullptr); internalEvent->GetTargetInteractor()->SetDataNode(nullptr); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return true; } return false; } diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp index 948f7d26e1..ab8f96c317 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventBroadcast.cpp @@ -1,918 +1,918 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayActionEventBroadcast.h" // us #include "usGetModuleContext.h" #include "usModuleContext.h" // mitk core module #include #include #include #include #include #include #include #include #include #include #include #include mitk::DisplayActionEventBroadcast::DisplayActionEventBroadcast() : m_AlwaysReact(false) , m_AutoRepeat(false) , m_IndexToSliceModifier(4) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_ZoomFactor(2) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_LastCoordinateInMM.Fill(0); m_CurrentDisplayCoordinate.Fill(0); // register the broadcast class (itself) as an interaction event observer via micro services us::ServiceProperties props; props["name"] = std::string("DisplayActionEventBroadcast"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(this, props); } mitk::DisplayActionEventBroadcast::~DisplayActionEventBroadcast() { m_ServiceRegistration.Unregister(); } void mitk::DisplayActionEventBroadcast::Notify(InteractionEvent* interactionEvent, bool isHandled) { // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } void mitk::DisplayActionEventBroadcast::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } void mitk::DisplayActionEventBroadcast::ConfigurationChanged() { PropertyList::Pointer properties = GetAttributes(); // allwaysReact std::string strAlwaysReact = ""; m_AlwaysReact = false; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } } // auto repeat std::string strAutoRepeat = ""; m_AutoRepeat = false; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; m_IndexToSliceModifier = 4; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; m_LinkPlanes = false; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") { m_LinkPlanes = true; } } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } } bool mitk::DisplayActionEventBroadcast::FilterEvents(InteractionEvent* interactionEvent, DataNode * /*dataNode*/) { BaseRenderer* sendingRenderer = interactionEvent->GetSender(); if (nullptr == sendingRenderer) { return false; } if (BaseRenderer::Standard3D == sendingRenderer->GetMapperID()) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } return true; } bool mitk::DisplayActionEventBroadcast::CheckRotationPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO intersection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer* renderer = positionEvent->GetSender(); if (nullptr == renderer) { return false; } const PlaneGeometry* rendererWorldPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); if (nullptr == rendererWorldPlaneGeometry) { return false; } Point3D position = positionEvent->GetPositionInWorld(); const auto spacing = rendererWorldPlaneGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const ScalarType threshholdDistancePixels = 12.0; - auto allRenderWindows = renderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) { continue; } const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); if (nullptr == rendererPlaneGeometry) { continue; // ignore, we don't see a plane } // check if there is an intersection between rendered / clicked geometry and the one being analyzed Line3D intersectionLine; if (!rendererWorldPlaneGeometry->IntersectionLine(rendererPlaneGeometry, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line const double distanceFromIntersectionLine = intersectionLine.Distance(position) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { // we just take the last one, so overwrite each iteration (we just need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used anyOtherGeometry = rendererPlaneGeometry; if (m_LinkPlanes) { // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (nullptr == geometryToBeRotated) // first one close to the cursor { geometryToBeRotated = rendererPlaneGeometry; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && rendererWorldPlaneGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we have enough information for rotation // remember where the last cursor position ON THE LINE has been observed m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project(position); // find center of rotation by intersection with any of the OTHER lines if (anyOtherGeometry->IntersectionPoint(intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) { return true; } else { return false; } } return false; } bool mitk::DisplayActionEventBroadcast::CheckSwivelPossible(const InteractionEvent *interactionEvent) { // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return false; } BaseRenderer* renderer = positionEvent->GetSender(); if (nullptr == renderer) { return false; } const Point3D& position = positionEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry* clickedGeometry(nullptr); const PlaneGeometry* otherGeometry1(nullptr); const PlaneGeometry* otherGeometry2(nullptr); const ScalarType threshholdDistancePixels = 6.0; - auto allRenderWindows = renderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { SliceNavigationController* snc = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::Standard3D == BaseRenderer::GetInstance(renderWindow)->GetMapperID()) { continue; } const PlaneGeometry* rendererPlaneGeometry = snc->GetCurrentPlaneGeometry(); if (nullptr == rendererPlaneGeometry) { continue; // ignore, we don't see a plane } if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = rendererPlaneGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (nullptr == otherGeometry1) { otherGeometry1 = rendererPlaneGeometry; } else { otherGeometry2 = rendererPlaneGeometry; } if (m_LinkPlanes) { // if planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } Line3D line; Point3D point; if ((nullptr != clickedGeometry) && (nullptr != otherGeometry1) && (nullptr != otherGeometry2) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(position) < threshholdDistancePixels) { return false; } else { m_ReferenceCursor = positionEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = { 1.0, 0.0, 0.0 }; ScalarType yVector[] = { 0.0, 1.0, 0.0 }; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayActionEventBroadcast::Init(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayActionEventBroadcast::Move(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer* sender = interactionEvent->GetSender(); Vector2D moveVector = m_LastDisplayCoordinate - positionEvent->GetPointerPositionOnScreen(); if (m_InvertMoveDirection) { moveVector *= -1.0; } moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); // #TODO: put here? // store new display coordinate m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate move event with computed geometry values InvokeEvent(DisplayMoveEvent(interactionEvent, moveVector)); } void mitk::DisplayActionEventBroadcast::SetCrosshair(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); // propagate set crosshair event with computed geometry values InvokeEvent(DisplaySetCrosshairEvent(interactionEvent, position)); } void mitk::DisplayActionEventBroadcast::Zoom(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate zoom event with computed geometry values InvokeEvent(DisplayZoomEvent(interactionEvent, factor, m_StartCoordinateInMM)); } void mitk::DisplayActionEventBroadcast::Scroll(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } int sliceDelta = 0; // scroll direction if (m_ScrollDirection == "updown") { sliceDelta = static_cast(m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]); } else { sliceDelta = static_cast(m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]); } if (m_InvertScrollDirection) { sliceDelta *= -1; } // set how many pixels the mouse has to be moved to scroll one slice // if the mouse has been moved less than 'm_IndexToSliceModifier', pixels slice ONE slice only if (sliceDelta > 0 && sliceDelta < m_IndexToSliceModifier) { sliceDelta = m_IndexToSliceModifier; } else if (sliceDelta < 0 && sliceDelta > -m_IndexToSliceModifier) { sliceDelta = -m_IndexToSliceModifier; } sliceDelta /= m_IndexToSliceModifier; // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate scroll event with computed geometry values InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneUp(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = 1; if (m_InvertScrollDirection) { sliceDelta = -1; } // propagate scroll event with a single slice delta (increase) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::ScrollOneDown(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { int sliceDelta = -1; if (m_InvertScrollDirection) { sliceDelta = 1; } // propagate scroll event with a single slice delta (decrease) InvokeEvent(DisplayScrollEvent(interactionEvent, sliceDelta)); } void mitk::DisplayActionEventBroadcast::AdjustLevelWindow(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } ScalarType level; ScalarType window; if (m_LevelDirection == "leftright") { level = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; window = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { level = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; window = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertLevelWindowDirection) { level *= -1; window *= -1; } level *= static_cast(2); window *= static_cast(2); // store new display coordinates m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // propagate set level window event with the level and window delta InvokeEvent(DisplaySetLevelWindowEvent(interactionEvent, level, window)); } void mitk::DisplayActionEventBroadcast::StartRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayActionEventBroadcast::EndRotation(StateMachineAction* /*stateMachineAction*/, InteractionEvent* /*interactionEvent*/) { ResetMouseCursor(); } void mitk::DisplayActionEventBroadcast::Rotate(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } Point3D position = positionEvent->GetPositionInWorld(); Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; Vector3D toCursor = position - m_CenterOfRotation; // cross product: | A x B | = |A| * |B| * sin(angle) Vector3D axisOfRotation; vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); axisOfRotation.SetVnlVector(vnlDirection); // scalar product: A * B = |A| * |B| * cos(angle) // tan = sin / cos ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); angle *= 180.0 / vnl_math::pi; m_LastCursorPosition = position; // create RotationOperation and apply to all SNCs that should be rotated RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); // iterate the OTHER slice navigation controllers for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } timeGeometry->ExecuteOperation(&rotationOperation); (*iter)->SendCreatedWorldGeometryUpdate(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayActionEventBroadcast::Swivel(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } // Determine relative mouse movement projected onto world space Point2D position = positionEvent->GetPointerPositionOnScreen(); Vector2D relativeCursor = position - m_ReferenceCursor; Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; // Determine rotation axis (perpendicular to rotation plane and cursor movement) Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; // Restore the initial plane pose by undoing the previous rotation operation RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); SNCVector::iterator iter; for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { TimeGeometry* timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } timeGeometry->ExecuteOperation(&op); (*iter)->SendCreatedWorldGeometryUpdate(); } } // Apply new rotation operation to all relevant SNCs RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { // Retrieve the TimeGeometry of this SliceNavigationController TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (nullptr == timeGeometry) { continue; } // Execute the new rotation timeGeometry->ExecuteOperation(&op2); // Notify listeners (*iter)->SendCreatedWorldGeometryUpdate(); } } m_PreviousRotationAxis = rotationAxis; m_PreviousRotationAngle = rotationAngle; RenderingManager::GetInstance()->RequestUpdateAll(); return; } -void mitk::DisplayActionEventBroadcast::IncreaseTimeStep(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +void mitk::DisplayActionEventBroadcast::IncreaseTimeStep(StateMachineAction*, InteractionEvent*) { - auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Next(); } -void mitk::DisplayActionEventBroadcast::DecreaseTimeStep(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) +void mitk::DisplayActionEventBroadcast::DecreaseTimeStep(StateMachineAction*, InteractionEvent*) { - auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Previous(); } void mitk::DisplayActionEventBroadcast::UpdateStatusbar(StateMachineAction* /*stateMachineAction*/, InteractionEvent* interactionEvent) { const auto* positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) { return; } BaseRenderer::Pointer renderer = positionEvent->GetSender(); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); DataStorage::SetOfObjects::ConstPointer nodes = renderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); if (nodes.IsNull()) { return; } Point3D worldposition; renderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); auto globalCurrentTimePoint = renderer->GetTime(); Image::Pointer image3D; DataNode::Pointer node; DataNode::Pointer topSourceNode; int component = 0; node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); if (node.IsNull()) { return; } bool isBinary(false); node->GetBoolProperty("binary", isBinary); if (isBinary) { DataStorage::SetOfObjects::ConstPointer sourcenodes = renderer->GetDataStorage()->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, renderer); } if (topSourceNode.IsNotNull()) { image3D = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } // get the position and pixel value from the image and build up status bar text auto statusBar = StatusBar::GetInstance(); if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue.c_str()); } else { ScalarType pixelValue; mitkPixelTypeMultiplex5( FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(renderer->GetTimeStep()), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, renderer->GetTime(), pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } bool mitk::DisplayActionEventBroadcast::GetBoolProperty(PropertyList::Pointer propertyList, const char* propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp index 0b35416d73..0aca932380 100644 --- a/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayActionEventFunctions.cpp @@ -1,321 +1,323 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayActionEventFunctions.h" // mitk core #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkDisplayActionEvents.h" #include "mitkInteractionPositionEvent.h" #include "mitkLevelWindow.h" #include "mitkLevelWindowProperty.h" #include "mitkNodePredicateDataType.h" ////////////////////////////////////////////////////////////////////////// // STANDARD FUNCTIONS ////////////////////////////////////////////////////////////////////////// mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveSenderCameraAction() { mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } sendingRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); - sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(sendingRenderer->GetRenderWindow()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } BaseRenderer::GetInstance(sendingRenderer->GetRenderWindow())->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomSenderCameraAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } if (1.0 != displayActionEvent->GetZoomFactor()) { sendingRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); - sendingRenderer->GetRenderingManager()->RequestUpdate(sendingRenderer->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(sendingRenderer->GetRenderWindow()); } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } mitk::SliceNavigationController* sliceNavigationController = sendingRenderer->GetSliceNavigationController(); if (nullptr == sliceNavigationController) { return; } if (sliceNavigationController->GetSliceLocked()) { return; } mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); if (nullptr == sliceStepper) { return; } // if only a single slice image was loaded, scrolling will affect the time steps if (sliceStepper->GetSteps() <= 1) { sliceStepper = sliceNavigationController->GetTime(); } sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetLevelWindowAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetLevelWindowEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetLevelWindowEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } // get the the topmost visible image of the sending renderer DataStorage::Pointer storage = sendingRenderer->GetDataStorage(); DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(NodePredicateDataType::New("Image")); Point3D worldposition; const auto* positionEvent = dynamic_cast(displayActionEvent->GetInteractionEvent()); sendingRenderer->DisplayToWorld(positionEvent->GetPointerPositionOnScreen(), worldposition); auto globalCurrentTimePoint = sendingRenderer->GetTime(); DataNode::Pointer node = FindTopmostVisibleNode(allImageNodes, worldposition, globalCurrentTimePoint, sendingRenderer); if (node.IsNull()) { return; } LevelWindow levelWindow = LevelWindow(); node->GetLevelWindow(levelWindow); ScalarType level = levelWindow.GetLevel(); ScalarType window = levelWindow.GetWindow(); level += displayActionEvent->GetLevel(); window += displayActionEvent->GetWindow(); levelWindow.SetLevelWindow(level, window); auto* levelWindowProperty = dynamic_cast(node->GetProperty("levelwindow")); if (nullptr != levelWindowProperty) { levelWindowProperty->SetLevelWindow(levelWindow); - sendingRenderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } }; return actionFunction; } ////////////////////////////////////////////////////////////////////////// // SYNCHRONIZED FUNCTIONS ////////////////////////////////////////////////////////////////////////// mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction() { mitk::StdFunctionCommand::ActionFunction actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayMoveEvent().CheckEvent(&displayInteractorEvent)) { const DisplayMoveEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } - auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto renderingManager = RenderingManager::GetInstance(); + auto allRenderWindows = renderingManager->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); currentRenderer->GetCameraController()->MoveBy(displayActionEvent->GetMoveVector()); - currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + renderingManager->RequestUpdate(currentRenderer->GetRenderWindow()); } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplaySetCrosshairEvent().CheckEvent(&displayInteractorEvent)) { const DisplaySetCrosshairEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } - auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController()->SelectSliceByPoint(displayActionEvent->GetPosition()); } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayZoomEvent().CheckEvent(&displayInteractorEvent)) { const DisplayZoomEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } if (1.0 != displayActionEvent->GetZoomFactor()) { - auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto renderingManager = RenderingManager::GetInstance(); + auto allRenderWindows = renderingManager->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { BaseRenderer* currentRenderer = BaseRenderer::GetInstance(renderWindow); currentRenderer->GetCameraController()->Zoom(displayActionEvent->GetZoomFactor(), displayActionEvent->GetStartCoordinate()); - currentRenderer->GetRenderingManager()->RequestUpdate(currentRenderer->GetRenderWindow()); + renderingManager->RequestUpdate(currentRenderer->GetRenderWindow()); } } } } }; return actionFunction; } mitk::StdFunctionCommand::ActionFunction mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction() { auto actionFunction = [](const itk::EventObject& displayInteractorEvent) { if (DisplayScrollEvent().CheckEvent(&displayInteractorEvent)) { const DisplayScrollEvent* displayActionEvent = dynamic_cast(&displayInteractorEvent); const BaseRenderer::Pointer sendingRenderer = displayActionEvent->GetSender(); if (nullptr == sendingRenderer) { return; } - auto allRenderWindows = sendingRenderer->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto allRenderWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renderWindow : allRenderWindows) { if (BaseRenderer::GetInstance(renderWindow)->GetMapperID() == BaseRenderer::Standard2D) { mitk::SliceNavigationController* sliceNavigationController = BaseRenderer::GetInstance(renderWindow)->GetSliceNavigationController(); if (nullptr == sliceNavigationController) { return; } if (sliceNavigationController->GetSliceLocked()) { return; } mitk::Stepper* sliceStepper = sliceNavigationController->GetSlice(); if (nullptr == sliceStepper) { return; } // if only a single slice image was loaded, scrolling will affect the time steps if (sliceStepper->GetSteps() <= 1) { sliceStepper = sliceNavigationController->GetTime(); } sliceStepper->MoveSlice(displayActionEvent->GetSliceDelta()); } } } }; return actionFunction; } diff --git a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp index 5936b5fa48..cc0d69209b 100644 --- a/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp +++ b/Modules/Core/src/Interactions/mitkDisplayInteractor.cpp @@ -1,951 +1,951 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDisplayInteractor.h" #include "mitkBaseRenderer.h" #include "mitkCameraController.h" #include "mitkInteractionPositionEvent.h" #include "mitkPropertyList.h" #include #include #include // level window #include "mitkLevelWindow.h" #include "mitkLevelWindowProperty.h" #include "mitkLine.h" #include "mitkNodePredicateDataType.h" #include "mitkStandaloneDataStorage.h" #include "vtkRenderWindowInteractor.h" // Rotation #include "mitkInteractionConst.h" #include "rotate_cursor.xpm" #include #include #include "mitkImage.h" #include "mitkImagePixelReadAccessor.h" #include "mitkPixelTypeMultiplex.h" #include "mitkStatusBar.h" #include void mitk::DisplayInteractor::Notify(InteractionEvent *interactionEvent, bool isHandled) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if (!isHandled || m_AlwaysReact) { HandleEvent(interactionEvent, nullptr); } } mitk::DisplayInteractor::DisplayInteractor() : m_IndexToSliceModifier(4) , m_AutoRepeat(false) , m_InvertScrollDirection(false) , m_InvertZoomDirection(false) , m_InvertMoveDirection(false) , m_InvertLevelWindowDirection(false) , m_AlwaysReact(false) , m_ZoomFactor(2) , m_LinkPlanes(true) { m_StartCoordinateInMM.Fill(0); m_LastDisplayCoordinate.Fill(0); m_LastCoordinateInMM.Fill(0); m_CurrentDisplayCoordinate.Fill(0); } mitk::DisplayInteractor::~DisplayInteractor() { // nothing here } void mitk::DisplayInteractor::ConnectActionsAndFunctions() { CONNECT_CONDITION("check_position_event", CheckPositionEvent); CONNECT_CONDITION("check_can_rotate", CheckRotationPossible); CONNECT_CONDITION("check_can_swivel", CheckSwivelPossible); CONNECT_FUNCTION("init", Init); CONNECT_FUNCTION("move", Move); CONNECT_FUNCTION("zoom", Zoom); CONNECT_FUNCTION("scroll", Scroll); CONNECT_FUNCTION("ScrollOneDown", ScrollOneDown); CONNECT_FUNCTION("ScrollOneUp", ScrollOneUp); CONNECT_FUNCTION("levelWindow", AdjustLevelWindow); CONNECT_FUNCTION("setCrosshair", SetCrosshair); CONNECT_FUNCTION("updateStatusbar", UpdateStatusbar) CONNECT_FUNCTION("startRotation", StartRotation); CONNECT_FUNCTION("endRotation", EndRotation); CONNECT_FUNCTION("rotate", Rotate); CONNECT_FUNCTION("swivel", Swivel); CONNECT_FUNCTION("IncreaseTimeStep", IncreaseTimeStep); CONNECT_FUNCTION("DecreaseTimeStep", DecreaseTimeStep); } bool mitk::DisplayInteractor::CheckPositionEvent(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) { return false; } return true; } bool mitk::DisplayInteractor::CheckRotationPossible(const mitk::InteractionEvent *interactionEvent) { // Decide between moving and rotation slices. /* Detailed logic: 1. Find the SliceNavigationController that has sent the event: this one defines our rendering plane and will NOT be rotated. Needs not even be counted or checked. 2. Inspect every other SliceNavigationController - calculate the line intersection of this SliceNavigationController's plane with our rendering plane - if there is NO interesection, ignore and continue - IF there is an intersection - check the mouse cursor's distance from that line. 0. if the line is NOT near the cursor, remember the plane as "one of the other planes" (which can be rotated in "locked" mode) 1. on first line near the cursor, just remember this intersection line as THE other plane that we want to rotate 2. on every consecutive line near the cursor, check if the line is geometrically identical to the line that we want to rotate - if yes, we just push this line to the "other" lines and rotate it along - if no, then we have a situation where the mouse is near two other lines (e.g. crossing point) and don't want to rotate */ const auto *posEvent = dynamic_cast(interactionEvent); if (posEvent == nullptr) return false; BaseRenderer *clickedRenderer = posEvent->GetSender(); const PlaneGeometry *ourViewportGeometry = (clickedRenderer->GetCurrentWorldPlaneGeometry()); if (!ourViewportGeometry) return false; Point3D cursorPosition = posEvent->GetPositionInWorld(); const auto spacing = ourViewportGeometry->GetSpacing(); const PlaneGeometry *geometryToBeRotated = nullptr; // this one is under the mouse cursor const PlaneGeometry *anyOtherGeometry = nullptr; // this is also visible (for calculation of intersection ONLY) Line3D intersectionLineWithGeometryToBeRotated; bool hitMultipleLines(false); m_SNCsToBeRotated.clear(); const double threshholdDistancePixels = 12.0; - auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto renWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; const PlaneGeometry *otherRenderersRenderPlane = snc->GetCurrentPlaneGeometry(); if (otherRenderersRenderPlane == nullptr) continue; // ignore, we don't see a plane // check if there is an intersection Line3D intersectionLine; // between rendered/clicked geometry and the one being analyzed if (!ourViewportGeometry->IntersectionLine(otherRenderersRenderPlane, intersectionLine)) { continue; // we ignore this plane, it's parallel to our plane } // check distance from intersection line const double distanceFromIntersectionLine = intersectionLine.Distance(cursorPosition) / spacing[snc->GetDefaultViewDirection()]; // far away line, only remember for linked rotation if necessary if (distanceFromIntersectionLine > threshholdDistancePixels) { anyOtherGeometry = otherRenderersRenderPlane; // we just take the last one, so overwrite each iteration (we just // need some crossing point) // TODO what about multiple crossings? NOW we have undefined behavior / random crossing point is used if (m_LinkPlanes) { m_SNCsToBeRotated.push_back(snc); } } else // close to cursor { if (geometryToBeRotated == nullptr) // first one close to the cursor { geometryToBeRotated = otherRenderersRenderPlane; intersectionLineWithGeometryToBeRotated = intersectionLine; m_SNCsToBeRotated.push_back(snc); } else { // compare to the line defined by geometryToBeRotated: if identical, just rotate this otherRenderersRenderPlane // together with the primary one // if different, DON'T rotate if (intersectionLine.IsParallel(intersectionLineWithGeometryToBeRotated) && intersectionLine.Distance(intersectionLineWithGeometryToBeRotated.GetPoint1()) < mitk::eps) { m_SNCsToBeRotated.push_back(snc); } else { hitMultipleLines = true; } } } } bool moveSlices(true); if (geometryToBeRotated && anyOtherGeometry && ourViewportGeometry && !hitMultipleLines) { // assure all three are valid, so calculation of center of rotation can be done moveSlices = false; } // question in state machine is: "rotate?" if (moveSlices) // i.e. NOT rotate { return false; } else { // we DO have enough information for rotation m_LastCursorPosition = intersectionLineWithGeometryToBeRotated.Project( cursorPosition); // remember where the last cursor position ON THE LINE has been observed if (anyOtherGeometry->IntersectionPoint( intersectionLineWithGeometryToBeRotated, m_CenterOfRotation)) // find center of rotation by intersection with any of the OTHER lines { return true; } else { return false; } } return false; } bool mitk::DisplayInteractor::CheckSwivelPossible(const mitk::InteractionEvent *interactionEvent) { const ScalarType ThresholdDistancePixels = 6.0; // Decide between moving and rotation: if we're close to the crossing // point of the planes, moving mode is entered, otherwise // rotation/swivel mode const auto *posEvent = dynamic_cast(interactionEvent); BaseRenderer *renderer = interactionEvent->GetSender(); if (!posEvent || !renderer) return false; const Point3D &cursor = posEvent->GetPositionInWorld(); m_SNCsToBeRotated.clear(); const PlaneGeometry *clickedGeometry(nullptr); const PlaneGeometry *otherGeometry1(nullptr); const PlaneGeometry *otherGeometry2(nullptr); - auto renWindows = interactionEvent->GetSender()->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto renWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { SliceNavigationController *snc = BaseRenderer::GetInstance(renWin)->GetSliceNavigationController(); // If the mouse cursor is in 3D Renderwindow, do not check for intersecting planes. if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard3D) continue; // unsigned int slice = (*iter)->GetSlice()->GetPos(); // unsigned int time = (*iter)->GetTime()->GetPos(); const PlaneGeometry *planeGeometry = snc->GetCurrentPlaneGeometry(); if (!planeGeometry) continue; if (snc == renderer->GetSliceNavigationController()) { clickedGeometry = planeGeometry; m_SNCsToBeRotated.push_back(snc); } else { if (otherGeometry1 == nullptr) { otherGeometry1 = planeGeometry; } else { otherGeometry2 = planeGeometry; } if (m_LinkPlanes) { // If planes are linked, apply rotation to all planes m_SNCsToBeRotated.push_back(snc); } } } mitk::Line3D line; mitk::Point3D point; if ((clickedGeometry != nullptr) && (otherGeometry1 != nullptr) && (otherGeometry2 != nullptr) && clickedGeometry->IntersectionLine(otherGeometry1, line) && otherGeometry2->IntersectionPoint(line, point)) { m_CenterOfRotation = point; if (m_CenterOfRotation.EuclideanDistanceTo(cursor) < ThresholdDistancePixels) { return false; } else { m_ReferenceCursor = posEvent->GetPointerPositionOnScreen(); // Get main axes of rotation plane and store it for rotation step m_RotationPlaneNormal = clickedGeometry->GetNormal(); ScalarType xVector[] = {1.0, 0.0, 0.0}; ScalarType yVector[] = {0.0, 1.0, 0.0}; clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(xVector), m_RotationPlaneXVector); clickedGeometry->BaseGeometry::IndexToWorld(Vector3D(yVector), m_RotationPlaneYVector); m_RotationPlaneNormal.Normalize(); m_RotationPlaneXVector.Normalize(); m_RotationPlaneYVector.Normalize(); m_PreviousRotationAxis.Fill(0.0); m_PreviousRotationAxis[2] = 1.0; m_PreviousRotationAngle = 0.0; return true; } } else { return false; } return false; } void mitk::DisplayInteractor::Init(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); m_CurrentDisplayCoordinate = m_LastDisplayCoordinate; positionEvent->GetSender()->DisplayToPlane(m_LastDisplayCoordinate, m_StartCoordinateInMM); m_LastCoordinateInMM = m_StartCoordinateInMM; } void mitk::DisplayInteractor::Move(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer *sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); float invertModifier = -1.0; if (m_InvertMoveDirection) { invertModifier = 1.0; } // perform translation Vector2D moveVector = (positionEvent->GetPointerPositionOnScreen() - m_LastDisplayCoordinate) * invertModifier; moveVector *= sender->GetScaleFactorMMPerDisplayUnit(); sender->GetCameraController()->MoveBy(moveVector); - sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(sender->GetRenderWindow()); m_LastDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); } void mitk::DisplayInteractor::SetCrosshair(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { auto* positionEvent = static_cast(interactionEvent); Point3D pos = positionEvent->GetPositionInWorld(); const BaseRenderer::Pointer sender = interactionEvent->GetSender(); - auto renWindows = sender->GetRenderingManager()->GetAllRegisteredRenderWindows(); + auto renWindows = RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); for (auto renWin : renWindows) { if (BaseRenderer::GetInstance(renWin)->GetMapperID() == BaseRenderer::Standard2D && renWin != sender->GetRenderWindow()) { BaseRenderer::GetInstance(renWin)->GetSliceNavigationController()->SelectSliceByPoint(pos); } } } void mitk::DisplayInteractor::IncreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { - auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Next(); } void mitk::DisplayInteractor::DecreaseTimeStep(StateMachineAction *, InteractionEvent *interactionEvent) { - auto sliceNaviController = interactionEvent->GetSender()->GetRenderingManager()->GetTimeNavigationController(); + auto sliceNaviController = RenderingManager::GetInstance()->GetTimeNavigationController(); auto stepper = sliceNaviController->GetTime(); stepper->SetAutoRepeat(true); stepper->Previous(); } void mitk::DisplayInteractor::Zoom(StateMachineAction *, InteractionEvent *interactionEvent) { float factor = 1.0; float distance = 0; if (m_ZoomDirection == "updown") { distance = m_CurrentDisplayCoordinate[1] - m_LastDisplayCoordinate[1]; } else { distance = m_CurrentDisplayCoordinate[0] - m_LastDisplayCoordinate[0]; } if (m_InvertZoomDirection) { distance *= -1.0; } // set zooming speed if (distance < 0.0) { factor = 1.0 / m_ZoomFactor; } else if (distance > 0.0) { factor = 1.0 * m_ZoomFactor; } auto* positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); if (factor != 1.0) { const BaseRenderer::Pointer sender = interactionEvent->GetSender(); sender->GetCameraController()->Zoom(factor, m_StartCoordinateInMM); - sender->GetRenderingManager()->RequestUpdate(sender->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(sender->GetRenderWindow()); } } void mitk::DisplayInteractor::Scroll(StateMachineAction *, InteractionEvent *interactionEvent) { auto* positionEvent = static_cast(interactionEvent); mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (sliceNaviController) { int delta = 0; // Scrolling direction if (m_ScrollDirection == "updown") { delta = static_cast(m_LastDisplayCoordinate[1] - positionEvent->GetPointerPositionOnScreen()[1]); } else { delta = static_cast(m_LastDisplayCoordinate[0] - positionEvent->GetPointerPositionOnScreen()[0]); } if (m_InvertScrollDirection) { delta *= -1; } // Set how many pixels the mouse has to be moved to scroll one slice // if we moved less than 'm_IndexToSliceModifier' pixels slice ONE slice only if (delta > 0 && delta < m_IndexToSliceModifier) { delta = m_IndexToSliceModifier; } else if (delta < 0 && delta > -m_IndexToSliceModifier) { delta = -m_IndexToSliceModifier; } delta /= m_IndexToSliceModifier; int newPos = sliceNaviController->GetSlice()->GetPos() + delta; // if auto repeat is on, start at first slice if you reach the last slice and vice versa int maxSlices = sliceNaviController->GetSlice()->GetSteps(); if (m_AutoRepeat) { while (newPos < 0) { newPos += maxSlices; } while (newPos >= maxSlices) { newPos -= maxSlices; } } else { // if the new slice is below 0 we still show slice 0 // due to the stepper using unsigned int we have to do this ourselves if (newPos < 1) { newPos = 0; } } m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // set the new position sliceNaviController->GetSlice()->SetPos(newPos); } } void mitk::DisplayInteractor::ScrollOneDown(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Next(); } } void mitk::DisplayInteractor::ScrollOneUp(StateMachineAction *, InteractionEvent *interactionEvent) { mitk::SliceNavigationController::Pointer sliceNaviController = interactionEvent->GetSender()->GetSliceNavigationController(); if (!sliceNaviController->GetSliceLocked()) { mitk::Stepper *stepper = sliceNaviController->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = sliceNaviController->GetTime(); } stepper->Previous(); } } void mitk::DisplayInteractor::AdjustLevelWindow(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer::Pointer sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); // search for active image mitk::DataStorage::Pointer storage = sender->GetDataStorage(); mitk::DataNode::Pointer node = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer allImageNodes = storage->GetSubset(mitk::NodePredicateDataType::New("Image")); for (unsigned int i = 0; i < allImageNodes->size(); ++i) { bool isActiveImage = false; bool propFound = allImageNodes->at(i)->GetBoolProperty("imageForLevelWindow", isActiveImage); if (propFound && isActiveImage) { node = allImageNodes->at(i); continue; } } if (node.IsNull()) { node = storage->GetNode(mitk::NodePredicateDataType::New("Image")); } if (node.IsNull()) { return; } mitk::LevelWindow lv = mitk::LevelWindow(); node->GetLevelWindow(lv); ScalarType level = lv.GetLevel(); ScalarType window = lv.GetWindow(); int levelIndex = 0; int windowIndex = 1; if (m_LevelDirection != "leftright") { levelIndex = 1; windowIndex = 0; } int directionModifier = 1; if (m_InvertLevelWindowDirection) { directionModifier = -1; } // calculate adjustments from mouse movements level += (m_CurrentDisplayCoordinate[levelIndex] - m_LastDisplayCoordinate[levelIndex]) * static_cast(2) * directionModifier; window += (m_CurrentDisplayCoordinate[windowIndex] - m_LastDisplayCoordinate[windowIndex]) * static_cast(2) * directionModifier; lv.SetLevelWindow(level, window); dynamic_cast(node->GetProperty("levelwindow"))->SetLevelWindow(lv); - sender->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayInteractor::StartRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->SetMouseCursor(rotate_cursor_xpm, 0, 0); } void mitk::DisplayInteractor::EndRotation(mitk::StateMachineAction *, mitk::InteractionEvent *) { this->ResetMouseCursor(); } void mitk::DisplayInteractor::Rotate(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (posEvent == nullptr) return; Point3D cursor = posEvent->GetPositionInWorld(); Vector3D toProjected = m_LastCursorPosition - m_CenterOfRotation; Vector3D toCursor = cursor - m_CenterOfRotation; // cross product: | A x B | = |A| * |B| * sin(angle) Vector3D axisOfRotation; vnl_vector_fixed vnlDirection = vnl_cross_3d(toCursor.GetVnlVector(), toProjected.GetVnlVector()); axisOfRotation.SetVnlVector(vnlDirection); // scalar product: A * B = |A| * |B| * cos(angle) // tan = sin / cos ScalarType angle = -atan2((double)(axisOfRotation.GetNorm()), (double)(toCursor * toProjected)); angle *= 180.0 / vnl_math::pi; m_LastCursorPosition = cursor; // create RotationOperation and apply to all SNCs that should be rotated RotationOperation rotationOperation(OpROTATE, m_CenterOfRotation, axisOfRotation, angle); // iterate the OTHER slice navigation controllers: these are filled in DoDecideBetweenRotationAndSliceSelection for (auto iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&rotationOperation); (*iter)->SendCreatedWorldGeometryUpdate(); } RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::DisplayInteractor::Swivel(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto *posEvent = dynamic_cast(event); if (!posEvent) return; // Determine relative mouse movement projected onto world space Point2D cursor = posEvent->GetPointerPositionOnScreen(); Vector2D relativeCursor = cursor - m_ReferenceCursor; Vector3D relativeCursorAxis = m_RotationPlaneXVector * relativeCursor[0] + m_RotationPlaneYVector * relativeCursor[1]; // Determine rotation axis (perpendicular to rotation plane and cursor // movement) Vector3D rotationAxis = itk::CrossProduct(m_RotationPlaneNormal, relativeCursorAxis); ScalarType rotationAngle = relativeCursor.GetNorm() / 2.0; // Restore the initial plane pose by undoing the previous rotation // operation RotationOperation op(OpROTATE, m_CenterOfRotation, m_PreviousRotationAxis, -m_PreviousRotationAngle); SNCVector::iterator iter; for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; timeGeometry->ExecuteOperation(&op); (*iter)->SendCreatedWorldGeometryUpdate(); } } // Apply new rotation operation to all relevant SNCs RotationOperation op2(OpROTATE, m_CenterOfRotation, rotationAxis, rotationAngle); for (iter = m_SNCsToBeRotated.begin(); iter != m_SNCsToBeRotated.end(); ++iter) { if (!(*iter)->GetSliceRotationLocked()) { // Retrieve the TimeGeometry of this SliceNavigationController TimeGeometry *timeGeometry = (*iter)->GetCreatedWorldGeometry(); if (!timeGeometry) continue; // Execute the new rotation timeGeometry->ExecuteOperation(&op2); // Notify listeners (*iter)->SendCreatedWorldGeometryUpdate(); } } m_PreviousRotationAxis = rotationAxis; m_PreviousRotationAngle = rotationAngle; RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::DisplayInteractor::UpdateStatusbar(mitk::StateMachineAction *, mitk::InteractionEvent *event) { const auto* posEvent = dynamic_cast(event); if (nullptr == posEvent) { return; } const mitk::BaseRenderer::Pointer baseRenderer = posEvent->GetSender(); TNodePredicateDataType::Pointer isImageData = TNodePredicateDataType::New(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = baseRenderer->GetDataStorage()->GetSubset(isImageData).GetPointer(); if (nodes.IsNull()) { return; } // posEvent->GetPositionInWorld() would return the world position at the // time of initiating the interaction. However, we need to update the // status bar with the position after changing slice. Therefore, we // translate the same display position with the renderer again to // get the new world position. Point3D worldposition; baseRenderer->DisplayToWorld(posEvent->GetPointerPositionOnScreen(), worldposition); mitk::Image::Pointer image3D; mitk::DataNode::Pointer node; mitk::DataNode::Pointer topSourceNode; int component = 0; node = FindTopmostVisibleNode(nodes, worldposition, globalCurrentTimePoint, baseRenderer); if (node.IsNull()) { return; } bool isBinary(false); node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = baseRenderer->GetDataStorage()->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, worldposition, globalCurrentTimePoint, baseRenderer); } if (topSourceNode.IsNotNull()) { image3D = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image3D = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } // get the position and gray value from the image and build up status bar text auto statusBar = StatusBar::GetInstance(); if (image3D.IsNotNull() && statusBar != nullptr) { itk::Index<3> p; image3D->GetGeometry()->WorldToIndex(worldposition, p); auto pixelType = image3D->GetChannelDescriptor().GetPixelType().GetPixelType(); if (pixelType == itk::ImageIOBase::RGB || pixelType == itk::ImageIOBase::RGBA) { std::string pixelValue = "Pixel RGB(A) value: "; pixelValue.append(ConvertCompositePixelValueToString(image3D, p)); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } else if (pixelType == itk::ImageIOBase::DIFFUSIONTENSOR3D || pixelType == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR) { std::string pixelValue = "See ODF Details view. "; statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue.c_str()); } else { mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image3D->GetChannelDescriptor().GetPixelType(), image3D, image3D->GetVolumeData(image3D->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), p, pixelValue, component); statusBar->DisplayImageInfo(worldposition, p, globalCurrentTimePoint, pixelValue); } } else { statusBar->DisplayImageInfoInvalid(); } } void mitk::DisplayInteractor::ConfigurationChanged() { mitk::PropertyList::Pointer properties = GetAttributes(); // auto repeat std::string strAutoRepeat = ""; if (properties->GetStringProperty("autoRepeat", strAutoRepeat)) { if (strAutoRepeat == "true") { m_AutoRepeat = true; } else { m_AutoRepeat = false; } } // pixel movement for scrolling one slice std::string strPixelPerSlice = ""; if (properties->GetStringProperty("pixelPerSlice", strPixelPerSlice)) { m_IndexToSliceModifier = atoi(strPixelPerSlice.c_str()); } else { m_IndexToSliceModifier = 4; } // scroll direction if (!properties->GetStringProperty("scrollDirection", m_ScrollDirection)) { m_ScrollDirection = "updown"; } m_InvertScrollDirection = GetBoolProperty(properties, "invertScrollDirection", false); // zoom direction if (!properties->GetStringProperty("zoomDirection", m_ZoomDirection)) { m_ZoomDirection = "updown"; } m_InvertZoomDirection = GetBoolProperty(properties, "invertZoomDirection", false); m_InvertMoveDirection = GetBoolProperty(properties, "invertMoveDirection", false); if (!properties->GetStringProperty("levelWindowDirection", m_LevelDirection)) { m_LevelDirection = "leftright"; } m_InvertLevelWindowDirection = GetBoolProperty(properties, "invertLevelWindowDirection", false); // coupled rotation std::string strCoupled = ""; if (properties->GetStringProperty("coupled", strCoupled)) { if (strCoupled == "true") m_LinkPlanes = true; else m_LinkPlanes = false; } // zoom factor std::string strZoomFactor = ""; properties->GetStringProperty("zoomFactor", strZoomFactor); m_ZoomFactor = .05; if (atoi(strZoomFactor.c_str()) > 0) { m_ZoomFactor = 1.0 + (atoi(strZoomFactor.c_str()) / 100.0); } // allwaysReact std::string strAlwaysReact = ""; if (properties->GetStringProperty("alwaysReact", strAlwaysReact)) { if (strAlwaysReact == "true") { m_AlwaysReact = true; } else { m_AlwaysReact = false; } } else { m_AlwaysReact = false; } } bool mitk::DisplayInteractor::FilterEvents(InteractionEvent *interactionEvent, DataNode * /*dataNode*/) { if (interactionEvent->GetSender() == nullptr) return false; if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard3D) return false; return true; } bool mitk::DisplayInteractor::GetBoolProperty(mitk::PropertyList::Pointer propertyList, const char *propertyName, bool defaultValue) { std::string valueAsString; if (!propertyList->GetStringProperty(propertyName, valueAsString)) { return defaultValue; } else { if (valueAsString == "true") { return true; } else { return false; } } } diff --git a/Modules/Core/src/Interactions/mitkPointSetDataInteractor.cpp b/Modules/Core/src/Interactions/mitkPointSetDataInteractor.cpp index 4c23fa04e4..fe541eefcd 100644 --- a/Modules/Core/src/Interactions/mitkPointSetDataInteractor.cpp +++ b/Modules/Core/src/Interactions/mitkPointSetDataInteractor.cpp @@ -1,626 +1,625 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkPointSetDataInteractor.h" #include "mitkMouseMoveEvent.h" #include "mitkInteractionConst.h" // TODO: refactor file #include "mitkInternalEvent.h" #include "mitkOperationEvent.h" #include "mitkRenderingManager.h" #include // #include "mitkBaseRenderer.h" #include "mitkDispatcher.h" #include "mitkUndoController.h" void mitk::PointSetDataInteractor::ConnectActionsAndFunctions() { // Condition which is evaluated before transition is taken // following actions in the statemachine are only executed if it returns TRUE CONNECT_CONDITION("isoverpoint", CheckSelection); CONNECT_FUNCTION("addpoint", AddPoint); CONNECT_FUNCTION("selectpoint", SelectPoint); CONNECT_FUNCTION("unselect", UnSelectPointAtPosition); CONNECT_FUNCTION("unselectAll", UnSelectAll); CONNECT_FUNCTION("initMove", InitMove); CONNECT_FUNCTION("movePoint", MovePoint); CONNECT_FUNCTION("finishMovement", FinishMove); CONNECT_FUNCTION("removePoint", RemovePoint); } void mitk::PointSetDataInteractor::AddPoint(StateMachineAction *stateMachineAction, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); // disallow adding of new points if maximum number of points is reached if (m_MaxNumberOfPoints > 1 && m_PointSet->GetSize(timeStep) >= m_MaxNumberOfPoints) { return; } // To add a point the minimal information is the position, this method accepts all InteractionsPositionEvents auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { mitk::Point3D itkPoint = positionEvent->GetPositionInWorld(); this->UnselectAll(timeStep, timeInMs); int lastPosition = 0; mitk::PointSet::PointsIterator it, end; it = m_PointSet->Begin(timeStep); end = m_PointSet->End(timeStep); while (it != end) { if (!m_PointSet->IndexExists(lastPosition, timeStep)) break; ++it; ++lastPosition; } // Insert a Point to the PointSet // 2) Create the Operation inserting the point if (m_PointSet->IsEmpty()) { lastPosition = 0; } auto *doOp = new mitk::PointOperation(OpINSERT, timeInMs, itkPoint, lastPosition); // 3) If Undo is enabled, also create the inverse Operation if (m_UndoEnabled) { auto *undoOp = new mitk::PointOperation(OpREMOVE, timeInMs, itkPoint, lastPosition); // 4) Do and Undo Operations are combined in an Operation event which also contains the target of the operations // (here m_PointSet) OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Add point"); // 5) Store the Operation in the UndoController OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); } // 6) Execute the Operation performs the actual insertion of the point into the PointSet m_PointSet->ExecuteOperation(doOp); // 7) If Undo is not enabled the Do-Operation is to be dropped to prevent memory leaks. if (!m_UndoEnabled) delete doOp; - // Request update - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); // Check if points form a closed contour now, if so fire an InternalEvent IsClosedContour(stateMachineAction, interactionEvent); if (m_MaxNumberOfPoints > 0 && m_PointSet->GetSize(timeStep) >= m_MaxNumberOfPoints) { // Signal that DataNode is fully filled this->NotifyResultReady(); // Send internal event that can be used by StateMachines to switch in a different state InternalEvent::Pointer event = InternalEvent::New(nullptr, this, "MaximalNumberOfPoints"); positionEvent->GetSender()->GetDispatcher()->QueueEvent(event.GetPointer()); } } } void mitk::PointSetDataInteractor::SelectPoint(StateMachineAction *, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { Point3D point = positionEvent->GetPositionInWorld(); // iterate over point set and check if it contains a point close enough to the pointer to be selected int index = GetPointIndexByPosition(point, timeStep); if (index != -1) { // first deselect the other points // undoable deselect of all points in the DataList this->UnselectAll(timeStep, timeInMs); auto *doOp = new mitk::PointOperation(OpSELECTPOINT, timeInMs, point, index); /*if (m_UndoEnabled) { PointOperation* undoOp = new mitk::PointOperation(OpDESELECTPOINT,timeInMs,point, index); OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Select Point"); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); }*/ // execute the Operation m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } } mitk::PointSetDataInteractor::PointSetDataInteractor() : m_MaxNumberOfPoints(0), m_SelectionAccuracy(3.5) { } mitk::PointSetDataInteractor::~PointSetDataInteractor() { } void mitk::PointSetDataInteractor::RemovePoint(StateMachineAction *, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { mitk::Point3D itkPoint = positionEvent->GetPositionInWorld(); // search the point in the list int position = m_PointSet->SearchPoint(itkPoint, m_SelectionAccuracy, timeStep); if (position >= 0) // found a point { PointSet::PointType pt = m_PointSet->GetPoint(position, timeStep); itkPoint[0] = pt[0]; itkPoint[1] = pt[1]; itkPoint[2] = pt[2]; auto *doOp = new mitk::PointOperation(OpREMOVE, timeInMs, itkPoint, position); if (m_UndoEnabled) // write to UndoMechanism { auto *undoOp = new mitk::PointOperation(OpINSERT, timeInMs, itkPoint, position); OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Remove point"); mitk::OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); } // execute the Operation m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; /*now select the point "position-1", and if it is the first in list, then continue at the last in list*/ // only then a select of a point is possible! if (m_PointSet->GetSize(timeStep) > 0) { this->SelectPoint(m_PointSet->Begin(timeStep)->Index(), timeStep, timeInMs); } } - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::PointSetDataInteractor::IsClosedContour(StateMachineAction *, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { Point3D point = positionEvent->GetPositionInWorld(); // iterate over point set and check if it contains a point close enough to the pointer to be selected if (GetPointIndexByPosition(point, timeStep) != -1 && m_PointSet->GetSize(timeStep) >= 3) { InternalEvent::Pointer event = InternalEvent::New(nullptr, this, "ClosedContour"); positionEvent->GetSender()->GetDispatcher()->QueueEvent(event.GetPointer()); } } } void mitk::PointSetDataInteractor::MovePoint(StateMachineAction *stateMachineAction, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { IsClosedContour(stateMachineAction, interactionEvent); mitk::Point3D newPoint, resultPoint; newPoint = positionEvent->GetPositionInWorld(); // search the elements in the list that are selected then calculate the // vector, because only with the vector we can move several elements in // the same direction // newPoint - lastPoint = vector // then move all selected and set the lastPoint = newPoint. // then add all vectors to a summeryVector (to be able to calculate the // startpoint for undoOperation) mitk::Vector3D dirVector = newPoint - m_LastPoint; // sum up all Movement for Undo in FinishMovement m_SumVec = m_SumVec + dirVector; mitk::PointSet::PointsIterator it, end; it = m_PointSet->Begin(timeStep); end = m_PointSet->End(timeStep); while (it != end) { int position = it->Index(); if (m_PointSet->GetSelectInfo(position, timeStep)) // if selected { PointSet::PointType pt = m_PointSet->GetPoint(position, timeStep); mitk::Point3D sumVec; sumVec[0] = pt[0]; sumVec[1] = pt[1]; sumVec[2] = pt[2]; resultPoint = sumVec + dirVector; auto *doOp = new mitk::PointOperation(OpMOVE, timeInMs, resultPoint, position); // execute the Operation // here no undo is stored, because the movement-steps aren't interesting. // only the start and the end is interisting to store for undo. m_PointSet->ExecuteOperation(doOp); delete doOp; } ++it; } m_LastPoint = newPoint; // for calculation of the direction vector // Update the display - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); IsClosedContour(stateMachineAction, interactionEvent); } } void mitk::PointSetDataInteractor::UnSelectPointAtPosition(StateMachineAction *, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { Point3D point = positionEvent->GetPositionInWorld(); // iterate over point set and check if it contains a point close enough to the pointer to be selected int index = GetPointIndexByPosition(point, timeStep); // here it is ensured that we don't switch from one point being selected to another one being selected, // without accepting the unselect of the current point if (index != -1) { auto *doOp = new mitk::PointOperation(OpDESELECTPOINT, timeInMs, point, index); /*if (m_UndoEnabled) { PointOperation* undoOp = new mitk::PointOperation(OpSELECTPOINT,timeInMs, point, index); OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Unselect Point"); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); }*/ m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } } void mitk::PointSetDataInteractor::UnSelectAll(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { Point3D positioninWorld = positionEvent->GetPositionInWorld(); PointSet::PointsContainer::Iterator it, end; PointSet::DataType *itkPointSet = m_PointSet->GetPointSet(timeStep); end = itkPointSet->GetPoints()->End(); for (it = itkPointSet->GetPoints()->Begin(); it != end; it++) { int position = it->Index(); // then declare an operation which unselects this point; // UndoOperation as well! if (m_PointSet->GetSelectInfo(position, timeStep)) { float distance = sqrt(positioninWorld.SquaredEuclideanDistanceTo(m_PointSet->GetPoint(position, timeStep))); if (distance > m_SelectionAccuracy) { mitk::Point3D noPoint; noPoint.Fill(0); auto *doOp = new mitk::PointOperation(OpDESELECTPOINT, timeInMs, noPoint, position); /*if ( m_UndoEnabled ) { mitk::PointOperation* undoOp = new mitk::PointOperation(OpSELECTPOINT, timeInMs, noPoint, position); OperationEvent *operationEvent = new OperationEvent( m_PointSet, doOp, undoOp, "Unselect Point" ); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent( operationEvent ); }*/ m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; } } } } else { this->UnselectAll(timeStep, timeInMs); } - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PointSetDataInteractor::UpdatePointSet(mitk::StateMachineAction *, mitk::InteractionEvent *) { auto *pointSet = dynamic_cast(this->GetDataNode()->GetData()); if (pointSet == nullptr) { MITK_ERROR << "PointSetDataInteractor:: No valid point set ."; return; } m_PointSet = pointSet; } void mitk::PointSetDataInteractor::Abort(StateMachineAction *, InteractionEvent *interactionEvent) { InternalEvent::Pointer event = InternalEvent::New(nullptr, this, IntDeactivateMe); interactionEvent->GetSender()->GetDispatcher()->QueueEvent(event.GetPointer()); } /* * Check whether the DataNode contains a pointset, if not create one and add it. */ void mitk::PointSetDataInteractor::DataNodeChanged() { if (GetDataNode() != nullptr) { auto *points = dynamic_cast(GetDataNode()->GetData()); if (points == nullptr) { m_PointSet = PointSet::New(); GetDataNode()->SetData(m_PointSet); } else { m_PointSet = points; } // load config file parameter: maximal number of points mitk::PropertyList::Pointer properties = GetAttributes(); std::string strNumber; if (properties->GetStringProperty("MaxPoints", strNumber)) { m_MaxNumberOfPoints = atoi(strNumber.c_str()); } } } void mitk::PointSetDataInteractor::InitMove(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; // start of the Movement is stored to calculate the undoKoordinate // in FinishMovement m_LastPoint = positionEvent->GetPositionInWorld(); // initialize a value to calculate the movement through all // MouseMoveEvents from MouseClick to MouseRelease m_SumVec.Fill(0); GetDataNode()->SetProperty("contourcolor", ColorProperty::New(1.0, 1.0, 1.0)); } void mitk::PointSetDataInteractor::FinishMove(StateMachineAction *, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { // finish the movement: // the final point is m_LastPoint // m_SumVec stores the movement in a vector // the operation would not be necessary, but we need it for the undo Operation. // m_LastPoint is for the Operation // the point for undoOperation calculates from all selected // elements (point) - m_SumVec // search all selected elements and move them with undo-functionality. mitk::PointSet::PointsIterator it, end; it = m_PointSet->Begin(timeStep); end = m_PointSet->End(timeStep); while (it != end) { int position = it->Index(); if (m_PointSet->GetSelectInfo(position, timeStep)) // if selected { PointSet::PointType pt = m_PointSet->GetPoint(position, timeStep); Point3D itkPoint; itkPoint[0] = pt[0]; itkPoint[1] = pt[1]; itkPoint[2] = pt[2]; auto *doOp = new mitk::PointOperation(OpMOVE, timeInMs, itkPoint, position); if (m_UndoEnabled) //&& (posEvent->GetType() == mitk::Type_MouseButtonRelease) { // set the undo-operation, so the final position is undo-able // calculate the old Position from the already moved position - m_SumVec mitk::Point3D undoPoint = (itkPoint - m_SumVec); auto *undoOp = new mitk::PointOperation(OpMOVE, timeInMs, undoPoint, position); OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Move point"); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); } // execute the Operation m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; } ++it; } // Update the display - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } else { return; } this->NotifyResultReady(); } void mitk::PointSetDataInteractor::SetAccuracy(float accuracy) { m_SelectionAccuracy = accuracy; } void mitk::PointSetDataInteractor::SetMaxPoints(unsigned int maxNumber) { m_MaxNumberOfPoints = maxNumber; } int mitk::PointSetDataInteractor::GetPointIndexByPosition(Point3D position, unsigned int time, float accuracy) { // iterate over point set and check if it contains a point close enough to the pointer to be selected auto *points = dynamic_cast(GetDataNode()->GetData()); int index = -1; if (points == nullptr) { return index; } if (points->GetPointSet(time) == nullptr) return -1; PointSet::PointsContainer *pointsContainer = points->GetPointSet(time)->GetPoints(); float minDistance = m_SelectionAccuracy; if (accuracy != -1) minDistance = accuracy; for (PointSet::PointsIterator it = pointsContainer->Begin(); it != pointsContainer->End(); it++) { float distance = sqrt(position.SquaredEuclideanDistanceTo(points->GetPoint(it->Index(), time))); if (distance < minDistance) // if several points fall within the margin, choose the one with minimal distance to position { index = it->Index(); } } return index; } bool mitk::PointSetDataInteractor::CheckSelection(const mitk::InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { int timeStep = positionEvent->GetSender()->GetTimeStep(); Point3D point = positionEvent->GetPositionInWorld(); // iterate over point set and check if it contains a point close enough to the pointer to be selected int index = GetPointIndexByPosition(point, timeStep); if (index != -1) return true; } return false; } void mitk::PointSetDataInteractor::UnselectAll(unsigned int timeStep, ScalarType timeInMs) { auto *pointSet = dynamic_cast(GetDataNode()->GetData()); if (pointSet == nullptr) { return; } mitk::PointSet::DataType *itkPointSet = pointSet->GetPointSet(timeStep); if (itkPointSet == nullptr) { return; } mitk::PointSet::PointsContainer::Iterator it, end; end = itkPointSet->GetPoints()->End(); for (it = itkPointSet->GetPoints()->Begin(); it != end; it++) { int position = it->Index(); PointSet::PointDataType pointData = {0, false, PTUNDEFINED}; itkPointSet->GetPointData(position, &pointData); // then declare an operation which unselects this point; // UndoOperation as well! if (pointData.selected) { mitk::Point3D noPoint; noPoint.Fill(0); auto *doOp = new mitk::PointOperation(OpDESELECTPOINT, timeInMs, noPoint, position); /*if ( m_UndoEnabled ) { mitk::PointOperation *undoOp = new mitk::PointOperation(OpSELECTPOINT, timeInMs, noPoint, position); OperationEvent *operationEvent = new OperationEvent( pointSet, doOp, undoOp, "Unselect Point" ); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent( operationEvent ); }*/ pointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; } } } void mitk::PointSetDataInteractor::SelectPoint(int position, unsigned int timeStep, ScalarType timeInMS) { auto *pointSet = dynamic_cast(this->GetDataNode()->GetData()); // if List is empty, then no selection of a point can be done! if ((pointSet == nullptr) || (pointSet->GetSize(timeStep) <= 0)) { return; } // dummyPoint... not needed anyway mitk::Point3D noPoint; noPoint.Fill(0); auto *doOp = new mitk::PointOperation(OpSELECTPOINT, timeInMS, noPoint, position); /*if ( m_UndoEnabled ) { mitk::PointOperation* undoOp = new mitk::PointOperation(OpDESELECTPOINT,timeInMS, noPoint, position); OperationEvent *operationEvent = new OperationEvent(pointSet, doOp, undoOp, "Select Point"); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); }*/ pointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; } diff --git a/Modules/Core/src/Interactions/mitkSinglePointDataInteractor.cpp b/Modules/Core/src/Interactions/mitkSinglePointDataInteractor.cpp index 70e751b24a..5d413d89ce 100644 --- a/Modules/Core/src/Interactions/mitkSinglePointDataInteractor.cpp +++ b/Modules/Core/src/Interactions/mitkSinglePointDataInteractor.cpp @@ -1,107 +1,106 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSinglePointDataInteractor.h" #include "mitkMouseMoveEvent.h" #include "mitkInteractionConst.h" // TODO: refactor file #include "mitkInternalEvent.h" #include "mitkOperationEvent.h" #include "mitkRenderingManager.h" #include // #include "mitkBaseRenderer.h" #include "mitkDispatcher.h" #include "mitkUndoController.h" mitk::SinglePointDataInteractor::SinglePointDataInteractor() { this->SetMaxPoints(1); } mitk::SinglePointDataInteractor::~SinglePointDataInteractor() { } void mitk::SinglePointDataInteractor::AddPoint(StateMachineAction * /*stateMachineAction*/, InteractionEvent *interactionEvent) { unsigned int timeStep = interactionEvent->GetSender()->GetTimeStep(GetDataNode()->GetData()); ScalarType timeInMs = interactionEvent->GetSender()->GetTime(); // To add a point the minimal information is the position, this method accepts all InteractionsPositionEvents auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent != nullptr) { PointOperation *doOp; PointOperation *undoOp; if (m_PointSet->IndexExists(0, timeStep)) { PointSet::PointType pt = m_PointSet->GetPoint(0, timeStep); Point3D itkPoint; itkPoint[0] = pt[0]; itkPoint[1] = pt[1]; itkPoint[2] = pt[2]; doOp = new mitk::PointOperation(OpMOVE, timeInMs, positionEvent->GetPositionInWorld(), 0); undoOp = new mitk::PointOperation(OpMOVE, timeInMs, itkPoint, 0); } else { doOp = new mitk::PointOperation(OpINSERT, timeInMs, positionEvent->GetPositionInWorld(), 0); undoOp = new mitk::PointOperation(OpREMOVE, timeInMs, positionEvent->GetPositionInWorld(), 0); } if (m_UndoEnabled) { OperationEvent *operationEvent = new OperationEvent(m_PointSet, doOp, undoOp, "Move point"); OperationEvent::IncCurrObjectEventId(); m_UndoController->SetOperationEvent(operationEvent); } // execute the Operation m_PointSet->ExecuteOperation(doOp); if (!m_UndoEnabled) delete doOp; - // Request update - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } /* * Check whether the DataNode contains a pointset, if not create one and add it. */ void mitk::SinglePointDataInteractor::DataNodeChanged() { if (GetDataNode() != nullptr) { auto *points = dynamic_cast(GetDataNode()->GetData()); if (points == nullptr) { m_PointSet = PointSet::New(); GetDataNode()->SetData(m_PointSet); } else { points->Clear(); m_PointSet = points; } } } diff --git a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp index ed9225bacc..e0991e35b5 100644 --- a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp @@ -1,787 +1,779 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkBaseRenderer.h" #include "mitkMapper.h" #include "mitkResliceMethodProperty.h" // Geometries #include "mitkPlaneGeometry.h" #include "mitkSlicedGeometry3D.h" // Controllers #include "mitkCameraController.h" #include "mitkCameraRotationController.h" #include "mitkSliceNavigationController.h" #include "mitkVtkLayerController.h" #include "mitkInteractionConst.h" #include "mitkProperties.h" #include "mitkWeakPointerProperty.h" // VTK #include #include #include #include #include #include #include mitk::BaseRenderer::BaseRendererMapType mitk::BaseRenderer::baseRendererMap; mitk::BaseRenderer *mitk::BaseRenderer::GetInstance(vtkRenderWindow *renWin) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).first == renWin) return (*mapit).second; } return nullptr; } void mitk::BaseRenderer::AddInstance(vtkRenderWindow *renWin, BaseRenderer *baseRenderer) { if (renWin == nullptr || baseRenderer == nullptr) return; // ensure that no BaseRenderer is managed twice mitk::BaseRenderer::RemoveInstance(renWin); baseRendererMap.insert(BaseRendererMapType::value_type(renWin, baseRenderer)); } void mitk::BaseRenderer::RemoveInstance(vtkRenderWindow *renWin) { auto mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer *mitk::BaseRenderer::GetByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).second; } return nullptr; } vtkRenderWindow *mitk::BaseRenderer::GetRenderWindowByName(const std::string &name) { for (auto mapit = baseRendererMap.begin(); mapit != baseRendererMap.end(); ++mapit) { if ((*mapit).second->m_Name == name) return (*mapit).first; } return nullptr; } mitk::BaseRenderer::BaseRenderer(const char *name, - vtkRenderWindow *renWin, - mitk::RenderingManager *rm, - RenderingMode renderingMode) + vtkRenderWindow *renWin) : m_RenderWindow(nullptr), m_VtkRenderer(nullptr), m_MapperID(defaultMapper), m_DataStorage(nullptr), - m_RenderingManager(rm), m_LastUpdateTime(0), m_CameraController(nullptr), m_SliceNavigationController(nullptr), m_CameraRotationController(nullptr), m_WorldTimeGeometry(nullptr), m_CurrentWorldGeometry(nullptr), m_CurrentWorldPlaneGeometry(nullptr), m_Slice(0), m_TimeStep(), m_CurrentWorldPlaneGeometryUpdateTime(), m_TimeStepUpdateTime(), m_KeepDisplayedRegion(true), m_CurrentWorldPlaneGeometryData(nullptr), m_CurrentWorldPlaneGeometryNode(nullptr), m_CurrentWorldPlaneGeometryTransformTime(0), m_Name(name), m_EmptyWorldGeometry(true), m_NumberOfVisibleLODEnabledMappers(0) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; if (name != nullptr) { m_Name = name; } else { m_Name = "unnamed renderer"; itkWarningMacro(<< "Created unnamed renderer. Bad for serialization. Please choose a name."); } if (renWin != nullptr) { m_RenderWindow = renWin; m_RenderWindow->Register(nullptr); } else { itkWarningMacro(<< "Created mitkBaseRenderer without vtkRenderWindow present."); } // instances.insert( this ); // adding this BaseRenderer to the List of all BaseRenderer m_BindDispatcherInteractor = new mitk::BindDispatcherInteractor(GetName()); WeakPointerProperty::Pointer rendererProp = WeakPointerProperty::New((itk::Object *)this); m_CurrentWorldPlaneGeometry = mitk::PlaneGeometry::New(); m_CurrentWorldPlaneGeometryData = mitk::PlaneGeometryData::New(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryNode = mitk::DataNode::New(); m_CurrentWorldPlaneGeometryNode->SetData(m_CurrentWorldPlaneGeometryData); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("renderer", rendererProp); m_CurrentWorldPlaneGeometryNode->GetPropertyList()->SetProperty("layer", IntProperty::New(1000)); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New()); m_CurrentWorldPlaneGeometryNode->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(1)); m_CurrentWorldPlaneGeometryTransformTime = m_CurrentWorldPlaneGeometryNode->GetVtkTransform()->GetMTime(); mitk::SliceNavigationController::Pointer sliceNavigationController = mitk::SliceNavigationController::New(); sliceNavigationController->SetRenderer(this); sliceNavigationController->ConnectGeometrySliceEvent(this); sliceNavigationController->ConnectGeometryUpdateEvent(this); sliceNavigationController->ConnectGeometryTimeEvent(this, false); m_SliceNavigationController = sliceNavigationController; m_CameraRotationController = mitk::CameraRotationController::New(); m_CameraRotationController->SetRenderWindow(m_RenderWindow); m_CameraRotationController->AcquireCamera(); m_CameraController = mitk::CameraController::New(); m_CameraController->SetRenderer(this); m_VtkRenderer = vtkRenderer::New(); m_VtkRenderer->UseDepthPeelingOn(); m_VtkRenderer->UseDepthPeelingForVolumesOn(); m_VtkRenderer->SetMaximumNumberOfPeels(16); // This could be made adjustable in the Preferences m_VtkRenderer->SetOcclusionRatio(0.0); - if (RenderingMode::FastApproximateAntiAliasing == renderingMode) + if (AntiAliasing::FastApproximate == RenderingManager::GetInstance()->GetAntiAliasing()) m_VtkRenderer->UseFXAAOn(); if (nullptr == mitk::VtkLayerController::GetInstance(m_RenderWindow)) mitk::VtkLayerController::AddInstance(m_RenderWindow, m_VtkRenderer); mitk::VtkLayerController::GetInstance(m_RenderWindow)->InsertSceneRenderer(m_VtkRenderer); } mitk::BaseRenderer::~BaseRenderer() { if (m_VtkRenderer != nullptr) { m_VtkRenderer->Delete(); m_VtkRenderer = nullptr; } if (m_CameraController.IsNotNull()) m_CameraController->SetRenderer(nullptr); mitk::VtkLayerController::RemoveInstance(m_RenderWindow); RemoveAllLocalStorages(); m_DataStorage = nullptr; if (m_BindDispatcherInteractor != nullptr) { delete m_BindDispatcherInteractor; } if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); m_RenderWindow = nullptr; } } void mitk::BaseRenderer::RemoveAllLocalStorages() { this->InvokeEvent(mitk::BaseRenderer::RendererResetEvent()); std::list::iterator it; for (it = m_RegisteredLocalStorageHandlers.begin(); it != m_RegisteredLocalStorageHandlers.end(); ++it) (*it)->ClearLocalStorage(this, false); m_RegisteredLocalStorageHandlers.clear(); } void mitk::BaseRenderer::RegisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.push_back(lsh); } mitk::Dispatcher::Pointer mitk::BaseRenderer::GetDispatcher() const { return m_BindDispatcherInteractor->GetDispatcher(); } void mitk::BaseRenderer::UnregisterLocalStorageHandler(mitk::BaseLocalStorageHandler *lsh) { m_RegisteredLocalStorageHandlers.remove(lsh); } void mitk::BaseRenderer::SetDataStorage(DataStorage *storage) { if (storage != m_DataStorage && storage != nullptr) { m_DataStorage = storage; m_BindDispatcherInteractor->SetDataStorage(m_DataStorage); this->Modified(); } } const mitk::BaseRenderer::MapperSlotId mitk::BaseRenderer::defaultMapper = 1; void mitk::BaseRenderer::Paint() { } void mitk::BaseRenderer::Initialize() { } void mitk::BaseRenderer::Resize(int w, int h) { this->m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::InitRenderer(vtkRenderWindow *renderwindow) { if (m_RenderWindow != renderwindow) { if (m_RenderWindow != nullptr) { m_RenderWindow->Delete(); } m_RenderWindow = renderwindow; if (m_RenderWindow != nullptr) { m_RenderWindow->Register(nullptr); } } RemoveAllLocalStorages(); if (m_CameraController.IsNotNull()) { m_CameraController->SetRenderer(this); } } void mitk::BaseRenderer::InitSize(int w, int h) { this->m_RenderWindow->SetSize(w, h); } void mitk::BaseRenderer::SetSlice(unsigned int slice) { if (m_Slice != slice) { m_Slice = slice; if (m_WorldTimeGeometry.IsNotNull()) { // get world geometry which may be rotated, for the current time step SlicedGeometry3D *slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != nullptr) { // if slice position is part of the world geometry... if (m_Slice >= slicedWorldGeometry->GetSlices()) // set the current worldplanegeomety as the selected 2D slice of the world geometry m_Slice = slicedWorldGeometry->GetSlices() - 1; SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } void mitk::BaseRenderer::SetTimeStep(unsigned int timeStep) { if (m_TimeStep != timeStep) { m_TimeStep = timeStep; m_TimeStepUpdateTime.Modified(); if (m_WorldTimeGeometry.IsNotNull()) { if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; SlicedGeometry3D *slicedWorldGeometry = dynamic_cast(m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep).GetPointer()); if (slicedWorldGeometry != nullptr) { SetCurrentWorldPlaneGeometry(slicedWorldGeometry->GetPlaneGeometry(m_Slice)); SetCurrentWorldGeometry(slicedWorldGeometry); } } else Modified(); } } int mitk::BaseRenderer::GetTimeStep(const mitk::BaseData *data) const { if ((data == nullptr) || (data->IsInitialized() == false)) { return -1; } return data->GetTimeGeometry()->TimePointToTimeStep(GetTime()); } mitk::ScalarType mitk::BaseRenderer::GetTime() const { if (m_WorldTimeGeometry.IsNull()) { return 0; } else { ScalarType timeInMS = m_WorldTimeGeometry->TimeStepToTimePoint(GetTimeStep()); if (timeInMS == itk::NumericTraits::NonpositiveMin()) return 0; else return timeInMS; } } void mitk::BaseRenderer::SetWorldTimeGeometry(const mitk::TimeGeometry *geometry) { assert(geometry != nullptr); itkDebugMacro("setting WorldTimeGeometry to " << geometry); if (m_WorldTimeGeometry != geometry) { if (geometry->GetBoundingBoxInWorld()->GetDiagonalLength2() == 0) return; m_WorldTimeGeometry = geometry; itkDebugMacro("setting WorldTimeGeometry to " << m_WorldTimeGeometry); if (m_TimeStep >= m_WorldTimeGeometry->CountTimeSteps()) m_TimeStep = m_WorldTimeGeometry->CountTimeSteps() - 1; BaseGeometry *geometry3d; geometry3d = m_WorldTimeGeometry->GetGeometryForTimeStep(m_TimeStep); SetWorldGeometry3D(geometry3d); } } void mitk::BaseRenderer::SetWorldGeometry3D(const mitk::BaseGeometry *geometry) { itkDebugMacro("setting WorldGeometry3D to " << geometry); if (geometry->GetBoundingBox()->GetDiagonalLength2() == 0) return; const SlicedGeometry3D *slicedWorldGeometry; slicedWorldGeometry = dynamic_cast(geometry); PlaneGeometry::ConstPointer geometry2d; if (slicedWorldGeometry != nullptr) { if (m_Slice >= slicedWorldGeometry->GetSlices() && (m_Slice != 0)) m_Slice = slicedWorldGeometry->GetSlices() - 1; geometry2d = slicedWorldGeometry->GetPlaneGeometry(m_Slice); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = mitk::PlaneGeometry::New(); plane->InitializeStandardPlane(slicedWorldGeometry); geometry2d = plane; } SetCurrentWorldGeometry(slicedWorldGeometry); } else { geometry2d = dynamic_cast(geometry); if (geometry2d.IsNull()) { PlaneGeometry::Pointer plane = PlaneGeometry::New(); plane->InitializeStandardPlane(geometry); geometry2d = plane; } SetCurrentWorldGeometry(geometry); } SetCurrentWorldPlaneGeometry(geometry2d); // calls Modified() if (m_CurrentWorldPlaneGeometry.IsNull()) itkWarningMacro("m_CurrentWorldPlaneGeometry is nullptr"); } void mitk::BaseRenderer::SetCurrentWorldPlaneGeometry(const mitk::PlaneGeometry *geometry2d) { if (m_CurrentWorldPlaneGeometry != geometry2d) { m_CurrentWorldPlaneGeometry = geometry2d->Clone(); m_CurrentWorldPlaneGeometryData->SetPlaneGeometry(m_CurrentWorldPlaneGeometry); m_CurrentWorldPlaneGeometryUpdateTime.Modified(); Modified(); } } void mitk::BaseRenderer::SendUpdateSlice() { m_CurrentWorldPlaneGeometryUpdateTime.Modified(); } int *mitk::BaseRenderer::GetSize() const { return this->m_RenderWindow->GetSize(); } int *mitk::BaseRenderer::GetViewportSize() const { return this->m_VtkRenderer->GetSize(); } void mitk::BaseRenderer::SetCurrentWorldGeometry(const mitk::BaseGeometry *geometry) { m_CurrentWorldGeometry = geometry; if (geometry == nullptr) { m_Bounds[0] = 0; m_Bounds[1] = 0; m_Bounds[2] = 0; m_Bounds[3] = 0; m_Bounds[4] = 0; m_Bounds[5] = 0; m_EmptyWorldGeometry = true; return; } BoundingBox::Pointer boundingBox = m_CurrentWorldGeometry->CalculateBoundingBoxRelativeToTransform(nullptr); const BoundingBox::BoundsArrayType &worldBounds = boundingBox->GetBounds(); m_Bounds[0] = worldBounds[0]; m_Bounds[1] = worldBounds[1]; m_Bounds[2] = worldBounds[2]; m_Bounds[3] = worldBounds[3]; m_Bounds[4] = worldBounds[4]; m_Bounds[5] = worldBounds[5]; if (boundingBox->GetDiagonalLength2() <= mitk::eps) m_EmptyWorldGeometry = true; else m_EmptyWorldGeometry = false; } void mitk::BaseRenderer::SetGeometry(const itk::EventObject &geometrySendEvent) { const auto *sendEvent = dynamic_cast(&geometrySendEvent); assert(sendEvent != nullptr); SetWorldTimeGeometry(sendEvent->GetTimeGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject &geometryUpdateEvent) { const auto *updateEvent = dynamic_cast(&geometryUpdateEvent); if (updateEvent == nullptr) return; if (m_CurrentWorldGeometry.IsNotNull()) { auto *slicedWorldGeometry = dynamic_cast(m_CurrentWorldGeometry.GetPointer()); if (slicedWorldGeometry) { PlaneGeometry *geometry2D = slicedWorldGeometry->GetPlaneGeometry(m_Slice); SetCurrentWorldPlaneGeometry(geometry2D); // calls Modified() } } } void mitk::BaseRenderer::SetGeometrySlice(const itk::EventObject &geometrySliceEvent) { const auto *sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent != nullptr); SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject &geometryTimeEvent) { const auto *timeEvent = dynamic_cast(&geometryTimeEvent); assert(timeEvent != nullptr); SetTimeStep(timeEvent->GetPos()); } const double *mitk::BaseRenderer::GetBounds() const { return m_Bounds; } void mitk::BaseRenderer::DrawOverlayMouse(mitk::Point2D &itkNotUsed(p2d)) { MITK_INFO << "BaseRenderer::DrawOverlayMouse()- should be inconcret implementation OpenGLRenderer." << std::endl; } void mitk::BaseRenderer::RequestUpdate() { SetConstrainZoomingAndPanning(true); - m_RenderingManager->RequestUpdate(this->m_RenderWindow); + RenderingManager::GetInstance()->RequestUpdate(this->m_RenderWindow); } void mitk::BaseRenderer::ForceImmediateUpdate() { - m_RenderingManager->ForceImmediateUpdate(this->m_RenderWindow); + RenderingManager::GetInstance()->ForceImmediateUpdate(this->m_RenderWindow); } unsigned int mitk::BaseRenderer::GetNumberOfVisibleLODEnabledMappers() const { return m_NumberOfVisibleLODEnabledMappers; } -mitk::RenderingManager *mitk::BaseRenderer::GetRenderingManager() const -{ - return m_RenderingManager.GetPointer(); -} - /*! Sets the new Navigation controller */ void mitk::BaseRenderer::SetSliceNavigationController(mitk::SliceNavigationController *SlicenavigationController) { if (SlicenavigationController == nullptr) return; // copy worldgeometry SlicenavigationController->SetInputWorldTimeGeometry(SlicenavigationController->GetCreatedWorldGeometry()); SlicenavigationController->Update(); // set new m_SliceNavigationController = SlicenavigationController; m_SliceNavigationController->SetRenderer(this); if (m_SliceNavigationController.IsNotNull()) { m_SliceNavigationController->ConnectGeometrySliceEvent(this); m_SliceNavigationController->ConnectGeometryUpdateEvent(this); m_SliceNavigationController->ConnectGeometryTimeEvent(this, false); } } void mitk::BaseRenderer::DisplayToWorld(const Point2D &displayPoint, Point3D &worldIndex) const { if (m_MapperID == BaseRenderer::Standard2D) { double display[3], *world; // For the rigth z-position in display coordinates, take the focal point, convert it to display and use it for // correct depth. double *displayCoord; double cameraFP[4]; // Get camera focal point and position. Convert to display (screen) // coordinates. We need a depth value for z-buffer. this->GetVtkRenderer()->GetActiveCamera()->GetFocalPoint(cameraFP); cameraFP[3] = 0.0; this->GetVtkRenderer()->SetWorldPoint(cameraFP[0], cameraFP[1], cameraFP[2], cameraFP[3]); this->GetVtkRenderer()->WorldToDisplay(); displayCoord = this->GetVtkRenderer()->GetDisplayPoint(); // now convert the display point to world coordinates display[0] = displayPoint[0]; display[1] = displayPoint[1]; display[2] = displayCoord[2]; this->GetVtkRenderer()->SetDisplayPoint(display); this->GetVtkRenderer()->DisplayToWorld(); world = this->GetVtkRenderer()->GetWorldPoint(); for (int i = 0; i < 3; i++) { worldIndex[i] = world[i] / world[3]; } } else if (m_MapperID == BaseRenderer::Standard3D) { PickWorldPoint( displayPoint, worldIndex); // Seems to be the same code as above, but subclasses may contain different implementations. } return; } void mitk::BaseRenderer::DisplayToPlane(const Point2D &displayPoint, Point2D &planePointInMM) const { if (m_MapperID == BaseRenderer::Standard2D) { Point3D worldPoint; this->DisplayToWorld(displayPoint, worldPoint); this->m_CurrentWorldPlaneGeometry->Map(worldPoint, planePointInMM); } else if (m_MapperID == BaseRenderer::Standard3D) { MITK_WARN << "No conversion possible with 3D mapper."; return; } return; } void mitk::BaseRenderer::WorldToDisplay(const Point3D &worldIndex, Point2D &displayPoint) const { double world[4], *display; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToDisplay(); display = this->GetVtkRenderer()->GetDisplayPoint(); displayPoint[0] = display[0]; displayPoint[1] = display[1]; return; } void mitk::BaseRenderer::WorldToView(const mitk::Point3D &worldIndex, mitk::Point2D &viewPoint) const { double world[4], *view; world[0] = worldIndex[0]; world[1] = worldIndex[1]; world[2] = worldIndex[2]; world[3] = 1.0; this->GetVtkRenderer()->SetWorldPoint(world); this->GetVtkRenderer()->WorldToView(); view = this->GetVtkRenderer()->GetViewPoint(); this->GetVtkRenderer()->ViewToNormalizedViewport(view[0], view[1], view[2]); viewPoint[0] = view[0] * this->GetViewportSize()[0]; viewPoint[1] = view[1] * this->GetViewportSize()[1]; return; } void mitk::BaseRenderer::PlaneToDisplay(const Point2D &planePointInMM, Point2D &displayPoint) const { Point3D worldPoint; this->m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToDisplay(worldPoint, displayPoint); return; } void mitk::BaseRenderer::PlaneToView(const Point2D &planePointInMM, Point2D &viewPoint) const { Point3D worldPoint; this->m_CurrentWorldPlaneGeometry->Map(planePointInMM, worldPoint); this->WorldToView(worldPoint,viewPoint); return; } double mitk::BaseRenderer::GetScaleFactorMMPerDisplayUnit() const { if (this->GetMapperID() == BaseRenderer::Standard2D) { // GetParallelScale returns half of the height of the render window in mm. // Divided by the half size of the Display size in pixel givest the mm per pixel. return this->GetVtkRenderer()->GetActiveCamera()->GetParallelScale() * 2.0 / GetViewportSize()[1]; } else return 1.0; } mitk::Point2D mitk::BaseRenderer::GetDisplaySizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetSizeX() * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetSizeY() * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetViewportSizeInMM() const { Point2D dispSizeInMM; dispSizeInMM[0] = GetViewportSize()[0] * GetScaleFactorMMPerDisplayUnit(); dispSizeInMM[1] = GetViewportSize()[1] * GetScaleFactorMMPerDisplayUnit(); return dispSizeInMM; } mitk::Point2D mitk::BaseRenderer::GetOriginInMM() const { Point2D originPx; originPx[0] = m_VtkRenderer->GetOrigin()[0]; originPx[1] = m_VtkRenderer->GetOrigin()[1]; Point2D displayGeometryOriginInMM; DisplayToPlane(originPx, displayGeometryOriginInMM); // top left of the render window (Origin) return displayGeometryOriginInMM; } void mitk::BaseRenderer::SetConstrainZoomingAndPanning(bool constrain) { m_ConstrainZoomingAndPanning = constrain; if (m_ConstrainZoomingAndPanning) { this->GetCameraController()->AdjustCameraToPlane(); } } mitk::Point3D mitk::BaseRenderer::Map2DRendererPositionTo3DWorldPosition(const Point2D &mousePosition) const { // DEPRECATED: Map2DRendererPositionTo3DWorldPosition is deprecated. use DisplayToWorldInstead Point3D position; DisplayToWorld(mousePosition, position); return position; } void mitk::BaseRenderer::PrintSelf(std::ostream &os, itk::Indent indent) const { os << indent << " MapperID: " << m_MapperID << std::endl; os << indent << " Slice: " << m_Slice << std::endl; os << indent << " TimeStep: " << m_TimeStep << std::endl; os << indent << " CurrentWorldPlaneGeometry: "; if (m_CurrentWorldPlaneGeometry.IsNull()) os << "nullptr" << std::endl; else m_CurrentWorldPlaneGeometry->Print(os, indent); os << indent << " CurrentWorldPlaneGeometryUpdateTime: " << m_CurrentWorldPlaneGeometryUpdateTime << std::endl; os << indent << " CurrentWorldPlaneGeometryTransformTime: " << m_CurrentWorldPlaneGeometryTransformTime << std::endl; Superclass::PrintSelf(os, indent); } diff --git a/Modules/Core/src/Rendering/mitkRenderWindow.cpp b/Modules/Core/src/Rendering/mitkRenderWindow.cpp index cb9d75a1c1..23515e1424 100644 --- a/Modules/Core/src/Rendering/mitkRenderWindow.cpp +++ b/Modules/Core/src/Rendering/mitkRenderWindow.cpp @@ -1,87 +1,83 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRenderWindow.h" -#include "mitkRenderingManager.h" #include "mitkVtkEventProvider.h" #include "mitkVtkLayerController.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" -mitk::RenderWindow::RenderWindow(vtkRenderWindow *renWin, - const char *name, - mitk::RenderingManager *rm, - mitk::BaseRenderer::RenderingMode renderingMode) +mitk::RenderWindow::RenderWindow(vtkRenderWindow *renWin, const char *name) : m_vtkRenderWindow(renWin), m_vtkRenderWindowInteractor(nullptr), m_vtkMitkEventProvider(nullptr) { if (nullptr == m_vtkRenderWindow) { m_vtkRenderWindow = vtkRenderWindow::New(); m_vtkRenderWindow->SetMultiSamples(0); // We do not support MSAA as it is incompatible with depth peeling m_vtkRenderWindow->SetAlphaBitPlanes(1); // Necessary for depth peeling } if (m_vtkRenderWindow->GetSize()[0] <= 10) { m_vtkRenderWindow->SetSize(100, 100); } m_vtkRenderWindowInteractor = vtkRenderWindowInteractor::New(); m_vtkRenderWindowInteractor->SetRenderWindow(m_vtkRenderWindow); m_vtkRenderWindowInteractor->Initialize(); // initialize from RenderWindowBase - this->Initialize(rm, name, renderingMode); + this->Initialize(name); m_vtkMitkEventProvider = vtkEventProvider::New(); m_vtkMitkEventProvider->SetInteractor(this->GetVtkRenderWindowInteractor()); m_vtkMitkEventProvider->SetMitkRenderWindow(this); m_vtkMitkEventProvider->SetEnabled(1); } mitk::RenderWindow::~RenderWindow() { Destroy(); m_vtkRenderWindow->Delete(); m_vtkRenderWindowInteractor->Delete(); m_vtkMitkEventProvider->Delete(); } vtkRenderWindow *mitk::RenderWindow::GetVtkRenderWindow() { return m_vtkRenderWindow; } vtkRenderWindowInteractor *mitk::RenderWindow::GetVtkRenderWindowInteractor() { return m_vtkRenderWindowInteractor; } void mitk::RenderWindow::SetSize(int width, int height) { this->GetVtkRenderWindow()->SetSize(width, height); } void mitk::RenderWindow::ReinitEventProvider() { m_vtkMitkEventProvider->SetEnabled(0); m_vtkMitkEventProvider->SetInteractor(this->GetVtkRenderWindowInteractor()); m_vtkMitkEventProvider->SetMitkRenderWindow(this); m_vtkMitkEventProvider->SetEnabled(1); } diff --git a/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp b/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp index 64ba922ed5..e6a2c99c6c 100644 --- a/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp +++ b/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp @@ -1,117 +1,114 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRenderWindowBase.h" #include "mitkRenderingManager.h" #include "mitkVtkLayerController.h" #include "vtkRenderer.h" #include "mitkAnnotationUtils.h" mitk::RenderWindowBase::RenderWindowBase() : m_RenderProp(nullptr), m_InResize(false) { } /* * "Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a * virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from * a destructor, and the object to which the call applies is the object under construction or destruction, the function called is * the one defined in the constructor or destructor's own class or in one of its bases, but not a function overriding it in a class * derived from the constructor or destructor's class, or overriding it in one of the other base classes of the most derived object[..]" * or short: within constructors and destructors classes are not polymorph. */ -void mitk::RenderWindowBase::Initialize(mitk::RenderingManager *renderingManager, - const char *name, - mitk::BaseRenderer::RenderingMode renderingMode) +void mitk::RenderWindowBase::Initialize(const char *name) { - if (nullptr == renderingManager) - renderingManager = mitk::RenderingManager::GetInstance(); + auto renderingManager = mitk::RenderingManager::GetInstance(); if (m_Renderer.IsNull()) - m_Renderer = mitk::VtkPropRenderer::New(name, GetVtkRenderWindow(), renderingManager, renderingMode); + m_Renderer = mitk::VtkPropRenderer::New(name, GetVtkRenderWindow()); m_Renderer->InitRenderer(this->GetVtkRenderWindow()); mitk::BaseRenderer::AddInstance(GetVtkRenderWindow(), m_Renderer); renderingManager->AddRenderWindow(GetVtkRenderWindow()); // Add previously created overlays to new BaseRenderer mitk::AnnotationUtils::BaseRendererChanged(m_Renderer); m_RenderProp = vtkMitkRenderProp::New(); m_RenderProp->SetPropRenderer(m_Renderer); m_Renderer->GetVtkRenderer()->AddViewProp(m_RenderProp); if ((this->GetVtkRenderWindow()->GetSize()[0] > 10) && (this->GetVtkRenderWindow()->GetSize()[1] > 10)) m_Renderer->InitSize(this->GetVtkRenderWindow()->GetSize()[0], this->GetVtkRenderWindow()->GetSize()[1]); m_InResize = false; } bool mitk::RenderWindowBase::HandleEvent(InteractionEvent *interactionEvent) { return m_Renderer->GetDispatcher()->ProcessEvent(interactionEvent); } void mitk::RenderWindowBase::Destroy() { - m_Renderer->GetRenderingManager()->RemoveRenderWindow(GetVtkRenderWindow()); + RenderingManager::GetInstance()->RemoveRenderWindow(GetVtkRenderWindow()); m_Renderer->GetVtkRenderer()->RemoveViewProp(m_RenderProp); m_RenderProp->Delete(); BaseRenderer::RemoveInstance(this->GetVtkRenderWindow()); } mitk::RenderWindowBase::~RenderWindowBase() { } mitk::SliceNavigationController *mitk::RenderWindowBase::GetSliceNavigationController() { return mitk::BaseRenderer::GetInstance(this->GetVtkRenderWindow())->GetSliceNavigationController(); } mitk::CameraRotationController *mitk::RenderWindowBase::GetCameraRotationController() { return mitk::BaseRenderer::GetInstance(this->GetVtkRenderWindow())->GetCameraRotationController(); } mitk::BaseController *mitk::RenderWindowBase::GetController() { mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(GetVtkRenderWindow()); switch (renderer->GetMapperID()) { case mitk::BaseRenderer::Standard2D: return GetSliceNavigationController(); case mitk::BaseRenderer::Standard3D: return GetCameraRotationController(); default: return GetSliceNavigationController(); } } mitk::VtkPropRenderer *mitk::RenderWindowBase::GetRenderer() { return m_Renderer; } diff --git a/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp b/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp index 7abccd72a6..c24052db54 100644 --- a/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp @@ -1,715 +1,713 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkVtkPropRenderer.h" // MAPPERS #include "mitkCameraController.h" #include "mitkImageVtkMapper2D.h" #include "mitkMapper.h" #include "mitkPlaneGeometryDataVtkMapper3D.h" #include "mitkVtkMapper.h" #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -mitk::VtkPropRenderer::VtkPropRenderer(const char *name, - vtkRenderWindow *renWin, - RenderingManager *rm, - BaseRenderer::RenderingMode renderingMode) - : BaseRenderer(name, renWin, rm, renderingMode), m_CameraInitializedForMapperID(0) +mitk::VtkPropRenderer::VtkPropRenderer(const char *name, vtkRenderWindow *renWin) + : BaseRenderer(name, renWin), + m_CameraInitializedForMapperID(0) { didCount = false; m_WorldPointPicker = vtkWorldPointPicker::New(); m_PointPicker = vtkPointPicker::New(); m_PointPicker->SetTolerance(0.0025); m_CellPicker = vtkCellPicker::New(); m_CellPicker->SetTolerance(0.0025); mitk::PlaneGeometryDataVtkMapper3D::Pointer geometryMapper = mitk::PlaneGeometryDataVtkMapper3D::New(); m_CurrentWorldPlaneGeometryMapper = geometryMapper; m_CurrentWorldPlaneGeometryNode->SetMapper(2, geometryMapper); m_LightKit = vtkLightKit::New(); m_LightKit->AddLightsToRenderer(m_VtkRenderer); m_PickingMode = WorldPointPicking; m_TextRenderer = vtkRenderer::New(); m_TextRenderer->SetRenderWindow(renWin); m_TextRenderer->SetInteractive(0); m_TextRenderer->SetErase(0); } /*! \brief Destructs the VtkPropRenderer. */ mitk::VtkPropRenderer::~VtkPropRenderer() { // Workaround for GLDisplayList Bug { m_MapperID = 0; checkState(); } if (m_LightKit != nullptr) m_LightKit->Delete(); if (m_VtkRenderer != nullptr) { m_CameraController = nullptr; m_VtkRenderer->Delete(); m_VtkRenderer = nullptr; } else m_CameraController = nullptr; if (m_WorldPointPicker != nullptr) m_WorldPointPicker->Delete(); if (m_PointPicker != nullptr) m_PointPicker->Delete(); if (m_CellPicker != nullptr) m_CellPicker->Delete(); if (m_TextRenderer != nullptr) m_TextRenderer->Delete(); } void mitk::VtkPropRenderer::SetDataStorage(mitk::DataStorage *storage) { if (storage == nullptr || storage == m_DataStorage) return; BaseRenderer::SetDataStorage(storage); static_cast(m_CurrentWorldPlaneGeometryMapper.GetPointer()) ->SetDataStorageForTexture(m_DataStorage.GetPointer()); // Compute the geometry from the current data tree bounds and set it as world geometry this->SetWorldGeometryToDataStorageBounds(); } bool mitk::VtkPropRenderer::SetWorldGeometryToDataStorageBounds() { if (m_DataStorage.IsNull()) return false; // initialize world geometry auto geometry = m_DataStorage->ComputeVisibleBoundingGeometry3D(nullptr, "includeInBoundingBox"); if (geometry.IsNull()) return false; this->SetWorldTimeGeometry(geometry); this->GetVtkRenderer()->ResetCamera(); this->GetCameraController()->Fit(); this->Modified(); return true; } /*! \brief Called by the vtkMitkRenderProp in order to start MITK rendering process. */ int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type) { // Do we have objects to render? if (this->GetEmptyWorldGeometry()) return 0; if (m_DataStorage.IsNull()) return 0; // Update mappers and prepare mapper queue if (type == VtkPropRenderer::Opaque) { this->PrepareMapperQueue(); // Share vtkInformation, there might be new mappers this->PropagateRenderInfoToMappers(); } // go through the generated list and let the sorted mappers paint for (auto it = m_MappersMap.cbegin(); it != m_MappersMap.cend(); it++) { Mapper *mapper = (*it).second; mapper->MitkRender(this, type); } // Render text if (type == VtkPropRenderer::Overlay) { if (m_TextCollection.size() > 0) { m_TextRenderer->SetViewport(this->GetVtkRenderer()->GetViewport()); for (auto it = m_TextCollection.begin(); it != m_TextCollection.end(); ++it) m_TextRenderer->AddViewProp((*it).second); m_TextRenderer->Render(); } } return 1; } /*! \brief PrepareMapperQueue iterates the datatree PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer. */ void mitk::VtkPropRenderer::PrepareMapperQueue() { // variable for counting LOD-enabled mappers m_NumberOfVisibleLODEnabledMappers = 0; // Do we have to update the mappers ? if (m_LastUpdateTime < GetMTime() || m_LastUpdateTime < this->GetCurrentWorldPlaneGeometry()->GetMTime()) { Update(); } else if (m_MapperID >= 1 && m_MapperID < 6) Update(); // remove all text properties before mappers will add new ones m_TextRenderer->RemoveAllViewProps(); for (unsigned int i = 0; i < m_TextCollection.size(); i++) { m_TextCollection[i]->Delete(); } m_TextCollection.clear(); // clear priority_queue m_MappersMap.clear(); int mapperNo = 0; // DataStorage if (m_DataStorage.IsNull()) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { const DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; const mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID); if (mapper.IsNull()) continue; bool visible = true; node->GetVisibility(visible, this, "visible"); // The information about LOD-enabled mappers is required by RenderingManager if (mapper->IsLODEnabled(this) && visible) { ++m_NumberOfVisibleLODEnabledMappers; } // mapper without a layer property get layer number 1 int layer = 1; node->GetIntProperty("layer", layer, this); int nr = (layer << 16) + mapperNo; m_MappersMap.insert(std::pair(nr, mapper)); mapperNo++; } } void mitk::VtkPropRenderer::SetPropertyKeys(vtkInformation *info) { if (info == m_VtkRenderInfo) return; m_VtkRenderInfo = info; this->PropagateRenderInfoToMappers(); } void mitk::VtkPropRenderer::PropagateRenderInfoToMappers() { if (m_VtkRenderInfo == nullptr) return; for (const auto &mapEntry : m_MappersMap) { auto vtkMapper = dynamic_cast(mapEntry.second); if (nullptr != vtkMapper) { auto prop = vtkMapper->GetVtkProp(this); if (nullptr != prop) prop->SetPropertyKeys(m_VtkRenderInfo); } } } void mitk::VtkPropRenderer::Update(mitk::DataNode *datatreenode) { if (datatreenode != nullptr) { mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID); if (mapper.IsNotNull()) { if (GetCurrentWorldPlaneGeometry()->IsValid()) { mapper->Update(this); { auto *vtkmapper = dynamic_cast(mapper.GetPointer()); if (vtkmapper != nullptr) { vtkmapper->UpdateVtkTransform(this); } } } } } } void mitk::VtkPropRenderer::Update() { if (m_DataStorage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) Update(it->Value()); Modified(); m_LastUpdateTime = GetMTime(); } /*! \brief This method is called from the two Constructors */ void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow *renderWindow) { BaseRenderer::InitRenderer(renderWindow); vtkCallbackCommand *renderCallbackCommand = vtkCallbackCommand::New(); renderCallbackCommand->SetCallback(VtkPropRenderer::RenderingCallback); renderWindow->GetInteractor()->AddObserver(vtkCommand::RenderEvent, renderCallbackCommand); renderCallbackCommand->Delete(); if (renderWindow == nullptr) { m_InitNeeded = false; m_ResizeNeeded = false; return; } m_InitNeeded = true; m_ResizeNeeded = true; m_LastUpdateTime = 0; } void mitk::VtkPropRenderer::RenderingCallback(vtkObject *caller, unsigned long, void *, void *) { auto *renderWindowInteractor = dynamic_cast(caller); if (!renderWindowInteractor) return; mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowInteractor->GetRenderWindow()); if (renderer) renderer->RequestUpdate(); } /*! \brief Resize the OpenGL Window */ void mitk::VtkPropRenderer::Resize(int w, int h) { BaseRenderer::Resize(w, h); - m_RenderingManager->RequestUpdate(this->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(this->GetRenderWindow()); } void mitk::VtkPropRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w, h); Superclass::InitSize(w, h); Modified(); Update(); if (m_VtkRenderer != nullptr) { int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); m_VtkRenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } this->GetCameraController()->Fit(); } int mitk::VtkPropRenderer::WriteSimpleText( std::string text, double posX, double posY, double color1, double color2, double color3, float opacity) { this->GetVtkRenderer()->ViewToDisplay(); if (!text.empty()) { Point2D p; vtkTextActor *textActor = vtkTextActor::New(); textActor->SetDisplayPosition(posX, posY); textActor->SetInput(text.c_str()); textActor->SetTextScaleModeToNone(); textActor->GetTextProperty()->SetColor(color1, color2, color3); // TODO: Read color from node property textActor->GetTextProperty()->SetOpacity(opacity); int text_id = m_TextCollection.size(); m_TextCollection.insert(TextMapType::value_type(text_id, textActor)); return text_id; } else { return -1; } } void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId) { if (m_MapperID != mapperId) Superclass::SetMapperID(mapperId); // Workaround for GL Displaylist Bug checkState(); } /*! \brief Activates the current renderwindow. */ void mitk::VtkPropRenderer::MakeCurrent() { if (m_RenderWindow != nullptr) m_RenderWindow->MakeCurrent(); } void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D &displayPoint, mitk::Point3D &worldPoint) const { if (this->GetRenderWindow()->GetNeverRendered() != 0) return; // somebody called picking before we ever rendered; cannot have enough information yet switch (m_PickingMode) { case (WorldPointPicking): { m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint); break; } case (PointPicking): { m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_PointPicker->GetPickPosition(), worldPoint); break; } case (CellPicking): { m_CellPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_CellPicker->GetPickPosition(), worldPoint); break; } } // todo: is this picking in 2D renderwindows? // Superclass::PickWorldPoint(displayPoint, worldPoint); } mitk::DataNode *mitk::VtkPropRenderer::PickObject(const Point2D &displayPosition, Point3D &worldPosition) const { m_CellPicker->InitializePickList(); // Iterate over all DataStorage objects to determine all vtkProps intended // for picking DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { const DataNode *node = it->Value(); if (node == nullptr) continue; bool pickable = false; node->GetBoolProperty("pickable", pickable); if (!pickable) continue; auto *mapper = dynamic_cast(node->GetMapper(m_MapperID)); if (mapper == nullptr) continue; vtkProp *prop = mapper->GetVtkProp((mitk::BaseRenderer *)this); if (prop == nullptr) continue; m_CellPicker->AddPickList(prop); } // Do the picking and retrieve the picked vtkProp (if any) m_CellPicker->PickFromListOn(); m_CellPicker->Pick(displayPosition[0], displayPosition[1], 0.0, m_VtkRenderer); m_CellPicker->PickFromListOff(); vtk2itk(m_CellPicker->GetPickPosition(), worldPosition); vtkProp *prop = m_CellPicker->GetViewProp(); if (prop == nullptr) { return nullptr; } // Iterate over all DataStorage objects to determine if the retrieved // vtkProp is owned by any associated mapper. for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; mitk::Mapper *mapper = node->GetMapper(m_MapperID); if (mapper == nullptr) continue; auto *vtkmapper = dynamic_cast(mapper); if (vtkmapper) { // if vtk-based, then ... if (vtkmapper->HasVtkProp(prop, const_cast(this))) { return node; } } } return nullptr; } // todo: is this 2D renderwindow picking? // return Superclass::PickObject( displayPosition, worldPosition ); vtkTextProperty *mitk::VtkPropRenderer::GetTextLabelProperty(int text_id) { return this->m_TextCollection[text_id]->GetTextProperty(); } void mitk::VtkPropRenderer::InitPathTraversal() { if (m_DataStorage.IsNotNull()) { this->UpdatePaths(); this->m_Paths->InitTraversal(); } } void mitk::VtkPropRenderer::UpdatePaths() { if (m_DataStorage.IsNull()) { return; } if (GetMTime() > m_PathTime || (m_Paths != nullptr && m_Paths->GetMTime() > m_PathTime)) { // Create the list to hold all the paths m_Paths = vtkSmartPointer::New(); DataStorage::SetOfObjects::ConstPointer objects = m_DataStorage->GetAll(); for (auto iter = objects->begin(); iter != objects->end(); ++iter) { vtkSmartPointer onePath = vtkSmartPointer::New(); Mapper *mapper = (*iter)->GetMapper(BaseRenderer::Standard3D); if (mapper) { auto *vtkmapper = dynamic_cast(mapper); if (nullptr != vtkmapper) { vtkProp *prop = vtkmapper->GetVtkProp(this); if (prop && prop->GetVisibility()) { // add to assembly path onePath->AddNode(prop, prop->GetMatrix()); m_Paths->AddItem(onePath); } } } } m_PathTime.Modified(); } } int mitk::VtkPropRenderer::GetNumberOfPaths() { UpdatePaths(); return m_Paths->GetNumberOfItems(); } vtkAssemblyPath *mitk::VtkPropRenderer::GetNextPath() { return m_Paths ? m_Paths->GetNextItem() : nullptr; } void mitk::VtkPropRenderer::ReleaseGraphicsResources(vtkWindow * /*renWin*/) { if (m_DataStorage.IsNull()) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (auto iter = allObjects->begin(); iter != allObjects->end(); ++iter) { DataNode::Pointer node = *iter; if (node.IsNull()) continue; Mapper *mapper = node->GetMapper(m_MapperID); if (mapper) { auto *vtkmapper = dynamic_cast(mapper); if (vtkmapper) vtkmapper->ReleaseGraphicsResources(this); } } } const vtkWorldPointPicker *mitk::VtkPropRenderer::GetWorldPointPicker() const { return m_WorldPointPicker; } const vtkPointPicker *mitk::VtkPropRenderer::GetPointPicker() const { return m_PointPicker; } const vtkCellPicker *mitk::VtkPropRenderer::GetCellPicker() const { return m_CellPicker; } mitk::VtkPropRenderer::MappersMapType mitk::VtkPropRenderer::GetMappersMap() const { return m_MappersMap; } // Workaround for GL Displaylist bug static int glWorkAroundGlobalCount = 0; bool mitk::VtkPropRenderer::useImmediateModeRendering() { return glWorkAroundGlobalCount > 1; } void mitk::VtkPropRenderer::checkState() { if (m_MapperID == Standard3D) { if (!didCount) { didCount = true; glWorkAroundGlobalCount++; if (glWorkAroundGlobalCount == 2) { MITK_INFO << "Multiple 3D Renderwindows active...: turning Immediate Rendering ON for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOn(); } } } else { if (didCount) { didCount = false; glWorkAroundGlobalCount--; if (glWorkAroundGlobalCount == 1) { MITK_INFO << "Single 3D Renderwindow active...: turning Immediate Rendering OFF for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOff(); } } } } //### Contains all methods which are neceassry before each VTK Render() call void mitk::VtkPropRenderer::PrepareRender() { if (this->GetMapperID() != m_CameraInitializedForMapperID) { Initialize2DvtkCamera(); // Set parallel projection etc. } GetCameraController()->AdjustCameraToPlane(); } bool mitk::VtkPropRenderer::Initialize2DvtkCamera() { if (this->GetMapperID() == Standard3D) { // activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(false); vtkSmartPointer style = vtkSmartPointer::New(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); this->GetRenderWindow()->GetInteractor()->EnableRenderOff(); m_CameraInitializedForMapperID = Standard3D; } else if (this->GetMapperID() == Standard2D) { // activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); // turn the light out in the scene in order to render correct grey values. // TODO Implement a property for light in the 2D render windows (in another method) this->GetVtkRenderer()->RemoveAllLights(); vtkSmartPointer style = vtkSmartPointer::New(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); this->GetRenderWindow()->GetInteractor()->EnableRenderOff(); m_CameraInitializedForMapperID = Standard2D; } return true; } diff --git a/Modules/Core/test/mitkDataNodeTest.cpp b/Modules/Core/test/mitkDataNodeTest.cpp index 9a672c2eb7..ecd27ae641 100644 --- a/Modules/Core/test/mitkDataNodeTest.cpp +++ b/Modules/Core/test/mitkDataNodeTest.cpp @@ -1,334 +1,334 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkDataNode.h" #include "mitkVtkPropRenderer.h" #include #include "mitkTestingMacros.h" #include // Basedata Test #include #include #include #include #include // Mapper Test #include #include #include #include #include #include #include // Interactors #include // Property list Test #include /** * Simple example for a test for the (non-existent) class "DataNode". * * argc and argv are the command line parameters which were passed to * the ADD_TEST command in the CMakeLists.txt file. For the automatic * tests, argv is either empty for the simple tests or contains the filename * of a test image for the image tests (see CMakeLists.txt). */ class mitkDataNodeTestClass { public: static void TestDataSetting(mitk::DataNode::Pointer dataNode) { mitk::BaseData::Pointer baseData; // nullptr pointer Test dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a nullptr pointer was set correctly") baseData = mitk::GeometryData::New(); dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a GeometryData object was set correctly") baseData = mitk::PlaneGeometryData::New(); dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a PlaneGeometryData object was set correctly") baseData = mitk::PointSet::New(); dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a PointSet object was set correctly") baseData = mitk::Image::New(); dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a Image object was set correctly") baseData = mitk::Surface::New(); dataNode->SetData(baseData); MITK_TEST_CONDITION(baseData == dataNode->GetData(), "Testing if a Surface object was set correctly") dataNode->SetData(nullptr); MITK_TEST_CONDITION(nullptr == dataNode->GetData(), "Testing if base data (already set) was replaced by a nullptr pointer") } static void TestMapperSetting(mitk::DataNode::Pointer dataNode) { // tests the SetMapper() method // in dataNode is a mapper vector which can be accessed by index // in this test method we use only slot 0 (filled with null) and slot 1 // so we also test the destructor of the mapper classes mitk::Mapper::Pointer mapper; dataNode->SetMapper(0, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(0), "Testing if a nullptr pointer was set correctly") mapper = mitk::PlaneGeometryDataMapper2D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a PlaneGeometryDataMapper2D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::ImageVtkMapper2D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a ImageVtkMapper2D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::PointSetVtkMapper2D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a PointSetVtkMapper2D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::SurfaceVtkMapper2D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a SurfaceGLMapper2D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::PlaneGeometryDataVtkMapper3D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a PlaneGeometryDataVtkMapper3D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::PointSetVtkMapper3D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a PointSetVtkMapper3D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") mapper = mitk::SurfaceVtkMapper3D::New(); dataNode->SetMapper(1, mapper); MITK_TEST_CONDITION(mapper == dataNode->GetMapper(1), "Testing if a SurfaceVtkMapper3D was set correctly") MITK_TEST_CONDITION(dataNode == mapper->GetDataNode(), "Testing if the mapper returns the right DataNode") } static void TestInteractorSetting(mitk::DataNode::Pointer dataNode) { // this method tests the SetInteractor() and GetInteractor methods // the DataInteractor base class calls the DataNode->SetInteractor method mitk::DataInteractor::Pointer interactor; MITK_TEST_CONDITION(interactor == dataNode->GetDataInteractor(), "Testing if a nullptr pointer was set correctly (DataInteractor)") interactor = mitk::PointSetDataInteractor::New(); interactor->SetEventConfig("PointSetConfig.xml"); interactor->SetDataNode(dataNode); MITK_TEST_CONDITION(interactor == dataNode->GetDataInteractor(), "Testing if a PointSetDataInteractor was set correctly") interactor = mitk::PointSetDataInteractor::New(); dataNode->SetDataInteractor(interactor); MITK_TEST_CONDITION(interactor == dataNode->GetDataInteractor(), "Testing if a PointSetDataInteractor was set correctly") } static void TestPropertyList(mitk::DataNode::Pointer dataNode) { mitk::PropertyList::Pointer propertyList = dataNode->GetPropertyList(); MITK_TEST_CONDITION(dataNode->GetPropertyList() != nullptr, "Testing if the constructor set the propertylist") dataNode->SetIntProperty("int", -31337); int x; dataNode->GetIntProperty("int", x); MITK_TEST_CONDITION(x == -31337, "Testing Set/GetIntProperty"); dataNode->SetBoolProperty("bool", true); bool b; dataNode->GetBoolProperty("bool", b); MITK_TEST_CONDITION(b == true, "Testing Set/GetBoolProperty"); dataNode->SetFloatProperty("float", -31.337); float y; dataNode->GetFloatProperty("float", y); MITK_TEST_CONDITION(y - -31.337 < 0.01, "Testing Set/GetFloatProperty"); double yd = 0; dataNode->GetDoubleProperty("float", yd); MITK_TEST_CONDITION(mitk::Equal(yd, static_cast(y)), "Testing GetDoubleProperty"); double d = sqrt(2.0); dataNode->SetDoubleProperty("double", d); double read_d; MITK_TEST_CONDITION(dataNode->GetDoubleProperty("double", read_d), "Testing GetDoubleProperty"); MITK_TEST_CONDITION(d == read_d, "Testing Set/GetDoubleProperty"); // Equal does not the same thing dataNode->SetStringProperty("string", "MITK"); std::string s = "GANZVIELPLATZ"; dataNode->GetStringProperty("string", s); MITK_TEST_CONDITION(s == "MITK", "Testing Set/GetStringProperty"); std::string name = "MyTestName"; dataNode->SetName(name.c_str()); MITK_TEST_CONDITION(dataNode->GetName() == name, "Testing Set/GetName"); name = "MySecondTestName"; dataNode->SetName(name); MITK_TEST_CONDITION(dataNode->GetName() == name, "Testing Set/GetName(std::string)"); MITK_TEST_CONDITION(propertyList == dataNode->GetPropertyList(), "Testing if the propertylist has changed during the last tests") } static void TestDataPropertiesFallback(mitk::DataNode::Pointer dataNode) { const std::string name = "Catch Me If You Can"; auto image = mitk::Image::New(); image->SetProperty(name, mitk::StringProperty::New("Don't tase me, bro!")); dataNode->SetData(image); auto property = dataNode->GetProperty(name.c_str()); MITK_TEST_CONDITION(nullptr != property, "Testing GetProperty data property fallback (new behavior)"); property = dataNode->GetProperty(name.c_str(), nullptr, false); MITK_TEST_CONDITION(nullptr == property, "Testing GetProperty data property fallback (old behavior)"); } static void TestSelected(mitk::DataNode::Pointer dataNode) { vtkRenderWindow *renderWindow = vtkRenderWindow::New(); mitk::VtkPropRenderer::Pointer base = - mitk::VtkPropRenderer::New("the first renderer", renderWindow, mitk::RenderingManager::GetInstance()); + mitk::VtkPropRenderer::New("the first renderer", renderWindow); // with BaseRenderer==Null MITK_TEST_CONDITION(!dataNode->IsSelected(), "Testing if this node is not set as selected") dataNode->SetSelected(true); MITK_TEST_CONDITION(dataNode->IsSelected(), "Testing if this node is set as selected") dataNode->SetSelected(false); dataNode->SetSelected(true, base); MITK_TEST_CONDITION(dataNode->IsSelected(base), "Testing if this node with right base renderer is set as selected") // Delete RenderWindow correctly renderWindow->Delete(); } static void TestGetMTime(mitk::DataNode::Pointer dataNode) { unsigned long time; time = dataNode->GetMTime(); mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); dataNode->SetData(pointSet); MITK_TEST_CONDITION(time != dataNode->GetMTime(), "Testing if the node timestamp is updated after adding data to the node") mitk::Point3D point; point.Fill(3.0); pointSet->SetPoint(0, point); // less or equal because dataNode timestamp is little later then the basedata timestamp MITK_TEST_CONDITION(pointSet->GetMTime() <= dataNode->GetMTime(), "Testing if the node timestamp is updated after base data was modified") // testing if changing anything in the property list also sets the node in a modified state unsigned long lastModified = dataNode->GetMTime(); dataNode->SetIntProperty("testIntProp", 2344); MITK_TEST_CONDITION(lastModified <= dataNode->GetMTime(), "Testing if the node timestamp is updated after property list was modified") } static void TestSetDataUnderPropertyChange(void) { mitk::Image::Pointer image = mitk::Image::New(); mitk::Image::Pointer additionalImage = mitk::Image::New(); mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); image = mitk::ImageGenerator::GenerateRandomImage(3u, 3u); dataNode->SetData(image); const float defaultOutlineWidth = 1.0; float outlineWidth = 0; dataNode->GetPropertyValue("outline width", outlineWidth); MITK_TEST_CONDITION(mitk::Equal(outlineWidth, defaultOutlineWidth), "Testing if the SetData set the default property list") dataNode->SetProperty("outline width", mitk::FloatProperty::New(42.0)); dataNode->SetData(image); dataNode->GetPropertyValue("outline width", outlineWidth); MITK_TEST_CONDITION(mitk::Equal(outlineWidth, 42.0), "Testing if the SetData does not set anything if image data is identical") dataNode->SetData(additionalImage); dataNode->GetPropertyValue("outline width", outlineWidth); MITK_TEST_CONDITION(mitk::Equal(outlineWidth, 42.0), "Testing if the SetData does not set the default property list if image data is already set") mitk::Surface::Pointer surface = mitk::Surface::New(); dataNode->SetData(surface); MITK_TEST_CONDITION(dataNode->GetPropertyValue("outline width", outlineWidth) == false, "Testing if SetData cleared previous property list and set the default property list if data " "of different type has been set") } }; // mitkDataNodeTestClass int mitkDataNodeTest(int /* argc */, char * /*argv*/ []) { // always start with this! MITK_TEST_BEGIN("DataNode") // let's create an object of our class mitk::DataNode::Pointer myDataNode = mitk::DataNode::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myDataNode.IsNotNull(), "Testing instantiation") // test setData() Method mitkDataNodeTestClass::TestDataSetting(myDataNode); mitkDataNodeTestClass::TestMapperSetting(myDataNode); // // note, that no data is set to the dataNode mitkDataNodeTestClass::TestInteractorSetting(myDataNode); mitkDataNodeTestClass::TestPropertyList(myDataNode); mitkDataNodeTestClass::TestDataPropertiesFallback(myDataNode); mitkDataNodeTestClass::TestSelected(myDataNode); mitkDataNodeTestClass::TestGetMTime(myDataNode); mitkDataNodeTestClass::TestSetDataUnderPropertyChange(); // write your own tests here and use the macros from mitkTestingMacros.h !!! // do not write to std::cout and do not return from this function yourself! // always end with this! MITK_TEST_END() } diff --git a/Modules/Core/test/mitkDispatcherTest.cpp b/Modules/Core/test/mitkDispatcherTest.cpp index f0a04bccbd..8b5e84935b 100644 --- a/Modules/Core/test/mitkDispatcherTest.cpp +++ b/Modules/Core/test/mitkDispatcherTest.cpp @@ -1,123 +1,123 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkLightObject.h" #include "mitkBaseRenderer.h" #include "mitkDataInteractor.h" #include "mitkDataNode.h" #include "mitkDispatcher.h" #include "mitkStandaloneDataStorage.h" #include "mitkTestingMacros.h" #include "mitkVtkPropRenderer.h" int mitkDispatcherTest(int /*argc*/, char * /*argv*/ []) { MITK_TEST_BEGIN("Dispatcher") /* * Tests the process of creating Interactors and assigning DataNodes to them. * Test checks if these Interactors are added to the Dispatcher under different conditions, * and in different call order. */ // Here BindDispatcherInteractor and Dispatcher should be created automatically vtkRenderWindow *renWin = vtkRenderWindow::New(); mitk::VtkPropRenderer::Pointer renderer = - mitk::VtkPropRenderer::New("ContourRenderer", renWin, mitk::RenderingManager::GetInstance()); + mitk::VtkPropRenderer::New("ContourRenderer", renWin); mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); mitk::DataNode::Pointer dn; dn = mitk::DataNode::New(); mitk::DataNode::Pointer dn2 = mitk::DataNode::New(); mitk::DataInteractor::Pointer ei = mitk::DataInteractor::New(); mitk::DataInteractor::Pointer ei2 = mitk::DataInteractor::New(); MITK_TEST_CONDITION_REQUIRED(renderer->GetDispatcher()->GetNumberOfInteractors() == 0, "01 Check Existence of Dispatcher."); ei->SetDataNode(dn); renderer->SetDataStorage(ds); ds->Add(dn); int num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 1, "02 Number of registered Interactors " << num << " , expected 1"); // This _must not_ result in additionally registered interactors. ei->SetDataNode(dn); ei->SetDataNode(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 1, "03 Number of registered Interactors " << num << " , expected 1"); // Switching the DataNode of an Interactor also must not result in extra registered Interactors in Dispatcher // since dn2 is not connected to DataStorage // ei will be dropped from dispatcher ei->SetDataNode(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 0, "04 Number of registered Interactors " << num << " , expected 0"); // DataNode Added to DataStorage, now Interactor entry in Dispatcher should be replaced, // hence we restore Interactor in the Dispatcher ds->Add(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 1, "05 Number of registered Interactors " << num << " , expected 1"); // New DataNode and new interactor, this should result in additional Interactor in the Dispatcher. ei2->SetDataNode(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 2, "06 Number of registered Interactors " << num << " , expected 2"); // Here ei and ei2 point to the same dn2; dn2 now only points to ei2, so ei is abandoned, // therefore ei1 is expected to be removed ei2->SetDataNode(dn2); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 1, "07 Number of registered Interactors " << num << " , expected 1"); // Setting DataNode in Interactor to nullptr, should remove Interactor from Dispatcher ei2->SetDataNode(nullptr); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 0, "08 Number of registered Interactors " << num << " , expected 0"); // Add DN again check if it is registered ei2->SetDataNode(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 1, "09 Number of registered Interactors " << num << " , expected 1"); // If DN is removed Interactors should be too ds->Remove(dn); num = renderer->GetDispatcher()->GetNumberOfInteractors(); MITK_TEST_CONDITION_REQUIRED(num == 0, "10 Number of registered Interactors " << num << " , expected 0"); // after DN is removed from DS its reference count must be back to one MITK_TEST_CONDITION_REQUIRED(dn->GetReferenceCount() == 1, "10 Number of references of DataNode " << num << " , expected 1"); MITK_TEST_CONDITION_REQUIRED(ei->GetReferenceCount() == 1, "11 Number of references of Interactors " << num << " , expected 1"); renWin->Delete(); // always end with this! MITK_TEST_END() } diff --git a/Modules/Core/test/mitkRenderingManagerTest.cpp b/Modules/Core/test/mitkRenderingManagerTest.cpp index b581280440..d2cbd2a586 100644 --- a/Modules/Core/test/mitkRenderingManagerTest.cpp +++ b/Modules/Core/test/mitkRenderingManagerTest.cpp @@ -1,216 +1,216 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkProperties.h" #include "mitkRenderingManager.h" #include "mitkStandaloneDataStorage.h" #include "mitkVtkPropRenderer.h" #include "vtkRenderWindow.h" #include "mitkTestingMacros.h" #include "mitkSurface.h" #include // Propertylist Test /** * Simple example for a test for the class "RenderingManager". * * argc and argv are the command line parameters which were passed to * the ADD_TEST command in the CMakeLists.txt file. For the automatic * tests, argv is either empty for the simple tests or contains the filename * of a test image for the image tests (see CMakeLists.txt). */ class mitkRenderingManagerTestClass { public: static void TestPropertyList(mitk::RenderingManager::Pointer renderingManager) { mitk::PropertyList::Pointer propertyList = renderingManager->GetPropertyList(); MITK_TEST_CONDITION(renderingManager->GetPropertyList().IsNotNull(), "Testing if the constructor set the propertylist") // check if the default properties are set renderingManager->SetProperty("booltest", mitk::BoolProperty::New(true)); auto *prop = dynamic_cast(renderingManager->GetProperty("booltest")); MITK_TEST_CONDITION(prop->GetValue(), "Testing if getting the bool property") MITK_TEST_CONDITION(propertyList == renderingManager->GetPropertyList(), "Testing if the propertylist has changed during the last tests") } static void TestSurfaceLoading(mitk::RenderingManager::Pointer renderingManager) { // create and render two dimensional surface vtkCubeSource *plane = vtkCubeSource::New(); double planeBounds[] = {-1.0, 1.0, -1.0, 1.0, 0.0, 0.0}; double cubeBounds[] = {-0.5, 0.5, -0.5, 0.5, -0.5, 0.5}; plane->SetBounds(planeBounds); plane->SetCenter(0.0, 0.0, 0.0); vtkPolyData *polys = plane->GetOutput(); mitk::Surface::Pointer mitkPlane = mitk::Surface::New(); mitkPlane->SetVtkPolyData(polys); plane->Delete(); mitk::DataNode::Pointer planeNode = mitk::DataNode::New(); planeNode->SetData(mitkPlane); renderingManager->GetDataStorage()->Add(planeNode); mitk::Geometry3D::Pointer planeGeometry = mitk::Geometry3D::New(); planeGeometry->SetFloatBounds(planeBounds); MITK_TEST_CONDITION(renderingManager->InitializeViews(planeGeometry), "Testing if two dimensional Geometry3Ds can be displayed") // clear rendering renderingManager->GetDataStorage()->Remove(planeNode); renderingManager->InitializeViews(); // create and render three dimensional surface vtkCubeSource *cube = vtkCubeSource::New(); cube->SetBounds(cubeBounds); cube->SetCenter(0.0, 0.0, 0.0); vtkPolyData *polyCube = cube->GetOutput(); mitk::Surface::Pointer mitkCube = mitk::Surface::New(); mitkCube->SetVtkPolyData(polyCube); cube->Delete(); mitk::DataNode::Pointer cubeNode = mitk::DataNode::New(); cubeNode->SetData(mitkCube); renderingManager->GetDataStorage()->Add(cubeNode); mitk::Geometry3D::Pointer cubeGeometry = mitk::Geometry3D::New(); cubeGeometry->SetFloatBounds(cubeBounds); MITK_TEST_CONDITION(renderingManager->InitializeViews(cubeGeometry), "Testing if three dimensional Geometry3Ds can be displayed") // clear rendering renderingManager->GetDataStorage()->Remove(cubeNode); renderingManager->InitializeViews(); } static void TestAddRemoveRenderWindow() { mitk::RenderingManager::Pointer myRenderingManager = mitk::RenderingManager::New(); // mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); // myRenderingManager->SetDataStorage(ds); { vtkRenderWindow *vtkRenWin = vtkRenderWindow::New(); MITK_TEST_CONDITION_REQUIRED(myRenderingManager->GetAllRegisteredRenderWindows().size() == 0, "Render window list must be empty") // Add Render Window myRenderingManager->AddRenderWindow(vtkRenWin); MITK_TEST_CONDITION_REQUIRED(myRenderingManager->GetAllRegisteredRenderWindows().size() == 1, "Render window list must contain one item") // Remove Render Window myRenderingManager->RemoveRenderWindow(vtkRenWin); MITK_TEST_CONDITION_REQUIRED(myRenderingManager->GetAllRegisteredRenderWindows().size() == 0, "Render window list must be empty") // Test if the Render Window was removed properly. This should not do anything MITK_TEST_OUTPUT(<< "Call RequestUpdate on removed render window") myRenderingManager->RequestUpdate(vtkRenWin); MITK_TEST_OUTPUT(<< "Call ForceImmediateUpdate on removed render window") myRenderingManager->ForceImmediateUpdate(vtkRenWin); MITK_TEST_CONDITION_REQUIRED(myRenderingManager->GetAllRegisteredRenderWindows().size() == 0, "Render window list must be empty") // Delete vtk variable correctly vtkRenWin->Delete(); } // Check that the previous calls to RequestUpdate and ForceImmediateUpdate // did not modify the internal vtkRenderWindow list. This should not crash. MITK_TEST_OUTPUT(<< "Call RequestUpdateAll after deleting render window") myRenderingManager->RequestUpdateAll(); MITK_TEST_OUTPUT(<< "Call ForceImmediateUpdateAll after deleting render window") myRenderingManager->ForceImmediateUpdateAll(); } }; // mitkDataNodeTestClass int mitkRenderingManagerTest(int /* argc */, char * /*argv*/ []) { // always start with this! MITK_TEST_BEGIN("RenderingManager") mitkRenderingManagerTestClass::TestAddRemoveRenderWindow(); mitk::RenderingManager::Pointer globalRenderingManager = mitk::RenderingManager::GetInstance(); MITK_TEST_CONDITION_REQUIRED(globalRenderingManager.IsNotNull(), "Testing instantiation of global static instance") mitk::RenderingManager::Pointer myRenderingManager = mitk::RenderingManager::New(); MITK_TEST_CONDITION_REQUIRED(myRenderingManager.IsNotNull(), "Testing instantiation of second 'local' instance") MITK_TEST_CONDITION_REQUIRED(myRenderingManager != globalRenderingManager, "Testing whether global instance equals new local instance (must not be!)") mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); mitk::StandaloneDataStorage::Pointer ds2 = mitk::StandaloneDataStorage::New(); myRenderingManager->SetDataStorage(ds); vtkRenderWindow *vtkRenWin = vtkRenderWindow::New(); - mitk::VtkPropRenderer::Pointer br = mitk::VtkPropRenderer::New("testingBR", vtkRenWin, myRenderingManager); + mitk::VtkPropRenderer::Pointer br = mitk::VtkPropRenderer::New("testingBR", vtkRenWin); mitk::BaseRenderer::AddInstance(vtkRenWin, br); myRenderingManager->AddRenderWindow(vtkRenWin); MITK_TEST_CONDITION_REQUIRED(br->GetDataStorage() == ds, "Testing if internal DataStorage has been set correctly for registered BaseRenderer") myRenderingManager->SetDataStorage(ds2); MITK_TEST_CONDITION_REQUIRED( br->GetDataStorage() == ds2, "Testing if change of internal DataStorage has been forwarded correctly to registered BaseRenderer") mitkRenderingManagerTestClass::TestPropertyList(myRenderingManager); mitkRenderingManagerTestClass::TestSurfaceLoading(myRenderingManager); // write your own tests here and use the macros from mitkTestingMacros.h !!! // do not write to std::cout and do not return from this function yourself! // Remove Render Window myRenderingManager->RemoveRenderWindow(vtkRenWin); // Delete vtk variable correctly vtkRenWin->Delete(); // always end with this! MITK_TEST_END() } diff --git a/Modules/DataTypesExt/src/mitkAffineBaseDataInteractor3D.cpp b/Modules/DataTypesExt/src/mitkAffineBaseDataInteractor3D.cpp index 8de28a66de..4a6354d9bd 100644 --- a/Modules/DataTypesExt/src/mitkAffineBaseDataInteractor3D.cpp +++ b/Modules/DataTypesExt/src/mitkAffineBaseDataInteractor3D.cpp @@ -1,508 +1,508 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkAffineBaseDataInteractor3D.h" #include #include #include #include #include #include #include #include #include #include #include #include // Properties to allow the user to interact with the base data const char *translationStepSizePropertyName = "AffineBaseDataInteractor3D.Translation Step Size"; const char *selectedColorPropertyName = "AffineBaseDataInteractor3D.Selected Color"; const char *deselectedColorPropertyName = "AffineBaseDataInteractor3D.Deselected Color"; const char *priorPropertyName = "AffineBaseDataInteractor3D.Prior Color"; const char *rotationStepSizePropertyName = "AffineBaseDataInteractor3D.Rotation Step Size"; const char *scaleStepSizePropertyName = "AffineBaseDataInteractor3D.Scale Step Size"; const char *anchorPointX = "AffineBaseDataInteractor3D.Anchor Point X"; const char *anchorPointY = "AffineBaseDataInteractor3D.Anchor Point Y"; const char *anchorPointZ = "AffineBaseDataInteractor3D.Anchor Point Z"; mitk::AffineBaseDataInteractor3D::AffineBaseDataInteractor3D() { m_OriginalGeometry = mitk::Geometry3D::New(); } mitk::AffineBaseDataInteractor3D::~AffineBaseDataInteractor3D() { this->RestoreNodeProperties(); } void mitk::AffineBaseDataInteractor3D::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually // executing an action CONNECT_CONDITION("isOverObject", CheckOverObject); // **Function** in the statmachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectObject", SelectObject); CONNECT_FUNCTION("deselectObject", DeselectObject); CONNECT_FUNCTION("initTranslate", InitTranslate); CONNECT_FUNCTION("initRotate", InitRotate); CONNECT_FUNCTION("translateObject", TranslateObject); CONNECT_FUNCTION("rotateObject", RotateObject); CONNECT_FUNCTION("scaleObject", ScaleObject); CONNECT_FUNCTION("translateUpKey", TranslateUpKey); CONNECT_FUNCTION("translateDownKey", TranslateDownKey); CONNECT_FUNCTION("translateLeftKey", TranslateLeftKey); CONNECT_FUNCTION("translateRightKey", TranslateRightKey); CONNECT_FUNCTION("translateUpModifierKey", TranslateUpModifierKey); CONNECT_FUNCTION("translateDownModifierKey", TranslateDownModifierKey); CONNECT_FUNCTION("scaleDownKey", ScaleDownKey); CONNECT_FUNCTION("scaleUpKey", ScaleUpKey); CONNECT_FUNCTION("rotateUpKey", RotateUpKey); CONNECT_FUNCTION("rotateDownKey", RotateDownKey); CONNECT_FUNCTION("rotateLeftKey", RotateLeftKey); CONNECT_FUNCTION("rotateRightKey", RotateRightKey); CONNECT_FUNCTION("rotateUpModifierKey", RotateUpModifierKey); CONNECT_FUNCTION("rotateDownModifierKey", RotateDownModifierKey); } void mitk::AffineBaseDataInteractor3D::TranslateUpKey(StateMachineAction *, InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(2, stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::TranslateDownKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(2, -stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::TranslateLeftKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(0, -stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::TranslateRightKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(0, stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::TranslateUpModifierKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(1, stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::TranslateDownModifierKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(translationStepSizePropertyName, stepSize); mitk::Vector3D movementVector; movementVector.Fill(0.0); movementVector.SetElement(1, -stepSize); this->TranslateGeometry(movementVector, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::RotateUpKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(-stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::RotateDownKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(stepSize, 0, this->GetUpdatedTimeGeometry(interactionEvent)); return; } void mitk::AffineBaseDataInteractor3D::RotateLeftKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(-stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::RotateRightKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(stepSize, 2, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::RotateUpModifierKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::RotateDownModifierKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 1.0f; this->GetDataNode()->GetFloatProperty(rotationStepSizePropertyName, stepSize); this->RotateGeometry(-stepSize, 1, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::ScaleUpKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 0.1f; this->GetDataNode()->GetFloatProperty(scaleStepSizePropertyName, stepSize); mitk::Point3D newScale; newScale.Fill(stepSize); this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::ScaleDownKey(mitk::StateMachineAction *, mitk::InteractionEvent *interactionEvent) { float stepSize = 0.1f; this->GetDataNode()->GetFloatProperty(scaleStepSizePropertyName, stepSize); mitk::Point3D newScale; newScale.Fill(-stepSize); this->ScaleGeometry(newScale, this->GetUpdatedTimeGeometry(interactionEvent)); } void mitk::AffineBaseDataInteractor3D::ScaleGeometry(mitk::Point3D newScale, mitk::BaseGeometry *geometry) { mitk::Point3D anchorPoint; float pointX = 0.0f; float pointY = 0.0f; float pointZ = 0.0f; anchorPoint.Fill(0.0); this->GetDataNode()->GetFloatProperty(anchorPointX, pointX); this->GetDataNode()->GetFloatProperty(anchorPointY, pointY); this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ); anchorPoint[0] = pointX; anchorPoint[1] = pointY; anchorPoint[2] = pointZ; auto *doOp = new mitk::ScaleOperation(OpSCALE, newScale, anchorPoint); geometry->ExecuteOperation(doOp); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineBaseDataInteractor3D::RotateGeometry(mitk::ScalarType angle, int rotationaxis, mitk::BaseGeometry *geometry) { mitk::Vector3D rotationAxis = geometry->GetAxisVector(rotationaxis); float pointX = 0.0f; float pointY = 0.0f; float pointZ = 0.0f; mitk::Point3D pointOfRotation; pointOfRotation.Fill(0.0); this->GetDataNode()->GetFloatProperty(anchorPointX, pointX); this->GetDataNode()->GetFloatProperty(anchorPointY, pointY); this->GetDataNode()->GetFloatProperty(anchorPointZ, pointZ); pointOfRotation[0] = pointX; pointOfRotation[1] = pointY; pointOfRotation[2] = pointZ; auto *doOp = new mitk::RotationOperation(OpROTATE, pointOfRotation, rotationAxis, angle); geometry->ExecuteOperation(doOp); delete doOp; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineBaseDataInteractor3D::TranslateGeometry(mitk::Vector3D translate, mitk::BaseGeometry *geometry) { geometry->Translate(translate); this->GetDataNode()->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } mitk::BaseGeometry *mitk::AffineBaseDataInteractor3D::GetUpdatedTimeGeometry(mitk::InteractionEvent *interactionEvent) { // Get the correct time geometry to support 3D + t int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); BaseGeometry *geometry = this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep); if (geometry == nullptr) MITK_ERROR << "Geometry is nullptr. Cannot modify it."; return geometry; } void mitk::AffineBaseDataInteractor3D::DataNodeChanged() { mitk::DataNode::Pointer newInputNode = this->GetDataNode(); if (newInputNode.IsNotNull()) { // add default properties newInputNode->AddProperty(selectedColorPropertyName, mitk::ColorProperty::New(0.0, 1.0, 0.0)); newInputNode->AddProperty(deselectedColorPropertyName, mitk::ColorProperty::New(0.0, 0.0, 1.0)); newInputNode->AddProperty(translationStepSizePropertyName, mitk::FloatProperty::New(1.0f)); newInputNode->AddProperty(rotationStepSizePropertyName, mitk::FloatProperty::New(1.0f)); newInputNode->AddProperty(scaleStepSizePropertyName, mitk::FloatProperty::New(0.1f)); // save the previous color of the node, in order to restore it after the interactor is destroyed mitk::ColorProperty::Pointer priorColor = dynamic_cast(newInputNode->GetProperty("color")); if (priorColor.IsNotNull()) { mitk::ColorProperty::Pointer tmpCopyOfPriorColor = mitk::ColorProperty::New(); tmpCopyOfPriorColor->SetColor(priorColor->GetColor()); newInputNode->AddProperty(priorPropertyName, tmpCopyOfPriorColor); } newInputNode->SetColor(0.0, 0.0, 1.0); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineBaseDataInteractor3D::SetDataNode(DataNode *node) { this->RestoreNodeProperties(); // if there was another node set, restore it's color DataInteractor::SetDataNode(node); } bool mitk::AffineBaseDataInteractor3D::CheckOverObject(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; Point3D currentWorldPoint; if (interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentWorldPoint) == this->GetDataNode()) return true; return false; } -void mitk::AffineBaseDataInteractor3D::SelectObject(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::AffineBaseDataInteractor3D::SelectObject(StateMachineAction *, InteractionEvent *) { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(selectedColorPropertyName)); if (selectedColor.IsNotNull()) { node->GetPropertyList()->SetProperty("color", selectedColor); } - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return; } -void mitk::AffineBaseDataInteractor3D::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::AffineBaseDataInteractor3D::DeselectObject(StateMachineAction *, InteractionEvent *) { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; mitk::ColorProperty::Pointer selectedColor = dynamic_cast(node->GetProperty(deselectedColorPropertyName)); if (selectedColor.IsNotNull()) { node->GetPropertyList()->SetProperty("color", selectedColor); } - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return; } void mitk::AffineBaseDataInteractor3D::InitTranslate(StateMachineAction *, InteractionEvent *interactionEvent) { InitMembers(interactionEvent); } void mitk::AffineBaseDataInteractor3D::InitRotate(StateMachineAction *, InteractionEvent *interactionEvent) { InitMembers(interactionEvent); } bool mitk::AffineBaseDataInteractor3D::InitMembers(InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); m_InitialPickedWorldPoint = positionEvent->GetPositionInWorld(); // Get the timestep to also support 3D+t int timeStep = 0; if ((interactionEvent->GetSender()) != nullptr) timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // Make deep copy of current Geometry3D of the plane this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date m_OriginalGeometry = static_cast(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer()); return true; } void mitk::AffineBaseDataInteractor3D::TranslateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); Vector3D interactionMove; interactionMove[0] = currentPickedPoint[0] - m_InitialPickedWorldPoint[0]; interactionMove[1] = currentPickedPoint[1] - m_InitialPickedWorldPoint[1]; interactionMove[2] = currentPickedPoint[2] - m_InitialPickedWorldPoint[2]; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); mitk::BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetUpdatedTimeGeometry()->GetGeometryForTimeStep(timeStep); geometry->SetOrigin(m_OriginalGeometry->GetOrigin()); this->TranslateGeometry(interactionMove, this->GetUpdatedTimeGeometry(interactionEvent)); return; } void mitk::AffineBaseDataInteractor3D::RotateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); Point3D currentWorldPoint = positionEvent->GetPositionInWorld(); vtkCamera *camera = nullptr; vtkRenderer *currentVtkRenderer = nullptr; if ((interactionEvent->GetSender()) != nullptr) { camera = interactionEvent->GetSender()->GetVtkRenderer()->GetActiveCamera(); currentVtkRenderer = interactionEvent->GetSender()->GetVtkRenderer(); } if (camera && currentVtkRenderer) { double vpn[3]; camera->GetViewPlaneNormal(vpn); Vector3D viewPlaneNormal; viewPlaneNormal[0] = vpn[0]; viewPlaneNormal[1] = vpn[1]; viewPlaneNormal[2] = vpn[2]; Vector3D interactionMove; interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; if (interactionMove[0] == 0 && interactionMove[1] == 0 && interactionMove[2] == 0) return; Vector3D rotationAxis = itk::CrossProduct(viewPlaneNormal, interactionMove); rotationAxis.Normalize(); int *size = currentVtkRenderer->GetSize(); double l2 = (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) * (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) + (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) * (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]); double rotationAngle = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1])); // Use center of data bounding box as center of rotation Point3D rotationCenter = m_OriginalGeometry->GetCenter(); int timeStep = 0; if ((interactionEvent->GetSender()) != nullptr) timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // Reset current Geometry3D to original state (pre-interaction) and // apply rotation RotationOperation op(OpROTATE, rotationCenter, rotationAxis, rotationAngle); Geometry3D::Pointer newGeometry = static_cast(m_OriginalGeometry->Clone().GetPointer()); newGeometry->ExecuteOperation(&op); mitk::TimeGeometry::Pointer timeGeometry = this->GetDataNode()->GetData()->GetTimeGeometry(); if (timeGeometry.IsNotNull()) timeGeometry->SetTimeStepGeometry(newGeometry, timeStep); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::AffineBaseDataInteractor3D::ScaleObject(StateMachineAction *, InteractionEvent * /*interactionEvent*/) { return; } void mitk::AffineBaseDataInteractor3D::RestoreNodeProperties() { mitk::DataNode::Pointer inputNode = this->GetDataNode(); if (inputNode.IsNull()) return; mitk::ColorProperty::Pointer color = dynamic_cast(inputNode->GetProperty(priorPropertyName)); if (color.IsNotNull()) { inputNode->GetPropertyList()->SetProperty("color", color); } inputNode->GetPropertyList()->DeleteProperty(selectedColorPropertyName); inputNode->GetPropertyList()->DeleteProperty(deselectedColorPropertyName); inputNode->GetPropertyList()->DeleteProperty(priorPropertyName); inputNode->GetPropertyList()->DeleteProperty(translationStepSizePropertyName); inputNode->GetPropertyList()->DeleteProperty(rotationStepSizePropertyName); inputNode->GetPropertyList()->DeleteProperty(scaleStepSizePropertyName); // update rendering mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Modules/DataTypesExt/src/mitkAffineImageCropperInteractor.cpp b/Modules/DataTypesExt/src/mitkAffineImageCropperInteractor.cpp index e60562a461..3fdf7bdddc 100644 --- a/Modules/DataTypesExt/src/mitkAffineImageCropperInteractor.cpp +++ b/Modules/DataTypesExt/src/mitkAffineImageCropperInteractor.cpp @@ -1,264 +1,264 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkAffineImageCropperInteractor.h" #include "mitkInteractionConst.h" #include "mitkInteractionPositionEvent.h" #include "mitkRotationOperation.h" #include "mitkSurface.h" #include "mitkVtkMapper.h" #include #include #include #include #include #include #include #include #include #include mitk::AffineImageCropperInteractor::AffineImageCropperInteractor() { m_OriginalGeometry = Geometry3D::New(); } mitk::AffineImageCropperInteractor::~AffineImageCropperInteractor() { } void mitk::AffineImageCropperInteractor::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually // executing an action CONNECT_CONDITION("isOverObject", CheckOverObject); // **Function** in the statmachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectObject", SelectObject); CONNECT_FUNCTION("deselectObject", DeselectObject); CONNECT_FUNCTION("initTranslate", InitTranslate); CONNECT_FUNCTION("initRotate", InitRotate); CONNECT_FUNCTION("initDeformation", InitDeformation); CONNECT_FUNCTION("translateObject", TranslateObject); CONNECT_FUNCTION("rotateObject", RotateObject); CONNECT_FUNCTION("deformObject", DeformObject); CONNECT_FUNCTION("scaleRadius", ScaleRadius); } void mitk::AffineImageCropperInteractor::DataNodeChanged() { } bool mitk::AffineImageCropperInteractor::CheckOverObject(const InteractionEvent *interactionEvent) { mitk::DataNode::Pointer dn = this->GetDataNode(); if (dn.IsNull()) return false; const auto *positionEvent = dynamic_cast(interactionEvent); Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); auto *object = dynamic_cast(dn->GetData()); object->GetGeometry()->WorldToIndex(currentPickedPoint, currentPickedPoint); return object && object->GetGeometry()->GetBoundingBox()->IsInside(currentPickedPoint); } -void mitk::AffineImageCropperInteractor::SelectObject(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::AffineImageCropperInteractor::SelectObject(StateMachineAction *, InteractionEvent *) { mitk::DataNode::Pointer dn = this->GetDataNode(); if (dn.IsNull()) return; m_SelectedNode = dn; - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineImageCropperInteractor::Deselect() { mitk::DataNode::Pointer dn = this->GetDataNode(); if (dn.IsNull()) return; m_SelectedNode = dn; } -void mitk::AffineImageCropperInteractor::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::AffineImageCropperInteractor::DeselectObject(StateMachineAction *, InteractionEvent *) { Deselect(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineImageCropperInteractor::ScaleRadius(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *wheelEvent = dynamic_cast(interactionEvent); if (wheelEvent == nullptr) return; if (m_SelectedNode.IsNull()) return; double scale = (double)(wheelEvent->GetWheelDelta()) / 64.0; mitk::Point3D newScale; newScale[0] = newScale[1] = newScale[2] = scale; mitk::Point3D anchorPoint = wheelEvent->GetPositionInWorld(); auto *doOp = new mitk::ScaleOperation(OpSCALE, newScale, anchorPoint); m_SelectedNode->GetData()->GetGeometry()->ExecuteOperation(doOp); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineImageCropperInteractor::InitTranslate(StateMachineAction *, InteractionEvent *interactionEvent) { if (m_SelectedNode.IsNull()) return; auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; m_InitialPickedPoint = positionEvent->GetPositionInWorld(); m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); mitk::Surface::Pointer surface = dynamic_cast(m_SelectedNode->GetData()); mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry(); m_InitialOrigin = surGeo->GetOrigin(); } void mitk::AffineImageCropperInteractor::InitRotate(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; m_InitialPickedPoint = positionEvent->GetPositionInWorld(); m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); mitk::Surface::Pointer surface = dynamic_cast(m_SelectedNode->GetData()); mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry(); m_OriginalGeometry = dynamic_cast(surGeo.GetPointer()); } void mitk::AffineImageCropperInteractor::InitDeformation(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; m_InitialPickedPoint = positionEvent->GetPositionInWorld(); m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); mitk::Surface::Pointer surface = dynamic_cast(m_SelectedNode->GetData()); mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry(); m_OriginalGeometry = dynamic_cast(surGeo.GetPointer()); } void mitk::AffineImageCropperInteractor::TranslateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); Vector3D interactionMove; interactionMove[0] = currentPickedPoint[0] - m_InitialPickedPoint[0]; interactionMove[1] = currentPickedPoint[1] - m_InitialPickedPoint[1]; interactionMove[2] = currentPickedPoint[2] - m_InitialPickedPoint[2]; mitk::Surface::Pointer surface = dynamic_cast(m_SelectedNode->GetData()); mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry(); surGeo->SetOrigin(m_InitialOrigin); surGeo->Translate(interactionMove); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineImageCropperInteractor::DeformObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; Point3D currentPickedPoint = positionEvent->GetPositionInWorld(); Vector3D interactionMove = currentPickedPoint - m_InitialPickedPoint; mitk::Surface::Pointer surface = dynamic_cast(m_SelectedNode->GetData()); surface->SetGeometry(m_OriginalGeometry); mitk::BaseGeometry::Pointer surGeo = surface->GetGeometry(); surGeo->WorldToIndex(interactionMove, interactionMove); Point3D scale; for (int i = 0; i < 3; ++i) { scale[i] = (interactionMove[i] * surGeo->GetMatrixColumn(i).magnitude()) - 1; } mitk::Point3D anchorPoint = surGeo->GetCenter(); auto *doOp = new mitk::ScaleOperation(OpSCALE, scale, anchorPoint); surGeo->ExecuteOperation(doOp); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::AffineImageCropperInteractor::RotateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); if (currentPickedDisplayPoint.EuclideanDistanceTo(m_InitialPickedDisplayPoint) < 1) return; vtkRenderer *currentVtkRenderer = interactionEvent->GetSender()->GetVtkRenderer(); if (currentVtkRenderer && currentVtkRenderer->GetActiveCamera()) { double vpn[3]; currentVtkRenderer->GetActiveCamera()->GetViewPlaneNormal(vpn); Vector3D rotationAxis; rotationAxis[0] = vpn[0]; rotationAxis[1] = vpn[1]; rotationAxis[2] = vpn[2]; rotationAxis.Normalize(); Vector2D move = currentPickedDisplayPoint - m_InitialPickedDisplayPoint; double rotationAngle = -57.3 * atan(move[0] / move[1]); if (move[1] < 0) rotationAngle += 180; // Use center of data bounding box as center of rotation Point3D rotationCenter = m_OriginalGeometry->GetCenter(); if (positionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard2D) rotationCenter = m_InitialPickedPoint; // Reset current Geometry3D to original state (pre-interaction) and // apply rotation RotationOperation op(OpROTATE, rotationCenter, rotationAxis, rotationAngle); Geometry3D::Pointer newGeometry = static_cast(m_OriginalGeometry->Clone().GetPointer()); newGeometry->ExecuteOperation(&op); m_SelectedNode->GetData()->SetGeometry(newGeometry); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } diff --git a/Modules/DataTypesExt/src/mitkClippingPlaneInteractor3D.cpp b/Modules/DataTypesExt/src/mitkClippingPlaneInteractor3D.cpp index 2ac56950ac..e992805c13 100644 --- a/Modules/DataTypesExt/src/mitkClippingPlaneInteractor3D.cpp +++ b/Modules/DataTypesExt/src/mitkClippingPlaneInteractor3D.cpp @@ -1,337 +1,337 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkClippingPlaneInteractor3D.h" #include #include #include #include #include #include #include #include #include #include mitk::ClippingPlaneInteractor3D::ClippingPlaneInteractor3D() { m_OriginalGeometry = Geometry3D::New(); // Initialize vector arithmetic m_ObjectNormal[0] = 0.0; m_ObjectNormal[1] = 0.0; m_ObjectNormal[2] = 1.0; } mitk::ClippingPlaneInteractor3D::~ClippingPlaneInteractor3D() { } void mitk::ClippingPlaneInteractor3D::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually // executing an action CONNECT_CONDITION("isOverObject", CheckOverObject); // **Function** in the statmachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectObject", SelectObject); CONNECT_FUNCTION("deselectObject", DeselectObject); CONNECT_FUNCTION("initTranslate", InitTranslate); CONNECT_FUNCTION("initRotate", InitRotate); CONNECT_FUNCTION("translateObject", TranslateObject); CONNECT_FUNCTION("rotateObject", RotateObject); } void mitk::ClippingPlaneInteractor3D::DataNodeChanged() { } bool mitk::ClippingPlaneInteractor3D::CheckOverObject(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; Point3D currentWorldPoint; if (interactionEvent->GetSender()->PickObject(positionEvent->GetPointerPositionOnScreen(), currentWorldPoint) == this->GetDataNode()) return true; return false; } void mitk::ClippingPlaneInteractor3D::SelectObject(StateMachineAction *, InteractionEvent *interactionEvent) { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; node->SetColor(1.0, 0.0, 0.0); // Colorize surface / wireframe dependend on distance from picked point this->ColorizeSurface(interactionEvent->GetSender(), 0.0); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::ClippingPlaneInteractor3D::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent) { DataNode::Pointer node = this->GetDataNode(); if (node.IsNull()) return; node->SetColor(1.0, 1.0, 1.0); // Colorize surface / wireframe as inactive this->ColorizeSurface(interactionEvent->GetSender(), -1.0); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::ClippingPlaneInteractor3D::InitTranslate(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), m_InitialPickedDisplayPoint[0], m_InitialPickedDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], m_InitialPickedWorldPoint); // Get the timestep to also support 3D+t int timeStep = 0; if ((interactionEvent->GetSender()) != nullptr) timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // Make deep copy of current Geometry3D of the plane this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date m_OriginalGeometry = static_cast(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer()); } void mitk::ClippingPlaneInteractor3D::InitRotate(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; m_InitialPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), m_InitialPickedDisplayPoint[0], m_InitialPickedDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], m_InitialPickedWorldPoint); // Get the timestep to also support 3D+t int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // Make deep copy of current Geometry3D of the plane this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date m_OriginalGeometry = static_cast(this->GetDataNode()->GetData()->GetGeometry(timeStep)->Clone().GetPointer()); } void mitk::ClippingPlaneInteractor3D::TranslateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; double currentWorldPoint[4]; mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen(); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), currentDisplayPoint[0], currentDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], currentWorldPoint); Vector3D interactionMove; interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; Point3D origin = m_OriginalGeometry->GetOrigin(); // Get the timestep to also support 3D+t int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // If data is an mitk::Surface, extract it Surface::Pointer surface = dynamic_cast(this->GetDataNode()->GetData()); vtkPolyData *polyData = nullptr; if (surface.IsNotNull()) { polyData = surface->GetVtkPolyData(timeStep); // Extract surface normal from surface (if existent, otherwise use default) vtkPointData *pointData = polyData->GetPointData(); if (pointData != nullptr) { vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal"); if (normal != nullptr) { m_ObjectNormal[0] = normal->GetComponent(0, 0); m_ObjectNormal[1] = normal->GetComponent(0, 1); m_ObjectNormal[2] = normal->GetComponent(0, 2); } } } Vector3D transformedObjectNormal; this->GetDataNode()->GetData()->GetGeometry(timeStep)->IndexToWorld(m_ObjectNormal, transformedObjectNormal); this->GetDataNode()->GetData()->GetGeometry(timeStep)->SetOrigin( origin + transformedObjectNormal * (interactionMove * transformedObjectNormal)); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::ClippingPlaneInteractor3D::RotateObject(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; double currentWorldPoint[4]; Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), currentPickedDisplayPoint[0], currentPickedDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], currentWorldPoint); vtkCamera *camera = nullptr; vtkRenderer *currentVtkRenderer = nullptr; if ((interactionEvent->GetSender()) != nullptr) { vtkRenderWindow *renderWindow = interactionEvent->GetSender()->GetRenderWindow(); if (renderWindow != nullptr) { vtkRenderWindowInteractor *renderWindowInteractor = renderWindow->GetInteractor(); if (renderWindowInteractor != nullptr) { currentVtkRenderer = renderWindowInteractor->GetInteractorStyle()->GetCurrentRenderer(); if (currentVtkRenderer != nullptr) camera = currentVtkRenderer->GetActiveCamera(); } } } if (camera) { double vpn[3]; camera->GetViewPlaneNormal(vpn); Vector3D viewPlaneNormal; viewPlaneNormal[0] = vpn[0]; viewPlaneNormal[1] = vpn[1]; viewPlaneNormal[2] = vpn[2]; Vector3D interactionMove; interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; if (interactionMove[0] == 0 && interactionMove[1] == 0 && interactionMove[2] == 0) return; Vector3D rotationAxis = itk::CrossProduct(viewPlaneNormal, interactionMove); rotationAxis.Normalize(); int *size = currentVtkRenderer->GetSize(); double l2 = (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) * (currentPickedDisplayPoint[0] - m_InitialPickedDisplayPoint[0]) + (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]) * (currentPickedDisplayPoint[1] - m_InitialPickedDisplayPoint[1]); double rotationAngle = 360.0 * sqrt(l2 / (size[0] * size[0] + size[1] * size[1])); // Use center of data bounding box as center of rotation Point3D rotationCenter = m_OriginalGeometry->GetCenter(); int timeStep = 0; if ((interactionEvent->GetSender()) != nullptr) timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); // Reset current Geometry3D to original state (pre-interaction) and // apply rotation RotationOperation op(OpROTATE, rotationCenter, rotationAxis, rotationAngle); Geometry3D::Pointer newGeometry = static_cast(m_OriginalGeometry->Clone().GetPointer()); newGeometry->ExecuteOperation(&op); mitk::TimeGeometry::Pointer timeGeometry = this->GetDataNode()->GetData()->GetTimeGeometry(); if (timeGeometry.IsNotNull()) timeGeometry->SetTimeStepGeometry(newGeometry, timeStep); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::ClippingPlaneInteractor3D::ColorizeSurface(BaseRenderer::Pointer renderer, double scalar) { BaseData::Pointer data = this->GetDataNode()->GetData(); if (data.IsNull()) { MITK_ERROR << "ClippingPlaneInteractor3D: No data object present!"; return; } // Get the timestep to also support 3D+t int timeStep = 0; if (renderer.IsNotNull()) timeStep = renderer->GetTimeStep(data); // If data is an mitk::Surface, extract it Surface::Pointer surface = dynamic_cast(data.GetPointer()); vtkPolyData *polyData = nullptr; if (surface.IsNotNull()) polyData = surface->GetVtkPolyData(timeStep); if (polyData == nullptr) { MITK_ERROR << "ClippingPlaneInteractor3D: No poly data present!"; return; } vtkPointData *pointData = polyData->GetPointData(); if (pointData == nullptr) { MITK_ERROR << "ClippingPlaneInteractor3D: No point data present!"; return; } vtkDataArray *scalars = pointData->GetScalars(); if (scalars == nullptr) { MITK_ERROR << "ClippingPlaneInteractor3D: No scalars for point data present!"; return; } for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i) { scalars->SetComponent(i, 0, scalar); } polyData->Modified(); pointData->Update(); } diff --git a/Modules/DataTypesExt/src/mitkSurfaceDeformationDataInteractor3D.cpp b/Modules/DataTypesExt/src/mitkSurfaceDeformationDataInteractor3D.cpp index 580aebd20a..ba4697895c 100644 --- a/Modules/DataTypesExt/src/mitkSurfaceDeformationDataInteractor3D.cpp +++ b/Modules/DataTypesExt/src/mitkSurfaceDeformationDataInteractor3D.cpp @@ -1,305 +1,305 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSurfaceDeformationDataInteractor3D.h" #include "mitkMouseWheelEvent.h" #include #include #include mitk::SurfaceDeformationDataInteractor3D::SurfaceDeformationDataInteractor3D() : m_GaussSigma(30.0) { m_OriginalPolyData = vtkPolyData::New(); // Initialize vector arithmetic m_ObjectNormal[0] = 0.0; m_ObjectNormal[1] = 0.0; m_ObjectNormal[2] = 1.0; } mitk::SurfaceDeformationDataInteractor3D::~SurfaceDeformationDataInteractor3D() { m_OriginalPolyData->Delete(); } void mitk::SurfaceDeformationDataInteractor3D::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before // actually executing an action CONNECT_CONDITION("isOverObject", CheckOverObject); // **Function** in the statmachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectObject", SelectObject); CONNECT_FUNCTION("deselectObject", DeselectObject); CONNECT_FUNCTION("initDeformation", InitDeformation); CONNECT_FUNCTION("deformObject", DeformObject); CONNECT_FUNCTION("scaleRadius", ScaleRadius); } void mitk::SurfaceDeformationDataInteractor3D::DataNodeChanged() { if (this->GetDataNode() != nullptr) { m_Surface = dynamic_cast(this->GetDataNode()->GetData()); if (m_Surface == nullptr) MITK_ERROR << "SurfaceDeformationDataInteractor3D::DataNodeChanged(): DataNode has to contain a surface."; } else m_Surface = nullptr; } bool mitk::SurfaceDeformationDataInteractor3D::CheckOverObject(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); Point3D currentPickedPoint; if (interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, currentPickedPoint) == this->GetDataNode()) { // Colorized surface at current picked position m_SurfaceColorizationCenter = currentPickedPoint; return true; } return false; } void mitk::SurfaceDeformationDataInteractor3D::SelectObject(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep); this->GetDataNode()->SetColor(1.0, 0.0, 0.0); // Colorize surface / wireframe dependend on distance from picked point this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SurfaceDeformationDataInteractor3D::DeselectObject(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep); this->GetDataNode()->SetColor(1.0, 1.0, 1.0); // Colorize surface / wireframe as inactive this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_CONSTANT, -1.0); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SurfaceDeformationDataInteractor3D::InitDeformation(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep); // Store current picked point mitk::Point2D currentPickedDisplayPoint = positionEvent->GetPointerPositionOnScreen(); interactionEvent->GetSender()->PickObject(currentPickedDisplayPoint, m_InitialPickedPoint); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), currentPickedDisplayPoint[0], currentPickedDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], m_InitialPickedWorldPoint); // Make deep copy of vtkPolyData interacted on m_OriginalPolyData->DeepCopy(polyData); } void mitk::SurfaceDeformationDataInteractor3D::DeformObject(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep); BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep); double currentWorldPoint[4]; mitk::Point2D currentDisplayPoint = positionEvent->GetPointerPositionOnScreen(); vtkInteractorObserver::ComputeDisplayToWorld(interactionEvent->GetSender()->GetVtkRenderer(), currentDisplayPoint[0], currentDisplayPoint[1], 0.0, // m_InitialInteractionPickedPoint[2], currentWorldPoint); // Calculate mouse move in 3D space Vector3D interactionMove; interactionMove[0] = currentWorldPoint[0] - m_InitialPickedWorldPoint[0]; interactionMove[1] = currentWorldPoint[1] - m_InitialPickedWorldPoint[1]; interactionMove[2] = currentWorldPoint[2] - m_InitialPickedWorldPoint[2]; // Transform mouse move into geometry space this->GetDataNode()->GetData()->UpdateOutputInformation(); // make sure that the Geometry is up-to-date Vector3D interactionMoveIndex; geometry->WorldToIndex(interactionMove, interactionMoveIndex); // Get picked point and transform into local coordinates Point3D pickedPoint; geometry->WorldToIndex(m_InitialPickedPoint, pickedPoint); Vector3D v1 = pickedPoint.GetVectorFromOrigin(); vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal"); if (normal != nullptr) { m_ObjectNormal[0] = normal->GetComponent(0, 0); m_ObjectNormal[1] = normal->GetComponent(0, 1); m_ObjectNormal[2] = normal->GetComponent(0, 2); } Vector3D v2 = m_ObjectNormal * (interactionMoveIndex * m_ObjectNormal); vtkPoints *originalPoints = m_OriginalPolyData->GetPoints(); vtkPoints *deformedPoints = polyData->GetPoints(); double denom = m_GaussSigma * m_GaussSigma * 2; double point[3]; for (vtkIdType i = 0; i < deformedPoints->GetNumberOfPoints(); ++i) { // Get original point double *originalPoint = originalPoints->GetPoint(i); Vector3D v0; v0[0] = originalPoint[0]; v0[1] = originalPoint[1]; v0[2] = originalPoint[2]; // Calculate distance of this point from line through picked point double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm(); Vector3D t = v2 * exp(-d * d / denom); point[0] = originalPoint[0] + t[0]; point[1] = originalPoint[1] + t[1]; point[2] = originalPoint[2] + t[2]; deformedPoints->SetPoint(i, point); } // Make sure that surface is colorized at initial picked position as long as we are in deformation state m_SurfaceColorizationCenter = m_InitialPickedPoint; polyData->Modified(); m_Surface->Modified(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SurfaceDeformationDataInteractor3D::ScaleRadius(StateMachineAction *, InteractionEvent *interactionEvent) { const auto *wheelEvent = dynamic_cast(interactionEvent); if (wheelEvent == nullptr) return; m_GaussSigma += (double)(wheelEvent->GetWheelDelta()) / 20; if (m_GaussSigma < 10.0) { m_GaussSigma = 10.0; } else if (m_GaussSigma > 128.0) { m_GaussSigma = 128.0; } int timeStep = interactionEvent->GetSender()->GetTimeStep(this->GetDataNode()->GetData()); vtkPolyData *polyData = m_Surface->GetVtkPolyData(timeStep); // Colorize surface / wireframe dependend on sigma and distance from picked point this->ColorizeSurface(polyData, timeStep, m_SurfaceColorizationCenter, COLORIZATION_GAUSS); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::SurfaceDeformationDataInteractor3D::ColorizeSurface( vtkPolyData *polyData, int timeStep, const Point3D &pickedPoint, int mode, double scalar) { if (polyData == nullptr) return; vtkPoints *points = polyData->GetPoints(); vtkPointData *pointData = polyData->GetPointData(); if (pointData == nullptr) return; vtkDataArray *scalars = pointData->GetScalars(); if (scalars == nullptr) return; if (mode == COLORIZATION_GAUSS) { // Get picked point and transform into local coordinates Point3D localPickedPoint; BaseGeometry::Pointer geometry = this->GetDataNode()->GetData()->GetGeometry(timeStep); geometry->WorldToIndex(pickedPoint, localPickedPoint); Vector3D v1 = localPickedPoint.GetVectorFromOrigin(); vtkDataArray *normal = polyData->GetPointData()->GetVectors("planeNormal"); if (normal != nullptr) { m_ObjectNormal[0] = normal->GetComponent(0, 0); m_ObjectNormal[1] = normal->GetComponent(0, 1); m_ObjectNormal[2] = normal->GetComponent(0, 2); } double denom = m_GaussSigma * m_GaussSigma * 2; for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i) { // Get original point double *point = points->GetPoint(i); Vector3D v0; v0[0] = point[0]; v0[1] = point[1]; v0[2] = point[2]; // Calculate distance of this point from line through picked point double d = itk::CrossProduct(m_ObjectNormal, (v1 - v0)).GetNorm(); double t = exp(-d * d / denom); scalars->SetComponent(i, 0, t); } } else if (mode == COLORIZATION_CONSTANT) { for (vtkIdType i = 0; i < pointData->GetNumberOfTuples(); ++i) { scalars->SetComponent(i, 0, scalar); } } polyData->Modified(); pointData->Update(); } diff --git a/Modules/IGT/Testing/mitkCameraVisualizationTest.cpp b/Modules/IGT/Testing/mitkCameraVisualizationTest.cpp index fc509ee4d6..6fe051fafd 100644 --- a/Modules/IGT/Testing/mitkCameraVisualizationTest.cpp +++ b/Modules/IGT/Testing/mitkCameraVisualizationTest.cpp @@ -1,105 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCameraVisualization.h" #include "mitkNavigationData.h" #include "mitkTestingMacros.h" #include "mitkVtkPropRenderer.h" #include #include #include /**Documentation * test for the class "NavigationDataVisualizationByBaseDataTransformFilter". */ int mitkCameraVisualizationTest(int /* argc */, char* /*argv*/[]) { MITK_TEST_BEGIN("CameraVisualization") // let's create an object of our class mitk::CameraVisualization::Pointer myFilter = mitk::CameraVisualization::New(); // first test: did this work? // using MITK_TEST_CONDITION_REQUIRED makes the test stop after failure, since // it makes no sense to continue without an object. MITK_TEST_CONDITION_REQUIRED(myFilter.IsNotNull(),"Testing instantiation"); /* create helper objects: navigation data with position as origin, zero quaternion, zero error and data valid */ srand(time(nullptr)); // generate a random position for the navigation data mitk::NavigationData::PositionType position; position[0] = rand()%1000; position[1] = rand()%1000; position[2] = rand()%1000; // generate a random orientation for the navigation data mitk::NavigationData::OrientationType orientation; orientation[0] = (rand()%1000)/1000.0; orientation[1] = (rand()%1000)/1000.0; orientation[2] = (rand()%1000)/1000.0; orientation[3] = (rand()%1000)/1000.0; // generate a random error for the navigation data mitk::ScalarType error = rand()%10; // data valid flag of navigation data int val = rand()%2; bool valid(false); // this was uninitialized. how was this test ever meant to work?? if (val==0) { valid=false; } else if (val==1) { valid=true; } // set parameters of navigation data mitk::NavigationData::Pointer nd1 = mitk::NavigationData::New(); nd1->SetPosition(position); nd1->SetOrientation(orientation); nd1->SetPositionAccuracy(error); nd1->SetDataValid(valid); // create renderer vtkRenderWindow* renderWindow = vtkRenderWindow::New(); - mitk::VtkPropRenderer::Pointer renderer = mitk::VtkPropRenderer::New( "TestRenderer",renderWindow, mitk::RenderingManager::GetInstance() ); + mitk::VtkPropRenderer::Pointer renderer = mitk::VtkPropRenderer::New( "TestRenderer", renderWindow ); myFilter->SetInput(nd1); MITK_TEST_CONDITION(myFilter->GetInput() == nd1, "Testing Set-/GetInput() input 1"); // test for exception if renderer not set MITK_TEST_FOR_EXCEPTION_BEGIN(itk::ExceptionObject) myFilter->Update(); MITK_TEST_FOR_EXCEPTION_END(itk::ExceptionObject) // set renderer myFilter->SetRenderer(renderer); //Update filter myFilter->Update(); //Delete renderWindow correctly renderWindow->Delete(); // always end with this! MITK_TEST_END(); } diff --git a/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp b/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp index cb96e6bc48..1d2df7ad7b 100644 --- a/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp +++ b/Modules/PlanarFigure/src/Interactions/mitkPlanarFigureInteractor.cpp @@ -1,956 +1,953 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define PLANARFIGUREINTERACTOR_DBG MITK_DEBUG("PlanarFigureInteractor") << __LINE__ << ": " #include "mitkPlanarFigureInteractor.h" #include "mitkPlanarBezierCurve.h" #include "mitkPlanarCircle.h" #include "mitkPlanarFigure.h" #include "mitkPlanarPolygon.h" #include "mitkInteractionPositionEvent.h" #include "mitkInternalEvent.h" #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkAbstractTransformGeometry.h" #include "mitkPlaneGeometry.h" mitk::PlanarFigureInteractor::PlanarFigureInteractor() : DataInteractor(), m_Precision(6.5), m_MinimumPointDistance(25.0), m_IsHovering(false), m_LastPointWasValid(false) { } mitk::PlanarFigureInteractor::~PlanarFigureInteractor() { } void mitk::PlanarFigureInteractor::ConnectActionsAndFunctions() { CONNECT_CONDITION("figure_is_on_current_slice", CheckFigureOnRenderingGeometry); CONNECT_CONDITION("figure_is_placed", CheckFigurePlaced); CONNECT_CONDITION("minimal_figure_is_finished", CheckMinimalFigureFinished); CONNECT_CONDITION("hovering_above_figure", CheckFigureHovering); CONNECT_CONDITION("hovering_above_point", CheckControlPointHovering); CONNECT_CONDITION("figure_is_selected", CheckSelection); CONNECT_CONDITION("point_is_valid", CheckPointValidity); CONNECT_CONDITION("figure_is_finished", CheckFigureFinished); CONNECT_CONDITION("reset_on_point_select_needed", CheckResetOnPointSelect); CONNECT_CONDITION("points_can_be_added_or_removed", CheckFigureIsExtendable); CONNECT_CONDITION("figure_can_be_deleted", CheckFigureIsDeletable); CONNECT_CONDITION("figure_is_editable", CheckFigureIsEditable); CONNECT_FUNCTION("finalize_figure", FinalizeFigure); CONNECT_FUNCTION("hide_preview_point", HidePreviewPoint) CONNECT_FUNCTION("hide_control_points", HideControlPoints) CONNECT_FUNCTION("set_preview_point_position", SetPreviewPointPosition) CONNECT_FUNCTION("move_current_point", MoveCurrentPoint); CONNECT_FUNCTION("deselect_point", DeselectPoint); CONNECT_FUNCTION("add_new_point", AddPoint); CONNECT_FUNCTION("add_initial_point", AddInitialPoint); CONNECT_FUNCTION("remove_selected_point", RemoveSelectedPoint); CONNECT_FUNCTION("request_context_menu", RequestContextMenu); CONNECT_FUNCTION("select_figure", SelectFigure); CONNECT_FUNCTION("select_point", SelectPoint); CONNECT_FUNCTION("end_interaction", EndInteraction); CONNECT_FUNCTION("start_hovering", StartHovering) CONNECT_FUNCTION("end_hovering", EndHovering); CONNECT_FUNCTION("delete_figure", DeleteFigure); CONNECT_FUNCTION("reset_on_point_select", PerformPointResetOnSelect); } bool mitk::PlanarFigureInteractor::CheckFigurePlaced(const InteractionEvent * /*interactionEvent*/) { const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); bool isFigureFinished = false; planarFigure->GetPropertyList()->GetBoolProperty("initiallyplaced", isFigureFinished); return planarFigure->IsPlaced() && isFigureFinished; } void mitk::PlanarFigureInteractor::MoveCurrentPoint(StateMachineAction *, InteractionEvent *interactionEvent) { auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; bool isEditable = true; GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable); auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::PlaneGeometry *planarFigureGeometry = planarFigure->GetPlaneGeometry(); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); if (abstractTransformGeometry != nullptr) return; // Extract point in 2D world coordinates (relative to PlaneGeometry of // PlanarFigure) Point2D point2D; if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D) || !isEditable) { return; } planarFigure->InvokeEvent(StartInteractionPlanarFigureEvent()); // check if the control points shall be hidden during interaction bool hidecontrolpointsduringinteraction = false; GetDataNode()->GetBoolProperty("planarfigure.hidecontrolpointsduringinteraction", hidecontrolpointsduringinteraction); // hide the control points if necessary // interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( true ); GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", !hidecontrolpointsduringinteraction); // interactionEvent->GetSender()->GetDataStorage()->BlockNodeModifiedEvents( false ); // Move current control point to this point planarFigure->SetCurrentControlPoint(point2D); // Re-evaluate features planarFigure->EvaluateFeatures(); // Update rendered scene - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } -void mitk::PlanarFigureInteractor::FinalizeFigure(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::PlanarFigureInteractor::FinalizeFigure(StateMachineAction *, InteractionEvent *) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->Modified(); planarFigure->DeselectControlPoint(); planarFigure->RemoveLastControlPoint(); planarFigure->SetProperty("initiallyplaced", mitk::BoolProperty::New(true)); GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true); GetDataNode()->Modified(); planarFigure->InvokeEvent(EndPlacementPlanarFigureEvent()); planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent()); // Shape might change when figure is finalized, e.g., smoothing of subdivision polygon planarFigure->EvaluateFeatures(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } -void mitk::PlanarFigureInteractor::EndInteraction(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::PlanarFigureInteractor::EndInteraction(StateMachineAction *, InteractionEvent *) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true); planarFigure->Modified(); planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent()); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } bool mitk::PlanarFigureInteractor::FilterEvents(InteractionEvent *interactionEvent, mitk::DataNode * /*dataNode*/) { if (interactionEvent->GetSender() == nullptr) return false; if (interactionEvent->GetSender()->GetMapperID() == BaseRenderer::Standard3D) return false; return true; } -void mitk::PlanarFigureInteractor::EndHovering(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::PlanarFigureInteractor::EndHovering(StateMachineAction *, InteractionEvent *) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->ResetPreviewContolPoint(); // Invoke end-hover event once the mouse is exiting the figure area m_IsHovering = false; planarFigure->InvokeEvent(EndHoverPlanarFigureEvent()); // Set bool property to indicate that planar figure is no longer in "hovering" mode GetDataNode()->SetBoolProperty("planarfigure.ishovering", false); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PlanarFigureInteractor::DeleteFigure(StateMachineAction *, InteractionEvent *interactionEvent) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->RemoveAllObservers(); GetDataNode()->RemoveAllObservers(); interactionEvent->GetSender()->GetDataStorage()->Remove(GetDataNode()); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PlanarFigureInteractor::PerformPointResetOnSelect(StateMachineAction *, InteractionEvent *) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->ResetOnPointSelect(); } bool mitk::PlanarFigureInteractor::CheckMinimalFigureFinished(const InteractionEvent * /*interactionEvent*/) { const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); return (planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMinimumNumberOfControlPoints()); } bool mitk::PlanarFigureInteractor::CheckFigureFinished(const InteractionEvent * /*interactionEvent*/) { const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); return (planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints()); } bool mitk::PlanarFigureInteractor::CheckFigureIsExtendable(const InteractionEvent * /*interactionEvent*/) { bool isExtendable(false); GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable); return isExtendable; } bool mitk::PlanarFigureInteractor::CheckFigureIsDeletable(const InteractionEvent * /*interactionEvent*/) { bool isDeletable(true); GetDataNode()->GetBoolProperty("planarfigure.isdeletable", isDeletable); return isDeletable; } bool mitk::PlanarFigureInteractor::CheckFigureIsEditable(const InteractionEvent * /*interactionEvent*/) { bool isEditable(true); GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable); return isEditable; } void mitk::PlanarFigureInteractor::DeselectPoint(StateMachineAction *, InteractionEvent * /*interactionEvent*/) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); const bool wasSelected = planarFigure->DeselectControlPoint(); if (wasSelected) { // Issue event so that listeners may update themselves planarFigure->Modified(); planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent()); GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true); // GetDataNode()->SetBoolProperty( "planarfigure.ishovering", false ); GetDataNode()->Modified(); } } void mitk::PlanarFigureInteractor::AddPoint(StateMachineAction *, InteractionEvent *interactionEvent) { const mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; const DataNode::Pointer node = this->GetDataNode(); const BaseData::Pointer data = node->GetData(); /* * Added check for "initiallyplaced" due to bug 13097: * * There are two possible cases in which a point can be inserted into a PlanarPolygon: * * 1. The figure is currently drawn -> the point will be appended at the end of the figure * 2. A point is inserted at a userdefined position after the initial placement of the figure is finished * * In the second case we need to determine the proper insertion index. In the first case the index always has * to be -1 so that the point is appended to the end. * * These changes are necessary because of a macOS specific issue: If a users draws a PlanarPolygon then the * next point to be added moves according to the mouse position. If then the user left clicks in order to add * a point one would assume the last move position is identical to the left click position. This is actually the * case for windows and linux but somehow NOT for mac. Because of the insertion logic of a new point in the * PlanarFigure then for mac the wrong current selected point is determined. * * With this check here this problem can be avoided. However a redesign of the insertion logic should be considered */ bool isFigureFinished = false; data->GetPropertyList()->GetBoolProperty("initiallyplaced", isFigureFinished); bool selected = false; bool isEditable = true; node->GetBoolProperty("selected", selected); node->GetBoolProperty("planarfigure.iseditable", isEditable); if (!selected || !isEditable) { return; } auto *planarFigure = dynamic_cast(data.GetPointer()); // We can't derive a new control point from a polyline of a Bezier curve // as all control points contribute to each polyline point. if (dynamic_cast(planarFigure) != nullptr && isFigureFinished) return; const mitk::PlaneGeometry *planarFigureGeometry = planarFigure->GetPlaneGeometry(); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); if (abstractTransformGeometry != nullptr) return; // If the planarFigure already has reached the maximum number if (planarFigure->GetNumberOfControlPoints() >= planarFigure->GetMaximumNumberOfControlPoints()) { return; } // Extract point in 2D world coordinates (relative to PlaneGeometry of // PlanarFigure) Point2D point2D, projectedPoint; if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D)) { return; } // TODO: check segment of polyline we clicked in int nextIndex = -1; // We only need to check which position to insert the control point // when interacting with a PlanarPolygon. For all other types // new control points will always be appended const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry(); if (dynamic_cast(planarFigure) && isFigureFinished) { nextIndex = this->IsPositionOverFigure(positionEvent, planarFigure, planarFigureGeometry, projectionPlane, projectedPoint); } // Add point as new control point if (planarFigure->IsPreviewControlPointVisible()) { point2D = planarFigure->GetPreviewControlPoint(); } planarFigure->AddControlPoint(point2D, planarFigure->GetControlPointForPolylinePoint(nextIndex, 0)); if (planarFigure->IsPreviewControlPointVisible()) { planarFigure->SelectControlPoint(nextIndex); planarFigure->ResetPreviewContolPoint(); } // Re-evaluate features planarFigure->EvaluateFeatures(); // this->LogPrintPlanarFigureQuantities( planarFigure ); // Update rendered scene - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PlanarFigureInteractor::AddInitialPoint(StateMachineAction *, InteractionEvent *interactionEvent) { const mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); auto *planarFigureGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); // Invoke event to notify listeners that placement of this PF starts now planarFigure->InvokeEvent(StartPlacementPlanarFigureEvent()); // Use PlaneGeometry of the renderer clicked on for this PlanarFigure auto *planeGeometry = const_cast( dynamic_cast(renderer->GetSliceNavigationController()->GetCurrentPlaneGeometry())); if (planeGeometry != nullptr && abstractTransformGeometry == nullptr) { planarFigureGeometry = planeGeometry; planarFigure->SetPlaneGeometry(planeGeometry); } else { return; } // Extract point in 2D world coordinates (relative to PlaneGeometry of // PlanarFigure) Point2D point2D; if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D)) { return; } // Place PlanarFigure at this point planarFigure->PlaceFigure(point2D); // Re-evaluate features planarFigure->EvaluateFeatures(); // this->LogPrintPlanarFigureQuantities( planarFigure ); // Set a bool property indicating that the figure has been placed in // the current RenderWindow. This is required so that the same render // window can be re-aligned to the PlaneGeometry of the PlanarFigure later // on in an application. GetDataNode()->SetBoolProperty("PlanarFigureInitializedWindow", true, renderer); // Update rendered scene - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PlanarFigureInteractor::StartHovering(StateMachineAction *, InteractionEvent *interactionEvent) { const mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); - const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); if (!m_IsHovering) { // Invoke hover event once when the mouse is entering the figure area m_IsHovering = true; planarFigure->InvokeEvent(StartHoverPlanarFigureEvent()); // Set bool property to indicate that planar figure is currently in "hovering" mode GetDataNode()->SetBoolProperty("planarfigure.ishovering", true); - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::PlanarFigureInteractor::SetPreviewPointPosition(StateMachineAction *, InteractionEvent *interactionEvent) { const mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); planarFigure->DeselectControlPoint(); mitk::Point2D pointProjectedOntoLine = positionEvent->GetPointerPositionOnScreen(); bool selected(false); bool isExtendable(false); bool isEditable(true); GetDataNode()->GetBoolProperty("selected", selected); GetDataNode()->GetBoolProperty("planarfigure.isextendable", isExtendable); GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable); if (selected && isExtendable && isEditable) { renderer->DisplayToPlane(pointProjectedOntoLine, pointProjectedOntoLine); planarFigure->SetPreviewControlPoint(pointProjectedOntoLine); } - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::PlanarFigureInteractor::HideControlPoints(StateMachineAction *, InteractionEvent * /*interactionEvent*/) { GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", false); } void mitk::PlanarFigureInteractor::HidePreviewPoint(StateMachineAction *, InteractionEvent *interactionEvent) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->ResetPreviewContolPoint(); - - const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); } bool mitk::PlanarFigureInteractor::CheckFigureHovering(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const mitk::PlaneGeometry *planarFigureGeometry = planarFigure->GetPlaneGeometry(); auto *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry(); if (abstractTransformGeometry != nullptr) return false; mitk::Point2D pointProjectedOntoLine; int previousControlPoint = this->IsPositionOverFigure( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, pointProjectedOntoLine); bool isHovering = (previousControlPoint != -1); if (isHovering) { return true; } else { return false; } return false; } bool mitk::PlanarFigureInteractor::CheckControlPointHovering(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const mitk::PlaneGeometry *planarFigureGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry(); if (abstractTransformGeometry != nullptr) return false; int pointIndex = -1; pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer); if (pointIndex >= 0) { return true; } else { return false; } } bool mitk::PlanarFigureInteractor::CheckSelection(const InteractionEvent * /*interactionEvent*/) { bool selected = false; GetDataNode()->GetBoolProperty("selected", selected); return selected; } void mitk::PlanarFigureInteractor::SelectFigure(StateMachineAction *, InteractionEvent * /*interactionEvent*/) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); planarFigure->InvokeEvent(SelectPlanarFigureEvent()); } void mitk::PlanarFigureInteractor::SelectPoint(StateMachineAction *, InteractionEvent *interactionEvent) { const mitk::InteractionPositionEvent *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return; auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const mitk::PlaneGeometry *planarFigureGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const PlaneGeometry *projectionPlane = renderer->GetCurrentWorldPlaneGeometry(); if (abstractTransformGeometry != nullptr) return; const int pointIndex = mitk::PlanarFigureInteractor::IsPositionInsideMarker( positionEvent, planarFigure, planarFigureGeometry, projectionPlane, renderer); if (pointIndex >= 0) { // If mouse is above control point, mark it as selected planarFigure->SelectControlPoint(pointIndex); } else { planarFigure->DeselectControlPoint(); } } bool mitk::PlanarFigureInteractor::CheckPointValidity(const InteractionEvent *interactionEvent) { // Check if the distance of the current point to the previously set point in display coordinates // is sufficient (if a previous point exists) // Extract display position const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); m_LastPointWasValid = IsMousePositionAcceptableAsNewControlPoint(positionEvent, planarFigure); return m_LastPointWasValid; } void mitk::PlanarFigureInteractor::RemoveSelectedPoint(StateMachineAction *, InteractionEvent *interactionEvent) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); mitk::BaseRenderer *renderer = interactionEvent->GetSender(); const int selectedControlPoint = planarFigure->GetSelectedControlPoint(); planarFigure->RemoveControlPoint(selectedControlPoint); // Re-evaluate features planarFigure->EvaluateFeatures(); planarFigure->Modified(); GetDataNode()->SetBoolProperty("planarfigure.drawcontrolpoints", true); planarFigure->InvokeEvent(EndInteractionPlanarFigureEvent()); - renderer->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); HandleEvent(mitk::InternalEvent::New(renderer, this, "Dummy-Event"), GetDataNode()); } void mitk::PlanarFigureInteractor::RequestContextMenu(StateMachineAction *, InteractionEvent * /*interactionEvent*/) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); bool selected = false; GetDataNode()->GetBoolProperty("selected", selected); // no need to invoke this if the figure is already selected if (!selected) { planarFigure->InvokeEvent(SelectPlanarFigureEvent()); } planarFigure->InvokeEvent(ContextMenuPlanarFigureEvent()); } bool mitk::PlanarFigureInteractor::CheckResetOnPointSelect(const InteractionEvent * /*interactionEvent*/) { auto *planarFigure = dynamic_cast(GetDataNode()->GetData()); bool isEditable = true; GetDataNode()->GetBoolProperty("planarfigure.iseditable", isEditable); // Reset the PlanarFigure if required return isEditable && planarFigure->ResetOnPointSelectNeeded(); } bool mitk::PlanarFigureInteractor::CheckFigureOnRenderingGeometry(const InteractionEvent *interactionEvent) { const auto *posEvent = dynamic_cast(interactionEvent); if (posEvent == nullptr) return false; const mitk::Point3D worldPoint3D = posEvent->GetPositionInWorld(); const mitk::PlanarFigure *planarFigure = dynamic_cast(GetDataNode()->GetData()); const mitk::PlaneGeometry *planarFigurePlaneGeometry = dynamic_cast(planarFigure->GetGeometry(0)); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(0)); if (abstractTransformGeometry != nullptr) return false; const double planeThickness = planarFigurePlaneGeometry->GetExtentInMM(2); if (planarFigurePlaneGeometry->Distance(worldPoint3D) > planeThickness) { // don't react, when interaction is too far away return false; } return true; } void mitk::PlanarFigureInteractor::SetPrecision(mitk::ScalarType precision) { m_Precision = precision; } void mitk::PlanarFigureInteractor::SetMinimumPointDistance(ScalarType minimumDistance) { m_MinimumPointDistance = minimumDistance; } bool mitk::PlanarFigureInteractor::TransformPositionEventToPoint2D(const InteractionPositionEvent *positionEvent, const PlaneGeometry *planarFigureGeometry, Point2D &point2D) { const mitk::Point3D worldPoint3D = positionEvent->GetPositionInWorld(); // TODO: proper handling of distance tolerance if (planarFigureGeometry->Distance(worldPoint3D) > 0.1) { return false; } // Project point onto plane of this PlanarFigure planarFigureGeometry->Map(worldPoint3D, point2D); return true; } bool mitk::PlanarFigureInteractor::TransformObjectToDisplay(const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::PlaneGeometry *objectGeometry, const mitk::PlaneGeometry *rendererGeometry, const mitk::BaseRenderer *renderer) const { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map(point2D, point3D); const double planeThickness = objectGeometry->GetExtentInMM(2); // TODO: proper handling of distance tolerance if (rendererGeometry->Distance(point3D) < planeThickness / 3.0) { // Project 3D world point onto display geometry renderer->WorldToDisplay(point3D, displayPoint); return true; } return false; } bool mitk::PlanarFigureInteractor::IsPointNearLine(const mitk::Point2D &point, const mitk::Point2D &startPoint, const mitk::Point2D &endPoint, mitk::Point2D &projectedPoint) const { mitk::Vector2D n1 = endPoint - startPoint; n1.Normalize(); // Determine dot products between line vector and startpoint-point / endpoint-point vectors const double l1 = n1 * (point - startPoint); const double l2 = -n1 * (point - endPoint); // Determine projection of specified point onto line defined by start / end point const mitk::Point2D crossPoint = startPoint + n1 * l1; projectedPoint = crossPoint; const float dist1 = crossPoint.SquaredEuclideanDistanceTo(point); const float dist2 = endPoint.SquaredEuclideanDistanceTo(point); const float dist3 = startPoint.SquaredEuclideanDistanceTo(point); // Point is inside encompassing rectangle IF // - its distance to its projected point is small enough // - it is not further outside of the line than the defined tolerance if (((dist1 < 20.0) && (l1 > 0.0) && (l2 > 0.0)) || dist2 < 20.0 || dist3 < 20.0) { return true; } return false; } int mitk::PlanarFigureInteractor::IsPositionOverFigure(const InteractionPositionEvent *positionEvent, PlanarFigure *planarFigure, const PlaneGeometry *planarFigureGeometry, const PlaneGeometry *rendererGeometry, Point2D &pointProjectedOntoLine) const { mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen(); // Iterate over all polylines of planar figure, and check if // any one is close to the current display position typedef mitk::PlanarFigure::PolyLineType VertexContainerType; Point2D polyLinePoint; Point2D firstPolyLinePoint; Point2D previousPolyLinePoint; for (unsigned short loop = 0; loop < planarFigure->GetPolyLinesSize(); ++loop) { const VertexContainerType polyLine = planarFigure->GetPolyLine(loop); bool firstPoint(true); for (auto it = polyLine.begin(); it != polyLine.end(); ++it) { // Get plane coordinates of this point of polyline (if possible) if (!this->TransformObjectToDisplay( *it, polyLinePoint, planarFigureGeometry, rendererGeometry, positionEvent->GetSender())) { break; // Poly line invalid (not on current 2D plane) --> skip it } if (firstPoint) { firstPolyLinePoint = polyLinePoint; firstPoint = false; } else if (this->IsPointNearLine(displayPosition, previousPolyLinePoint, polyLinePoint, pointProjectedOntoLine)) { // Point is close enough to line segment --> Return index of the segment return std::distance(polyLine.begin(), it); } previousPolyLinePoint = polyLinePoint; } // For closed figures, also check last line segment if (planarFigure->IsClosed() && this->IsPointNearLine(displayPosition, polyLinePoint, firstPolyLinePoint, pointProjectedOntoLine)) { return 0; // Return index of first control point } } return -1; } int mitk::PlanarFigureInteractor::IsPositionInsideMarker(const InteractionPositionEvent *positionEvent, const PlanarFigure *planarFigure, const PlaneGeometry *planarFigureGeometry, const PlaneGeometry *rendererGeometry, const BaseRenderer *renderer) const { const mitk::Point2D displayPosition = positionEvent->GetPointerPositionOnScreen(); // Iterate over all control points of planar figure, and check if // any one is close to the current display position mitk::Point2D displayControlPoint; const int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); for (int i = 0; i < numberOfControlPoints; i++) { if (this->TransformObjectToDisplay( planarFigure->GetControlPoint(i), displayControlPoint, planarFigureGeometry, rendererGeometry, renderer)) { // TODO: variable size of markers if (displayPosition.SquaredEuclideanDistanceTo(displayControlPoint) < 20.0) { return i; } } } return -1; } void mitk::PlanarFigureInteractor::LogPrintPlanarFigureQuantities(const PlanarFigure *planarFigure) { MITK_INFO << "PlanarFigure: " << planarFigure->GetNameOfClass(); for (unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i) { MITK_INFO << "* " << planarFigure->GetFeatureName(i) << ": " << planarFigure->GetQuantity(i) << " " << planarFigure->GetFeatureUnit(i); } } bool mitk::PlanarFigureInteractor::IsMousePositionAcceptableAsNewControlPoint( const mitk::InteractionPositionEvent *positionEvent, const PlanarFigure *planarFigure) { assert(positionEvent && planarFigure); const BaseRenderer *renderer = positionEvent->GetSender(); assert(renderer); // Get the timestep to support 3D+t const int timeStep(renderer->GetTimeStep(planarFigure)); bool tooClose(false); const mitk::PlaneGeometry *planarFigureGeometry = dynamic_cast(planarFigure->GetGeometry(timeStep)); const mitk::AbstractTransformGeometry *abstractTransformGeometry = dynamic_cast(planarFigure->GetGeometry(timeStep)); if (abstractTransformGeometry != nullptr) return false; Point2D point2D; // Get the point2D from the positionEvent if (!this->TransformPositionEventToPoint2D(positionEvent, planarFigureGeometry, point2D)) { return false; } // apply the controlPoint constraints of the planarFigure to get the // coordinates that would actually be used. const Point2D correctedPoint = const_cast(planarFigure)->ApplyControlPointConstraints(0, point2D); // map the 2D coordinates of the new point to world-coordinates // and transform those to display-coordinates mitk::Point3D newPoint3D; planarFigureGeometry->Map(correctedPoint, newPoint3D); mitk::Point2D newDisplayPosition; renderer->WorldToDisplay(newPoint3D, newDisplayPosition); const int selectedControlPoint = planarFigure->GetSelectedControlPoint(); for (int i = 0; i < (int)planarFigure->GetNumberOfControlPoints(); ++i) { if (i != selectedControlPoint) { // Try to convert previous point to current display coordinates mitk::Point3D previousPoint3D; // map the 2D coordinates of the control-point to world-coordinates planarFigureGeometry->Map(planarFigure->GetControlPoint(i), previousPoint3D); if (renderer->GetCurrentWorldPlaneGeometry()->Distance(previousPoint3D) < 0.1) // ugly, but assert makes this work { mitk::Point2D previousDisplayPosition; // transform the world-coordinates into display-coordinates renderer->WorldToDisplay(previousPoint3D, previousDisplayPosition); // Calculate the distance. We use display-coordinates here to make // the check independent of the zoom-level of the rendering scene. const double a = newDisplayPosition[0] - previousDisplayPosition[0]; const double b = newDisplayPosition[1] - previousDisplayPosition[1]; // If point is to close, do not set a new point tooClose = (a * a + b * b < m_MinimumPointDistance); } if (tooClose) return false; // abort loop early } } return !tooClose; // default } void mitk::PlanarFigureInteractor::ConfigurationChanged() { const mitk::PropertyList::Pointer properties = GetAttributes(); std::string precision = ""; if (properties->GetStringProperty("precision", precision)) { m_Precision = atof(precision.c_str()); } else { m_Precision = (ScalarType)6.5; } std::string minPointDistance = ""; if (properties->GetStringProperty("minPointDistance", minPointDistance)) { m_MinimumPointDistance = atof(minPointDistance.c_str()); } else { m_MinimumPointDistance = (ScalarType)25.0; } } diff --git a/Modules/QtOverlays/QmitkOverlayController.cpp b/Modules/QtOverlays/QmitkOverlayController.cpp index f41e0314d7..44d005a6e6 100644 --- a/Modules/QtOverlays/QmitkOverlayController.cpp +++ b/Modules/QtOverlays/QmitkOverlayController.cpp @@ -1,498 +1,498 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkOverlayController.h" #include "QmitkOverlay.h" #include "QmitkOverlayContainerWidget.h" #include "QmitkRenderWindow.h" #include #include #include QmitkOverlayController::QmitkOverlayController(QmitkRenderWindow *rw, mitk::PropertyList *pl) : QObject(), m_RenderWindow(rw), m_PropertyList(pl) { if (m_RenderWindow == nullptr) { MITK_ERROR << "invalid QmitkRenderWindow"; return; } connect(rw, SIGNAL(moved()), this, SLOT(AdjustAllOverlayPosition())); this->InitializeOverlayLayout(); this->AdjustAllOverlayPosition(); this->SetOverlayVisibility(true); if (m_PropertyList.IsNull()) m_PropertyList = mitk::PropertyList::New(); } QmitkOverlayController::~QmitkOverlayController() { } void QmitkOverlayController::InitializeOverlayLayout() { // setup widget for each position this->InitializeWidget(QmitkOverlay::top_Left); this->InitializeWidget(QmitkOverlay::top_Center); this->InitializeWidget(QmitkOverlay::top_Right); this->InitializeWidget(QmitkOverlay::middle_Left); this->InitializeWidget(QmitkOverlay::middle_Right); this->InitializeWidget(QmitkOverlay::bottom_Left); this->InitializeWidget(QmitkOverlay::bottom_Center); this->InitializeWidget(QmitkOverlay::bottom_Right); } void QmitkOverlayController::InitializeWidget(QmitkOverlay::DisplayPosition pos) { // create a new QWidget as Tool & FramelessWindowHint m_PositionedOverlays[pos] = new QmitkOverlayContainerWidget(m_RenderWindow, Qt::Tool | Qt::FramelessWindowHint); // autoFillBackGround(false) and WA_TranslucentBackground = true are needed to have a translucent background // transparency does NOT work under Win-XP 32-Bit --> paint black background #if !defined(_WIN32) || defined(_WIN64) m_PositionedOverlays[pos]->setAttribute(Qt::WA_TranslucentBackground, true); #else m_PositionedOverlays[pos]->setStyleSheet("QWidget { background: black }"); m_PositionedOverlays[pos]->setAttribute(Qt::WA_TranslucentBackground, false); #endif // X11 specific attributes m_PositionedOverlays[pos]->setAttribute(Qt::WA_X11NetWmWindowTypeUtility, true); // mac-specific attributes: // making sure overlays are even visible if RenderWindow does not have the focus (not default for Qt::Tool on mac) m_PositionedOverlays[pos]->setAttribute(Qt::WA_MacAlwaysShowToolWindow, true); // testing something m_PositionedOverlays[pos]->setAttribute(Qt::WA_MacShowFocusRect, false); // overlays should not get the focus m_PositionedOverlays[pos]->setFocusPolicy(Qt::NoFocus); // setting the color of the background to transparent - not sure it's needed after the attributes have been set above QPalette p = QPalette(); p.setColor(QPalette::Window, Qt::transparent); m_PositionedOverlays[pos]->setPalette(p); // setting position-specific properties switch (pos) { case QmitkOverlay::top_Left: { // adding left-aligned top-to-bottom layout QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::TopToBottom); layout->setAlignment(Qt::AlignLeft); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } case QmitkOverlay::top_Center: { // adding center-aligned top-to-bottom layout QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::TopToBottom); layout->setAlignment(Qt::AlignCenter); layout->setAlignment(Qt::AlignLeft); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } case QmitkOverlay::top_Right: { // adding right-aligned top-to-bottom layout QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::TopToBottom); layout->setAlignment(Qt::AlignRight); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } case QmitkOverlay::middle_Left: { // adding left-aligned left-to-right layout QHBoxLayout *layout = new QHBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::LeftToRight); layout->setAlignment(Qt::AlignLeft); layout->setSpacing(3); break; } case QmitkOverlay::middle_Right: { // adding right-aligned right-to-left layout QHBoxLayout *layout = new QHBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::RightToLeft); layout->setAlignment(Qt::AlignRight); layout->setSpacing(3); break; } case QmitkOverlay::bottom_Left: { // adding left-aligned bottom-to-top layout QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::BottomToTop); layout->setAlignment(Qt::AlignLeft); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } case QmitkOverlay::bottom_Center: { QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::BottomToTop); layout->setAlignment(Qt::AlignCenter); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } case QmitkOverlay::bottom_Right: { QVBoxLayout *layout = new QVBoxLayout(m_PositionedOverlays[pos]); layout->setDirection(QBoxLayout::BottomToTop); layout->setAlignment(Qt::AlignRight); m_PositionedOverlays[pos]->layout()->setSpacing(0); break; } } } void QmitkOverlayController::AdjustAllOverlayPosition() { AdjustOverlayPosition(QmitkOverlay::top_Left); AdjustOverlayPosition(QmitkOverlay::top_Center); AdjustOverlayPosition(QmitkOverlay::top_Right); AdjustOverlayPosition(QmitkOverlay::middle_Left); AdjustOverlayPosition(QmitkOverlay::middle_Right); AdjustOverlayPosition(QmitkOverlay::bottom_Left); AdjustOverlayPosition(QmitkOverlay::bottom_Center); AdjustOverlayPosition(QmitkOverlay::bottom_Right); } void QmitkOverlayController::AdjustOverlayPosition(QmitkOverlay::DisplayPosition displayPosition) { QWidget *widget = m_PositionedOverlays[displayPosition]; QSize size = GetMinimumSizeForWidget(displayPosition); QPoint pos; switch (displayPosition) { case QmitkOverlay::top_Left: { // setting position of top-left overlay-container pos = m_RenderWindow->mapToGlobal(QPoint(0, 0)); m_PositionedOverlays[QmitkOverlay::top_Left]->move(pos.x(), pos.y()); break; } case QmitkOverlay::top_Center: { // setting position of top-center overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(m_RenderWindow->size().width() / 2, 0)); widget->move(pos.x() - widget->size().width() / 2, pos.y()); break; } case QmitkOverlay::top_Right: { // setting position of top-right overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(m_RenderWindow->size().width(), 0)); widget->move(pos.x() - widget->size().width(), pos.y()); break; } case QmitkOverlay::middle_Left: { // setting position of middle-left overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(0, m_RenderWindow->size().height() / 2)); widget->move(pos.x(), pos.y() - widget->size().height() / 2); break; } case QmitkOverlay::middle_Right: { // setting position of middle-right overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(m_RenderWindow->size().width(), m_RenderWindow->size().height() / 2)); widget->move(pos.x() - widget->size().width(), pos.y() - widget->size().height() / 2); break; } case QmitkOverlay::bottom_Left: { // setting position of bottom-left overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(0, m_RenderWindow->size().height())); widget->move(pos.x(), pos.y() - widget->size().height()); break; } case QmitkOverlay::bottom_Center: { // setting position of bottom-center overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(m_RenderWindow->size().width() / 2, m_RenderWindow->size().height())); widget->move(pos.x() - widget->size().width() / 2, pos.y() - widget->size().height()); break; } case QmitkOverlay::bottom_Right: { // setting position of bottom-right overlay-container widget->setFixedWidth(std::max(widget->width(), size.width() * 2)); pos = m_RenderWindow->mapToGlobal(QPoint(m_RenderWindow->size().width(), m_RenderWindow->size().height())); widget->move(pos.x() - widget->size().width(), pos.y() - widget->size().height()); break; } } } void QmitkOverlayController::SetOverlayVisibility(bool visible) { OverlayPositionMap::iterator overlayIter; for (overlayIter = m_PositionedOverlays.begin(); overlayIter != m_PositionedOverlays.end(); overlayIter++) { if (visible) { (overlayIter->second)->show(); } else { (overlayIter->second)->hide(); } } OverlayVector::iterator allOverlaysIter; for (allOverlaysIter = m_AllOverlays.begin(); allOverlaysIter != m_AllOverlays.end(); allOverlaysIter++) { if (visible) { (*allOverlaysIter)->GetWidget()->show(); } else { (*allOverlaysIter)->GetWidget()->hide(); } } } void QmitkOverlayController::AddOverlay(QmitkOverlay *overlay) { // if no renderwindow has been set, it's not possible to add overlays... if (m_RenderWindow == nullptr) { MITK_ERROR << "invalid QmitkRenderWindow"; return; } if (overlay != nullptr) { // get desired position and layer of the overlay QmitkOverlay::DisplayPosition pos = overlay->GetPosition(); // concatenate local propertyList and propertyList of the RenderingManager // local properties have priority as they are not overwritten if preset in both - m_PropertyList->ConcatenatePropertyList(m_RenderWindow->GetRenderer()->GetRenderingManager()->GetPropertyList(), + m_PropertyList->ConcatenatePropertyList(mitk::RenderingManager::GetInstance()->GetPropertyList(), false); // add the overlay to the OverlayContainer in the RenderWindow ... overlay->GetWidget()->setParent(m_PositionedOverlays[pos]); // ... and set it up with the correct properties this->UpdateOverlayData(overlay); // add overlay to list of all overlays and correctly put it into the layering m_AllOverlays.push_back(overlay); this->RestackOverlays(pos); // ... and reset the position of the widgets this->AdjustOverlayPosition(pos); } } void QmitkOverlayController::UpdateOverlayData(QmitkOverlay *overlay) { if (overlay != nullptr) { overlay->GenerateData(m_PropertyList); AdjustOverlayPosition(overlay->GetPosition()); } } void QmitkOverlayController::RemoveAllOverlays() { foreach (QmitkOverlay *overlay, m_AllOverlays) { overlay->GetWidget()->setParent(nullptr); overlay->GetWidget()->hide(); overlay->deleteLater(); } m_AllOverlays.clear(); } void QmitkOverlayController::RemoveOverlay(QmitkOverlay *overlay) { if (overlay != nullptr) { // get desired position and layer of the overlay QmitkOverlay::DisplayPosition pos = overlay->GetPosition(); OverlayVector::iterator iter = std::find(m_AllOverlays.begin(), m_AllOverlays.end(), overlay); if (iter != m_AllOverlays.end()) { m_AllOverlays.erase(iter); overlay->GetWidget()->setParent(nullptr); overlay->GetWidget()->hide(); if (m_PositionedOverlays[pos]->layout()->isEmpty()) { m_PositionedOverlays[pos]->hide(); } else { this->RestackOverlays(pos); // reset the position of the widgets this->AdjustOverlayPosition(pos); } } overlay->deleteLater(); } } void QmitkOverlayController::AlignOverlays() { // OverlayVector::iterator overlayIter; // for ( overlayIter=m_AllOverlays.begin(); overlayIter!=m_AllOverlays.end(); overlayIter++ ) //{ // int stackLayer = dynamic_cast( m_PositionedOverlays[ (*overlayIter)->GetPosition() ]->layout() // )->isEmpty() ? 0 : layer; // dynamic_cast( m_PositionedOverlays[ (*overlayIter)->GetPosition() ]->layout() )->addWidget( // (*overlayIter)->GetWidget(), stackLayer, Qt::AlignLeft ); //} } void QmitkOverlayController::RestackOverlays(QmitkOverlay::DisplayPosition pos) { OverlayVector::iterator overlayIter; QBoxLayout *layout = dynamic_cast(m_PositionedOverlays[pos]->layout()); std::sort(m_AllOverlays.begin(), m_AllOverlays.end()); for (overlayIter = m_AllOverlays.begin(); overlayIter != m_AllOverlays.end(); overlayIter++) { // do nothing if the overlay is not in the right position if ((*overlayIter)->GetPosition() != pos) { continue; } // determine the desired stacking layer // if the overlay-container is empty, simply append the overlay to the list // if it's not empty, use the layer of the overlay unsigned int layer = (*overlayIter)->GetLayer(); int stackLayer = 0; if (!layout->isEmpty()) { stackLayer = layer; } switch (pos) { // same alignment for all lefts, ... case QmitkOverlay::top_Left: { } case QmitkOverlay::middle_Left: { } case QmitkOverlay::bottom_Left: { layout->insertWidget(stackLayer, (*overlayIter)->GetWidget(), 0, Qt::AlignLeft); break; } // ... for all centers, ... case QmitkOverlay::top_Center: { } case QmitkOverlay::bottom_Center: { layout->insertWidget(stackLayer, (*overlayIter)->GetWidget(), 0, Qt::AlignCenter); break; } // ... and for all rights case QmitkOverlay::top_Right: { } case QmitkOverlay::middle_Right: { } case QmitkOverlay::bottom_Right: { layout->insertWidget(stackLayer, (*overlayIter)->GetWidget(), 0, Qt::AlignRight); break; } } } } void QmitkOverlayController::UpdateAllOverlays() { foreach (QmitkOverlay *overlay, m_AllOverlays) { this->UpdateOverlayData(overlay); } } QSize QmitkOverlayController::GetMinimumSizeForWidget(QmitkOverlay::DisplayPosition displayPosition) { int width = 0; int height = 0; foreach (QmitkOverlay *overlay, m_AllOverlays) { if (overlay->GetPosition() == displayPosition) { QSize overlaySize = overlay->GetNeededSize(); width = std::max(width, overlaySize.width()); height = std::max(height, overlaySize.height()); } } QSize result(width, height); return result; } diff --git a/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h index afe4f0af85..aca87a3731 100644 --- a/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkAbstractMultiWidget.h @@ -1,167 +1,162 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKABSTRACTMULTIWIDGET_H #define QMITKABSTRACTMULTIWIDGET_H // mitk qt widgets module #include "MitkQtWidgetsExports.h" // mitk core #include #include #include // qt #include // c++ #include #include class QmitkMultiWidgetLayoutManager; class QmitkRenderWindow; class QmitkRenderWindowWidget; namespace mitk { class DataStorage; class InteractionEventHandler; - class RenderingManager; } /** * @brief The 'QmitkAbstractMultiWidget' is a 'QWidget' that can be subclassed to display multiple render windows at once. * Render windows can dynamically be added and removed to change the layout of the multi widget. * A subclass of this multi widget can be used inside a 'QmitkAbstractMultiWidgetEditor'. * * The class uses the 'DisplayActionEventBroadcast' and 'DisplayActionEventHandler' classes to * load a state machine and set an event configuration. * * Using the 'Synchronize' function the user can enable or disable the synchronization of display action events. * See 'DisplayActionEventFunctions'-class for the different synchronized and non-synchronized functions used. */ class MITKQTWIDGETS_EXPORT QmitkAbstractMultiWidget : public QWidget { Q_OBJECT public: using RenderWindowWidgetPointer = std::shared_ptr; using RenderWindowWidgetMap = std::map>; using RenderWindowHash = QHash; using ViewDirection = mitk::BaseRenderer::ViewDirection; QmitkAbstractMultiWidget(QWidget* parent = 0, Qt::WindowFlags f = 0, - mitk::RenderingManager* renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing, const QString& multiWidgetName = "multiwidget"); virtual ~QmitkAbstractMultiWidget(); virtual void InitializeMultiWidget() = 0; virtual void MultiWidgetOpened() { } virtual void MultiWidgetClosed() { } virtual void SetDataStorage(mitk::DataStorage* dataStorage); mitk::DataStorage* GetDataStorage() const; - mitk::RenderingManager* GetRenderingManager() const; - int GetRowCount() const; int GetColumnCount() const; virtual void SetLayout(int row, int column); virtual void Synchronize(bool synchronized); virtual void SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme); mitk::InteractionEventHandler* GetInteractionEventHandler(); RenderWindowWidgetMap GetRenderWindowWidgets() const; RenderWindowWidgetMap Get2DRenderWindowWidgets() const; RenderWindowWidgetMap Get3DRenderWindowWidgets() const; RenderWindowWidgetPointer GetRenderWindowWidget(int row, int column) const; RenderWindowWidgetPointer GetRenderWindowWidget(const QString& widgetName) const; RenderWindowWidgetPointer GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const; RenderWindowHash GetRenderWindows() const; QmitkRenderWindow* GetRenderWindow(int row, int column) const; virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const; virtual QmitkRenderWindow* GetRenderWindow(const ViewDirection& viewDirection) const = 0; virtual void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget); RenderWindowWidgetPointer GetActiveRenderWindowWidget() const; RenderWindowWidgetPointer GetFirstRenderWindowWidget() const; RenderWindowWidgetPointer GetLastRenderWindowWidget() const; virtual QString GetNameFromIndex(int row, int column) const; virtual QString GetNameFromIndex(size_t index) const; unsigned int GetNumberOfRenderWindowWidgets() const; void RequestUpdate(const QString& widgetName); void RequestUpdateAll(); void ForceImmediateUpdate(const QString& widgetName); void ForceImmediateUpdateAll(); virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) = 0; virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const = 0; virtual void SetCrosshairVisibility(bool visible) = 0; virtual bool GetCrosshairVisibility() const = 0; virtual void ResetCrosshair() = 0; virtual void SetWidgetPlaneMode(int mode) = 0; virtual void ActivateMenuWidget(bool state); virtual bool IsMenuWidgetEnabled() const; QmitkMultiWidgetLayoutManager* GetMultiWidgetLayoutManager() const; Q_SIGNALS: void ActiveRenderWindowChanged(); protected: virtual void AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget); virtual void RemoveRenderWindowWidget(); private: /** * @brief This function will be called by the function 'SetLayout' and * can be implemented and customized in the subclasses. */ virtual void SetLayoutImpl() = 0; /** * @brief This function will be called by the function 'Synchronize' and * can be implemented and customized in the subclasses. */ virtual void SynchronizeImpl() = 0; /** * @brief This function will be called by the function 'SetInteractionScheme' and * can be implemented and customized in the subclasses. */ virtual void SetInteractionSchemeImpl() = 0; struct Impl; std::unique_ptr m_Impl; }; #endif // QMITKABSTRACTMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h index 23292859c5..7743460254 100644 --- a/Modules/QtWidgets/include/QmitkMxNMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkMxNMultiWidget.h @@ -1,87 +1,85 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKMXNMULTIWIDGET_H #define QMITKMXNMULTIWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkAbstractMultiWidget.h" /** * @brief The 'QmitkMxNMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. * Render windows can dynamically be added and removed to change the layout of the multi widget. This * is done by using the 'SetLayout'-function to define a layout. This will automatically add or remove * the appropriate number of render window widgets. */ class MITKQTWIDGETS_EXPORT QmitkMxNMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: QmitkMxNMultiWidget(QWidget* parent = nullptr, Qt::WindowFlags f = 0, - mitk::RenderingManager* renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing, const QString& multiWidgetName = "mxnmulti"); ~QmitkMxNMultiWidget() = default; void InitializeMultiWidget() override; void MultiWidgetOpened() override; void MultiWidgetClosed() override; QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; QmitkRenderWindow* GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const override; void SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) override; void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; void SetCrosshairVisibility(bool activate) override; bool GetCrosshairVisibility() const override { return m_CrosshairVisibility; } void ResetCrosshair() override; void SetWidgetPlaneMode(int userMode) override; public Q_SLOTS: // mouse events void wheelEvent(QWheelEvent* e) override; void mousePressEvent(QMouseEvent* e) override; void moveEvent(QMoveEvent* e) override; Q_SIGNALS: void WheelMoved(QWheelEvent *); void Moved(); private: void SetLayoutImpl() override; void SynchronizeImpl() override { } void SetInteractionSchemeImpl() override { } void CreateRenderWindowWidget(); bool m_CrosshairVisibility; }; #endif // QMITKMXNMULTIWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindow.h b/Modules/QtWidgets/include/QmitkRenderWindow.h index 5727026f9a..d963134579 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindow.h +++ b/Modules/QtWidgets/include/QmitkRenderWindow.h @@ -1,170 +1,168 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOW_H #define QMITKRENDERWINDOW_H #include "mitkRenderWindowBase.h" #include "QmitkRenderWindowMenu.h" #include #include #include #include "mitkBaseRenderer.h" #include "mitkInteractionEventConst.h" class QDragEnterEvent; class QDropEvent; class QInputEvent; /** * \ingroup QmitkModule * \brief MITK implementation of the QVTKWidget */ class MITKQTWIDGETS_EXPORT QmitkRenderWindow : public QVTKOpenGLWidget, public mitk::RenderWindowBase { Q_OBJECT public: QmitkRenderWindow( QWidget *parent = nullptr, const QString &name = "unnamed renderwindow", - mitk::VtkPropRenderer *renderer = nullptr, - mitk::RenderingManager *renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing); + mitk::VtkPropRenderer *renderer = nullptr); ~QmitkRenderWindow() override; /** * \brief Whether Qt events should be passed to parent (default: true) * * With introduction of the QVTKWidget the behaviour regarding Qt events changed. * QVTKWidget "accepts" Qt events like mouse clicks (i.e. set an "accepted" flag). * When this flag is set, Qt fininshed handling of this event -- otherwise it is * reached through to the widget's parent. * * This reaching through to the parent was implicitly required by QmitkMaterialWidget / QmitkMaterialShowCase. * * The default behaviour of QmitkRenderWindow is now to clear the "accepted" flag * of Qt events after they were handled by QVTKWidget. This way parents can also * handle events. * * If you don't want this behaviour, call SetResendQtEvents(true) on your render window. */ virtual void SetResendQtEvents(bool resend); // Set Layout Index to define the Layout Type void SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex); // Get Layout Index to define the Layout Type QmitkRenderWindowMenu::LayoutIndex GetLayoutIndex(); // MenuWidget need to update the Layout Design List when Layout had changed void LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign); // Activate or Deactivate MenuWidget. void ActivateMenuWidget(bool state); bool GetActivateMenuWidgetFlag() { return m_MenuWidgetActivated; } // Get it from the QVTKWidget parent vtkRenderWindow *GetVtkRenderWindow() override { return GetRenderWindow(); } vtkRenderWindowInteractor *GetVtkRenderWindowInteractor() override { return nullptr; } protected: // overloaded move handler void moveEvent(QMoveEvent *event) override; // overloaded show handler void showEvent(QShowEvent *event) override; // overloaded mouse press handler void mousePressEvent(QMouseEvent *event) override; // overloaded mouse double-click handler void mouseDoubleClickEvent(QMouseEvent *event) override; // overloaded mouse move handler void mouseMoveEvent(QMouseEvent *event) override; // overloaded mouse release handler void mouseReleaseEvent(QMouseEvent *event) override; // overloaded key press handler void keyPressEvent(QKeyEvent *event) override; // overloaded enter handler void enterEvent(QEvent *) override; // overloaded leave handler void leaveEvent(QEvent *) override; // Overloaded resize handler, see decs in QVTKOpenGLWidget. // Basically, we have to ensure the VTK rendering is updated for each change in window size. - void resizeGL(int w, int h) Q_DECL_OVERRIDE; + void resizeGL(int w, int h) override; /// \brief Simply says we accept the event type. void dragEnterEvent(QDragEnterEvent *event) override; /// \brief If the dropped type is application/x-mitk-datanodes we process the request by converting to mitk::DataNode /// pointers and emitting the NodesDropped signal. void dropEvent(QDropEvent *event) override; #ifndef QT_NO_WHEELEVENT // overload wheel mouse event void wheelEvent(QWheelEvent *) override; #endif void AdjustRenderWindowMenuVisibility(const QPoint &pos); Q_SIGNALS: void LayoutDesignChanged(QmitkRenderWindowMenu::LayoutDesign); void ResetView(); void CrosshairRotationModeChanged(int); void CrosshairVisibilityChanged(bool); void moved(); /// \brief Emits a signal to say that this window has had the following nodes dropped on it. void NodesDropped(QmitkRenderWindow *thisWindow, std::vector nodes); private Q_SLOTS: void DeferredHideMenu(); private: // Helper Functions to Convert Qt-Events to Mitk-Events mitk::Point2D GetMousePosition(QMouseEvent *me) const; mitk::Point2D GetMousePosition(QWheelEvent *we) const; mitk::InteractionEvent::MouseButtons GetEventButton(QMouseEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QMouseEvent *me) const; mitk::InteractionEvent::ModifierKeys GetModifiers(QInputEvent *me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QWheelEvent *we) const; std::string GetKeyLetter(QKeyEvent *ke) const; int GetDelta(QWheelEvent *we) const; bool m_ResendQtEvents; QmitkRenderWindowMenu *m_MenuWidget; bool m_MenuWidgetActivated; QmitkRenderWindowMenu::LayoutIndex m_LayoutIndex; vtkSmartPointer m_InternalRenderWindow; }; #endif // QMITKRENDERWINDOW_H diff --git a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h index a91f8c73c6..20693ef65a 100644 --- a/Modules/QtWidgets/include/QmitkRenderWindowWidget.h +++ b/Modules/QtWidgets/include/QmitkRenderWindowWidget.h @@ -1,119 +1,114 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKRENDERWINDOWWIDGET_H #define QMITKRENDERWINDOWWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkRenderWindow.h" // mitk core #include #include #include // qt #include #include #include class vtkCornerAnnotation; /** * @brief The 'QmitkRenderWindowWidget' is a QFrame that holds a render window * and some associates properties, like a crosshair (pointset) and decorations. * Decorations are corner annotation (text and color), frame color or background color * and can be set using this class. * The 'QmitkRenderWindowWidget' is used inside a 'QmitkAbstractMultiWidget', where a map contains * several render window widgets to create the multi widget display. */ class MITKQTWIDGETS_EXPORT QmitkRenderWindowWidget : public QFrame { Q_OBJECT public: QmitkRenderWindowWidget( QWidget* parent = nullptr, const QString& widgetName = "", - mitk::DataStorage* dataStorage = nullptr, - mitk::RenderingManager* renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode::Type renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing - ); + mitk::DataStorage* dataStorage = nullptr); ~QmitkRenderWindowWidget() override; void SetDataStorage(mitk::DataStorage* dataStorage); const QString& GetWidgetName() const { return m_WidgetName; }; QmitkRenderWindow* GetRenderWindow() const { return m_RenderWindow; }; mitk::SliceNavigationController* GetSliceNavigationController() const; void RequestUpdate(); void ForceImmediateUpdate(); void SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower); void ShowGradientBackground(bool enable); std::pair GetGradientBackgroundColors() const { return m_GradientBackgroundColors; }; bool IsGradientBackgroundOn() const; void SetDecorationColor(const mitk::Color& color); mitk::Color GetDecorationColor() const { return m_DecorationColor; }; void ShowColoredRectangle(bool show); bool IsColoredRectangleVisible() const; void ShowCornerAnnotation(bool show); bool IsCornerAnnotationVisible() const; void SetCornerAnnotationText(const std::string& cornerAnnotation); std::string GetCornerAnnotationText() const; bool IsRenderWindowMenuActivated() const; void ActivateCrosshair(bool activate); Q_SIGNALS: void MouseEvent(QMouseEvent* e); private: void InitializeGUI(); void InitializeDecorations(); void SetCrosshair(mitk::Point3D selectedPoint); QString m_WidgetName; QHBoxLayout* m_Layout; mitk::DataStorage* m_DataStorage; - mitk::RenderingManager::Pointer m_RenderingManager; - mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; QmitkRenderWindow* m_RenderWindow; mitk::DataNode::Pointer m_PointSetNode; mitk::PointSet::Pointer m_PointSet; std::pair m_GradientBackgroundColors; mitk::Color m_DecorationColor; vtkSmartPointer m_CornerAnnotation; }; #endif // QMITKRENDERWINDOWWIDGET_H diff --git a/Modules/QtWidgets/include/QmitkStdMultiWidget.h b/Modules/QtWidgets/include/QmitkStdMultiWidget.h index 50776812cd..1a279fc9f4 100644 --- a/Modules/QtWidgets/include/QmitkStdMultiWidget.h +++ b/Modules/QtWidgets/include/QmitkStdMultiWidget.h @@ -1,165 +1,163 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKSTDMULTIWIDGET_H #define QMITKSTDMULTIWIDGET_H // qt widgets module #include "MitkQtWidgetsExports.h" #include "QmitkAbstractMultiWidget.h" /** * @brief The 'QmitkStdMultiWidget' is a 'QmitkAbstractMultiWidget' that is used to display multiple render windows at once. * Render windows are predefined in a 2x2 design with 3 different 2D view planes and a 3D render window. */ class MITKQTWIDGETS_EXPORT QmitkStdMultiWidget : public QmitkAbstractMultiWidget { Q_OBJECT public: QmitkStdMultiWidget( QWidget *parent = nullptr, Qt::WindowFlags f = nullptr, - mitk::RenderingManager *renderingManager = nullptr, - mitk::BaseRenderer::RenderingMode renderingMode = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing, const QString &name = "stdmulti"); ~QmitkStdMultiWidget() override; virtual void InitializeMultiWidget() override; virtual QmitkRenderWindow* GetRenderWindow(const QString& widgetName) const override; virtual QmitkRenderWindow* GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const override; virtual void SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) override; virtual const mitk::Point3D GetSelectedPosition(const QString& widgetName) const override; virtual void SetCrosshairVisibility(bool) override; virtual bool GetCrosshairVisibility() const override; virtual void ResetCrosshair() override; virtual void SetWidgetPlaneMode(int mode) override; mitk::SliceNavigationController* GetTimeNavigationController(); void AddPlanesToDataStorage(); void RemovePlanesFromDataStorage(); /** \brief Listener to the CrosshairPositionEvent Ensures the CrosshairPositionEvent is handled only once and at the end of the Qt-Event loop */ void HandleCrosshairPositionEvent(); /** * @brief Convenience method to get a render window widget. * @param Number of the widget (0-3) * @return The render window widget */ QmitkRenderWindow* GetRenderWindow(unsigned int number) const; QmitkRenderWindow* GetRenderWindow1() const; QmitkRenderWindow* GetRenderWindow2() const; QmitkRenderWindow* GetRenderWindow3() const; QmitkRenderWindow* GetRenderWindow4() const; /** * @brief Convenience method to get a widget plane. * @param Number of the widget plane (1-3) * @return The widget plane as data node */ mitk::DataNode::Pointer GetWidgetPlane(unsigned int number) const; mitk::DataNode::Pointer GetWidgetPlane1() const; mitk::DataNode::Pointer GetWidgetPlane2() const; mitk::DataNode::Pointer GetWidgetPlane3() const; /** * @brief SetDecorationColor Set the color of the decoration of the 4 widgets. * * This is used to color the frame of the renderwindow and the corner annatation. * For the first 3 widgets, this color is a property of the helper object nodes * which contain the respective plane geometry. For widget 4, this is a member, * since there is no data node for this widget. */ void SetDecorationColor(unsigned int widgetNumber, mitk::Color color); /** * @brief GetDecorationColorForWidget Get the color for annotation, crosshair and rectangle. * @param widgetNumber Number of the renderwindow (0-3). * @return Color in mitk format. */ mitk::Color GetDecorationColor(unsigned int widgetNumber); public Q_SLOTS: // mouse events virtual void mousePressEvent(QMouseEvent*) override; virtual void moveEvent(QMoveEvent* e) override; virtual void wheelEvent(QWheelEvent* e) override; /// Receives the signal from HandleCrosshairPositionEvent, executes the StatusBar update void HandleCrosshairPositionEventDelayed(); void Fit(); void AddDisplayPlaneSubTree(); void EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p); void SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer = nullptr); void SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer = nullptr); Q_SIGNALS: void WheelMoved(QWheelEvent *); void Moved(); private: virtual void SetLayoutImpl() override; virtual void SynchronizeImpl() override { } virtual void SetInteractionSchemeImpl() override { } void CreateRenderWindowWidgets(); mitk::SliceNavigationController* m_TimeNavigationController; /** * @brief The 3 helper objects which contain the plane geometry. */ mitk::DataNode::Pointer m_PlaneNode1; mitk::DataNode::Pointer m_PlaneNode2; mitk::DataNode::Pointer m_PlaneNode3; /** * @brief m_ParentNodeForGeometryPlanes This helper object is added to the datastorage * and contains the 3 planes for displaying the image geometry (crosshair and 3D planes). */ mitk::DataNode::Pointer m_ParentNodeForGeometryPlanes; /** * @brief m_DecorationColorWidget4 color for annotation and rectangle of widget 4. * * For other widgets1-3, the color is a property of the respective data node. * There is no node for widget 4, hence, we need an extra member. */ mitk::Color m_DecorationColorWidget4; bool m_PendingCrosshairPositionEvent; }; #endif // QMITKSTDMULTIWIDGET_H diff --git a/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp index 440c982c9b..2b8b9e3228 100644 --- a/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkAbstractMultiWidget.cpp @@ -1,455 +1,434 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // mitk qt widgets module #include "QmitkAbstractMultiWidget.h" #include "QmitkLevelWindowWidget.h" #include "QmitkMultiWidgetLayoutManager.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include #include #include // qt #include // c++ #include struct QmitkAbstractMultiWidget::Impl final { Impl(QmitkAbstractMultiWidget* multiWidget, - mitk::RenderingManager* renderingManager, - mitk::BaseRenderer::RenderingMode::Type renderingMode, const QString& multiWidgetName); void SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; // set new data storage for the render window widgets for (const auto& renderWindowWidget : m_RenderWindowWidgets) { renderWindowWidget.second->SetDataStorage(m_DataStorage); } } void Synchronize(bool synchronized) { auto allObserverTags = m_DisplayActionEventHandler->GetAllObserverTags(); for (auto observerTag : allObserverTags) { m_DisplayActionEventHandler->DisconnectObserver(observerTag); } if (synchronized) { mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveCameraSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ZoomCameraSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperSynchronizedAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); } else { mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::MoveSenderCameraAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayMoveEvent(nullptr, mitk::Vector2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::SetCrosshairAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetCrosshairEvent(nullptr, mitk::Point3D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ZoomSenderCameraAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayZoomEvent(nullptr, 0.0, mitk::Point2D()), actionFunction); actionFunction = mitk::DisplayActionEventFunctions::ScrollSliceStepperAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplayScrollEvent(nullptr, 0), actionFunction); } // use the standard 'set level window' action for both modes mitk::StdFunctionCommand::ActionFunction actionFunction = mitk::DisplayActionEventFunctions::SetLevelWindowAction(); m_DisplayActionEventHandler->ConnectDisplayActionEvent(mitk::DisplaySetLevelWindowEvent(nullptr, mitk::ScalarType(), mitk::ScalarType()), actionFunction); } void InitializeDisplayActionEventHandling() { m_DisplayActionEventBroadcast = mitk::DisplayActionEventBroadcast::New(); m_DisplayActionEventBroadcast->LoadStateMachine("DisplayInteraction.xml"); m_DisplayActionEventBroadcast->SetEventConfig("DisplayConfigPACS.xml"); m_DisplayActionEventHandler = std::make_unique(); m_DisplayActionEventHandler->SetObservableBroadcast(m_DisplayActionEventBroadcast); Synchronize(true); } mitk::DataStorage::Pointer m_DataStorage; - mitk::RenderingManager* m_RenderingManager; - mitk::BaseRenderer::RenderingMode::Type m_RenderingMode; QString m_MultiWidgetName; RenderWindowWidgetMap m_RenderWindowWidgets; RenderWindowWidgetPointer m_ActiveRenderWindowWidget; int m_MultiWidgetRows; int m_MultiWidgetColumns; // interaction mitk::DisplayActionEventBroadcast::Pointer m_DisplayActionEventBroadcast; std::unique_ptr m_DisplayActionEventHandler; QmitkMultiWidgetLayoutManager* m_LayoutManager; }; QmitkAbstractMultiWidget::Impl::Impl(QmitkAbstractMultiWidget* multiWidget, - mitk::RenderingManager* renderingManager, - mitk::BaseRenderer::RenderingMode::Type renderingMode, const QString& multiWidgetName) : m_DataStorage(nullptr) - , m_RenderingManager(renderingManager) - , m_RenderingMode(renderingMode) , m_MultiWidgetName(multiWidgetName) , m_MultiWidgetRows(0) , m_MultiWidgetColumns(0) , m_DisplayActionEventBroadcast(nullptr) , m_DisplayActionEventHandler(nullptr) , m_LayoutManager(new QmitkMultiWidgetLayoutManager(multiWidget)) { InitializeDisplayActionEventHandling(); } QmitkAbstractMultiWidget::QmitkAbstractMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, - mitk::RenderingManager* renderingManager/* = nullptr*/, - mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing*/, const QString& multiWidgetName/* = "multiwidget"*/) : QWidget(parent, f) - , m_Impl(std::make_unique(this, renderingManager, renderingMode, multiWidgetName)) + , m_Impl(std::make_unique(this, multiWidgetName)) { // nothing here } QmitkAbstractMultiWidget::~QmitkAbstractMultiWidget() { } void QmitkAbstractMultiWidget::SetDataStorage(mitk::DataStorage* dataStorage) { m_Impl->SetDataStorage(dataStorage); } mitk::DataStorage* QmitkAbstractMultiWidget::GetDataStorage() const { return m_Impl->m_DataStorage; } -mitk::RenderingManager* QmitkAbstractMultiWidget::GetRenderingManager() const -{ - // use the global rendering manager if none was specified - if (m_Impl->m_RenderingManager == nullptr) - { - return mitk::RenderingManager::GetInstance(); - } - - return m_Impl->m_RenderingManager; -} - int QmitkAbstractMultiWidget::GetRowCount() const { return m_Impl->m_MultiWidgetRows; } int QmitkAbstractMultiWidget::GetColumnCount() const { return m_Impl->m_MultiWidgetColumns; } void QmitkAbstractMultiWidget::SetLayout(int row, int column) { m_Impl->m_MultiWidgetRows = row; m_Impl->m_MultiWidgetColumns = column; SetLayoutImpl(); } void QmitkAbstractMultiWidget::Synchronize(bool synchronized) { m_Impl->Synchronize(synchronized); SynchronizeImpl(); } void QmitkAbstractMultiWidget::SetInteractionScheme(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { auto interactionSchemeSwitcher = mitk::InteractionSchemeSwitcher::New(); auto interactionEventHandler = GetInteractionEventHandler(); try { interactionSchemeSwitcher->SetInteractionScheme(interactionEventHandler, scheme); } catch (const mitk::Exception&) { return; } SetInteractionSchemeImpl(); } mitk::InteractionEventHandler* QmitkAbstractMultiWidget::GetInteractionEventHandler() { return m_Impl->m_DisplayActionEventBroadcast.GetPointer(); } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::GetRenderWindowWidgets() const { return m_Impl->m_RenderWindowWidgets; } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get2DRenderWindowWidgets() const { RenderWindowWidgetMap renderWindowWidgets2D; auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); if(mitk::BaseRenderer::Standard2D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) { renderWindowWidgets2D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); } } return renderWindowWidgets2D; } QmitkAbstractMultiWidget::RenderWindowWidgetMap QmitkAbstractMultiWidget::Get3DRenderWindowWidgets() const { RenderWindowWidgetMap renderWindowWidgets3D; auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); if (mitk::BaseRenderer::Standard3D == mitk::BaseRenderer::GetInstance(renderWindow->GetVtkRenderWindow())->GetMapperID()) { renderWindowWidgets3D.insert(std::make_pair(renderWindowWidget.first, renderWindowWidget.second)); } } return renderWindowWidgets3D; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(int row, int column) const { return GetRenderWindowWidget(GetNameFromIndex(row, column)); } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QString& widgetName) const { RenderWindowWidgetMap::const_iterator it = m_Impl->m_RenderWindowWidgets.find(widgetName); if (it != m_Impl->m_RenderWindowWidgets.end()) { return it->second; } return nullptr; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetRenderWindowWidget(const QmitkRenderWindow* renderWindow) const { auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { if (renderWindowWidget.second->GetRenderWindow() == renderWindow) { return renderWindowWidget.second; } } return nullptr; } QmitkAbstractMultiWidget::RenderWindowHash QmitkAbstractMultiWidget::GetRenderWindows() const { RenderWindowHash result; // create QHash on demand auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { result.insert(renderWindowWidget.first, renderWindowWidget.second->GetRenderWindow()); } return result; } QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(int row, int column) const { return GetRenderWindow(GetNameFromIndex(row, column)); } QmitkRenderWindow* QmitkAbstractMultiWidget::GetRenderWindow(const QString& widgetName) const { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { return renderWindowWidget->GetRenderWindow(); } return nullptr; } void QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) { m_Impl->m_ActiveRenderWindowWidget = activeRenderWindowWidget; emit ActiveRenderWindowChanged(); } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetActiveRenderWindowWidget() const { return m_Impl->m_ActiveRenderWindowWidget; } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetFirstRenderWindowWidget() const { if (!m_Impl->m_RenderWindowWidgets.empty()) { return m_Impl->m_RenderWindowWidgets.begin()->second; } else { return nullptr; } } QmitkAbstractMultiWidget::RenderWindowWidgetPointer QmitkAbstractMultiWidget::GetLastRenderWindowWidget() const { if (!m_Impl->m_RenderWindowWidgets.empty()) { return m_Impl->m_RenderWindowWidgets.rbegin()->second; } else { return nullptr; } } QString QmitkAbstractMultiWidget::GetNameFromIndex(int row, int column) const { if (0 <= row && m_Impl->m_MultiWidgetRows > row && 0 <= column && m_Impl->m_MultiWidgetColumns > column) { return GetNameFromIndex(row * m_Impl->m_MultiWidgetColumns + column); } return QString(); } QString QmitkAbstractMultiWidget::GetNameFromIndex(size_t index) const { if (index <= m_Impl->m_RenderWindowWidgets.size()) { return m_Impl->m_MultiWidgetName + ".widget" + QString::number(index); } return QString(); } unsigned int QmitkAbstractMultiWidget::GetNumberOfRenderWindowWidgets() const { return m_Impl->m_RenderWindowWidgets.size(); } void QmitkAbstractMultiWidget::RequestUpdate(const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { return renderWindowWidget->RequestUpdate(); } } void QmitkAbstractMultiWidget::RequestUpdateAll() { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { renderWindowWidget.second->RequestUpdate(); } } void QmitkAbstractMultiWidget::ForceImmediateUpdate(const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget = GetRenderWindowWidget(widgetName); if (nullptr != renderWindowWidget) { renderWindowWidget->ForceImmediateUpdate(); } } void QmitkAbstractMultiWidget::ForceImmediateUpdateAll() { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { renderWindowWidget.second->ForceImmediateUpdate(); } } void QmitkAbstractMultiWidget::ActivateMenuWidget(bool state) { for (const auto& renderWindowWidget : m_Impl->m_RenderWindowWidgets) { auto renderWindow = renderWindowWidget.second->GetRenderWindow(); renderWindow->ActivateMenuWidget(state); } } bool QmitkAbstractMultiWidget::IsMenuWidgetEnabled() const { return m_Impl->m_ActiveRenderWindowWidget->GetRenderWindow()->GetActivateMenuWidgetFlag(); } QmitkMultiWidgetLayoutManager* QmitkAbstractMultiWidget::GetMultiWidgetLayoutManager() const { return m_Impl->m_LayoutManager; } void QmitkAbstractMultiWidget::AddRenderWindowWidget(const QString& widgetName, RenderWindowWidgetPointer renderWindowWidget) { m_Impl->m_RenderWindowWidgets.insert(std::make_pair(widgetName, renderWindowWidget)); } void QmitkAbstractMultiWidget::RemoveRenderWindowWidget() { auto iterator = m_Impl->m_RenderWindowWidgets.find(GetNameFromIndex(GetRenderWindowWidgets().size() - 1)); if (iterator == m_Impl->m_RenderWindowWidgets.end()) { return; } // disconnect each signal of this render window widget RenderWindowWidgetPointer renderWindowWidgetToRemove = iterator->second; disconnect(renderWindowWidgetToRemove.get(), 0, 0, 0); // erase the render window from the map m_Impl->m_RenderWindowWidgets.erase(iterator); } diff --git a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp index d38432440a..269de6f2d5 100644 --- a/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkMxNMultiWidget.cpp @@ -1,257 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMxNMultiWidget.h" #include "QmitkRenderWindowWidget.h" // qt #include QmitkMxNMultiWidget::QmitkMxNMultiWidget(QWidget* parent, Qt::WindowFlags f/* = 0*/, - mitk::RenderingManager* renderingManager/* = nullptr*/, - mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing*/, const QString& multiWidgetName/* = "mxnmulti"*/) - : QmitkAbstractMultiWidget(parent, f, renderingManager, renderingMode, multiWidgetName) + : QmitkAbstractMultiWidget(parent, f, multiWidgetName) , m_CrosshairVisibility(false) { // nothing here } void QmitkMxNMultiWidget::InitializeMultiWidget() { SetLayout(1, 1); ActivateMenuWidget(true); } void QmitkMxNMultiWidget::MultiWidgetOpened() { SetCrosshairVisibility(true); } void QmitkMxNMultiWidget::MultiWidgetClosed() { SetCrosshairVisibility(false); } QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName || "sagittal" == widgetName || "coronal" == widgetName || "3d" == widgetName) { return GetActiveRenderWindowWidget()->GetRenderWindow(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkMxNMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& /*viewDirection*/) const { // currently no mapping between view directions and render windows // simply return the currently active render window return GetActiveRenderWindowWidget()->GetRenderWindow(); } void QmitkMxNMultiWidget::SetActiveRenderWindowWidget(RenderWindowWidgetPointer activeRenderWindowWidget) { auto currentActiveRenderWindowWidget = GetActiveRenderWindowWidget(); if (currentActiveRenderWindowWidget == activeRenderWindowWidget) { return; } // reset the decoration color of the previously active render window widget if (nullptr != currentActiveRenderWindowWidget) { auto decorationColor = currentActiveRenderWindowWidget->GetDecorationColor(); QColor hexColor(decorationColor[0] * 255, decorationColor[1] * 255, decorationColor[2] * 255); currentActiveRenderWindowWidget->setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); } // set the new decoration color of the currently active render window widget if (nullptr != activeRenderWindowWidget) { activeRenderWindowWidget->setStyleSheet("border: 2px solid #FF6464"); } QmitkAbstractMultiWidget::SetActiveRenderWindowWidget(activeRenderWindowWidget); } void QmitkMxNMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& widgetName) { RenderWindowWidgetPointer renderWindowWidget; if (widgetName.isNull()) { renderWindowWidget = GetActiveRenderWindowWidget(); } else { renderWindowWidget = GetRenderWindowWidget(widgetName); } if (nullptr != renderWindowWidget) { renderWindowWidget->GetSliceNavigationController()->SelectSliceByPoint(newPosition); renderWindowWidget->RequestUpdate(); return; } MITK_ERROR << "Position can not be set for an unknown render window widget."; } const mitk::Point3D QmitkMxNMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { // see T26208 return mitk::Point3D(); } void QmitkMxNMultiWidget::SetCrosshairVisibility(bool activate) { auto renderWindowWidgets = GetRenderWindowWidgets(); for (const auto& renderWindowWidget : renderWindowWidgets) { renderWindowWidget.second->ActivateCrosshair(activate); } m_CrosshairVisibility = activate; } void QmitkMxNMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } - auto renderingManager = GetRenderingManager(); - if (nullptr == renderingManager) - { - return; - } - - renderingManager->InitializeViewsByBoundingObjects(dataStorage); + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkMxNMultiWidget::SetWidgetPlaneMode(int userMode) { MITK_DEBUG << "Changing crosshair mode to " << userMode; switch (userMode) { case 0: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); break; case 1: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); break; case 2: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); break; case 3: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); break; } } ////////////////////////////////////////////////////////////////////////// // PUBLIC SLOTS // MOUSE EVENTS ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkMxNMultiWidget::mousePressEvent(QMouseEvent* e) { if (QEvent::MouseButtonPress != e->type()) { return; } auto renderWindowWidget = dynamic_cast(this->sender()); if (nullptr == renderWindowWidget) { return; } auto renderWindowWidgetPointer = GetRenderWindowWidget(renderWindowWidget->GetWidgetName()); SetActiveRenderWindowWidget(renderWindowWidgetPointer); } void QmitkMxNMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the overlays as the MultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidget::SetLayoutImpl() { int requiredRenderWindowWidgets = GetRowCount() * GetColumnCount(); int existingRenderWindowWidgets = GetRenderWindowWidgets().size(); int difference = requiredRenderWindowWidgets - existingRenderWindowWidgets; while (0 < difference) { // more render window widgets needed CreateRenderWindowWidget(); --difference; } while (0 > difference) { // less render window widgets needed RemoveRenderWindowWidget(); ++difference; } auto firstRenderWindowWidget = GetFirstRenderWindowWidget(); if (nullptr != firstRenderWindowWidget) { SetActiveRenderWindowWidget(firstRenderWindowWidget); } GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); } void QmitkMxNMultiWidget::CreateRenderWindowWidget() { // create the render window widget and connect signal / slot QString renderWindowWidgetName = GetNameFromIndex(GetNumberOfRenderWindowWidgets()); - RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + RenderWindowWidgetPointer renderWindowWidget = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); renderWindowWidget->SetCornerAnnotationText(renderWindowWidgetName.toStdString()); connect(renderWindowWidget.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkMxNMultiWidget::mousePressEvent); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget); auto renderWindow = renderWindowWidget->GetRenderWindow(); auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindow, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindow, &QmitkRenderWindow::ResetView, this, &QmitkMxNMultiWidget::ResetCrosshair); connect(renderWindow, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkMxNMultiWidget::SetCrosshairVisibility); connect(renderWindow, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkMxNMultiWidget::SetWidgetPlaneMode); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindow.cpp b/Modules/QtWidgets/src/QmitkRenderWindow.cpp index eaa568ce67..55809a1bd1 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindow.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindow.cpp @@ -1,506 +1,506 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindow.h" #include "mitkInteractionKeyEvent.h" #include "mitkInternalEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMousePressEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkMouseWheelEvent.h" #include #include #include #include #include #include #include #include #include #include #include "QmitkMimeTypes.h" #include "QmitkRenderWindowMenu.h" -QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *, mitk::RenderingManager *renderingManager, mitk::BaseRenderer::RenderingMode renderingMode) +QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *) : QVTKOpenGLWidget(parent) , m_ResendQtEvents(true) , m_MenuWidget(nullptr) , m_MenuWidgetActivated(false) , m_LayoutIndex(QmitkRenderWindowMenu::LayoutIndex::AXIAL) { m_InternalRenderWindow = vtkSmartPointer::New(); m_InternalRenderWindow->SetMultiSamples(0); m_InternalRenderWindow->SetAlphaBitPlanes(0); SetRenderWindow(m_InternalRenderWindow); - Initialize(renderingManager, name.toStdString().c_str(), renderingMode); + Initialize(name.toStdString().c_str()); setFocusPolicy(Qt::StrongFocus); setMouseTracking(true); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(sizePolicy); } QmitkRenderWindow::~QmitkRenderWindow() { Destroy(); // Destroy mitkRenderWindowBase } void QmitkRenderWindow::SetResendQtEvents(bool resend) { m_ResendQtEvents = resend; } void QmitkRenderWindow::SetLayoutIndex(QmitkRenderWindowMenu::LayoutIndex layoutIndex) { m_LayoutIndex = layoutIndex; if (nullptr != m_MenuWidget) { m_MenuWidget->SetLayoutIndex(layoutIndex); } } QmitkRenderWindowMenu::LayoutIndex QmitkRenderWindow::GetLayoutIndex() { if (nullptr != m_MenuWidget) { return m_MenuWidget->GetLayoutIndex(); } else { return QmitkRenderWindowMenu::LayoutIndex::AXIAL; } } void QmitkRenderWindow::LayoutDesignListChanged(QmitkRenderWindowMenu::LayoutDesign layoutDesign) { if (nullptr != m_MenuWidget) { m_MenuWidget->UpdateLayoutDesignList(layoutDesign); } } void QmitkRenderWindow::ActivateMenuWidget(bool state) { if (nullptr == m_MenuWidget) { m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer); m_MenuWidget->SetLayoutIndex(m_LayoutIndex); } m_MenuWidgetActivated = state; if (m_MenuWidgetActivated) { connect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); connect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); } else { disconnect(m_MenuWidget, &QmitkRenderWindowMenu::LayoutDesignChanged, this, &QmitkRenderWindow::LayoutDesignChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::ResetView, this, &QmitkRenderWindow::ResetView); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairVisibilityChanged, this, &QmitkRenderWindow::CrosshairVisibilityChanged); disconnect(m_MenuWidget, &QmitkRenderWindowMenu::CrosshairRotationModeChanged, this, &QmitkRenderWindow::CrosshairRotationModeChanged); m_MenuWidget->hide(); } } void QmitkRenderWindow::moveEvent(QMoveEvent *event) { QVTKOpenGLWidget::moveEvent(event); // after a move the overlays need to be positioned emit moved(); } void QmitkRenderWindow::showEvent(QShowEvent *event) { QVTKOpenGLWidget::showEvent(event); // this singleshot is necessary to have the overlays positioned correctly after initial show // simple call of moved() is no use here!! QTimer::singleShot(0, this, SIGNAL(moved())); } void QmitkRenderWindow::mousePressEvent(QMouseEvent *me) { // Get mouse position in vtk display coordinate system. me contains qt display infos... mitk::Point2D displayPos = GetMousePosition(me); mitk::MousePressEvent::Pointer mPressEvent = mitk::MousePressEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { QVTKOpenGLWidget::mousePressEvent(me); } if (m_ResendQtEvents) { me->ignore(); } } void QmitkRenderWindow::mouseDoubleClickEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::MouseDoubleClickEvent::Pointer mPressEvent = mitk::MouseDoubleClickEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mPressEvent.GetPointer())) { QVTKOpenGLWidget::mousePressEvent(me); } if (m_ResendQtEvents) { me->ignore(); } } void QmitkRenderWindow::mouseReleaseEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); mitk::MouseReleaseEvent::Pointer mReleaseEvent = mitk::MouseReleaseEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me), GetEventButton(me)); if (!this->HandleEvent(mReleaseEvent.GetPointer())) { QVTKOpenGLWidget::mouseReleaseEvent(me); } if (m_ResendQtEvents) { me->ignore(); } } void QmitkRenderWindow::mouseMoveEvent(QMouseEvent *me) { mitk::Point2D displayPos = GetMousePosition(me); AdjustRenderWindowMenuVisibility(me->pos()); mitk::MouseMoveEvent::Pointer mMoveEvent = mitk::MouseMoveEvent::New(m_Renderer, displayPos, GetButtonState(me), GetModifiers(me)); if (!this->HandleEvent(mMoveEvent.GetPointer())) { QVTKOpenGLWidget::mouseMoveEvent(me); } } void QmitkRenderWindow::wheelEvent(QWheelEvent *we) { mitk::Point2D displayPos = GetMousePosition(we); mitk::MouseWheelEvent::Pointer mWheelEvent = mitk::MouseWheelEvent::New(m_Renderer, displayPos, GetButtonState(we), GetModifiers(we), GetDelta(we)); if (!this->HandleEvent(mWheelEvent.GetPointer())) { QVTKOpenGLWidget::wheelEvent(we); } if (m_ResendQtEvents) { we->ignore(); } } void QmitkRenderWindow::keyPressEvent(QKeyEvent *ke) { mitk::InteractionEvent::ModifierKeys modifiers = GetModifiers(ke); std::string key = GetKeyLetter(ke); mitk::InteractionKeyEvent::Pointer keyEvent = mitk::InteractionKeyEvent::New(m_Renderer, key, modifiers); if (!this->HandleEvent(keyEvent.GetPointer())) { QVTKOpenGLWidget::keyPressEvent(ke); } if (m_ResendQtEvents) { ke->ignore(); } } void QmitkRenderWindow::enterEvent(QEvent *e) { // TODO implement new event QVTKOpenGLWidget::enterEvent(e); } void QmitkRenderWindow::leaveEvent(QEvent *e) { mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, nullptr, "LeaveRenderWindow"); this->HandleEvent(internalEvent.GetPointer()); if (nullptr != m_MenuWidget) { m_MenuWidget->smoothHide(); } QVTKOpenGLWidget::leaveEvent(e); } void QmitkRenderWindow::resizeGL(int w, int h) { - this->GetRenderer()->GetRenderingManager()->ForceImmediateUpdate(GetRenderWindow()); QVTKOpenGLWidget::resizeGL(w, h); + mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(GetRenderWindow()); } void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("application/x-mitk-datanodes")) { event->accept(); } } void QmitkRenderWindow::dropEvent(QDropEvent *event) { QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData()); if (!dataNodeList.empty()) { emit NodesDropped(this, dataNodeList.toVector().toStdVector()); } } void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint & /*pos*/) { if (nullptr != m_MenuWidget) { m_MenuWidget->ShowMenu(); m_MenuWidget->MoveWidgetToCorrectPos(1.0f); } } void QmitkRenderWindow::DeferredHideMenu() { MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu"; if (nullptr != m_MenuWidget) { m_MenuWidget->HideMenu(); } } mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const { mitk::Point2D point; point[0] = me->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - me->y(); return point; } mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const { mitk::Point2D point; point[0] = we->x(); // We need to convert the y component, as the display and vtk have other definitions for the y direction point[1] = m_Renderer->GetSizeY() - we->y(); return point; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::InteractionEvent::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::InteractionEvent::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::InteractionEvent::MiddleMouseButton; break; default: eventButton = mitk::InteractionEvent::NoButton; break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const { // Converting Qt Key Event to string element. std::string key = ""; int tkey = ke->key(); if (tkey < 128) { // standard ascii letter key = (char)toupper(tkey); } else { // special keys switch (tkey) { case Qt::Key_Return: key = mitk::InteractionEvent::KeyReturn; break; case Qt::Key_Enter: key = mitk::InteractionEvent::KeyEnter; break; case Qt::Key_Escape: key = mitk::InteractionEvent::KeyEsc; break; case Qt::Key_Delete: key = mitk::InteractionEvent::KeyDelete; break; case Qt::Key_Up: key = mitk::InteractionEvent::KeyArrowUp; break; case Qt::Key_Down: key = mitk::InteractionEvent::KeyArrowDown; break; case Qt::Key_Left: key = mitk::InteractionEvent::KeyArrowLeft; break; case Qt::Key_Right: key = mitk::InteractionEvent::KeyArrowRight; break; case Qt::Key_F1: key = mitk::InteractionEvent::KeyF1; break; case Qt::Key_F2: key = mitk::InteractionEvent::KeyF2; break; case Qt::Key_F3: key = mitk::InteractionEvent::KeyF3; break; case Qt::Key_F4: key = mitk::InteractionEvent::KeyF4; break; case Qt::Key_F5: key = mitk::InteractionEvent::KeyF5; break; case Qt::Key_F6: key = mitk::InteractionEvent::KeyF6; break; case Qt::Key_F7: key = mitk::InteractionEvent::KeyF7; break; case Qt::Key_F8: key = mitk::InteractionEvent::KeyF8; break; case Qt::Key_F9: key = mitk::InteractionEvent::KeyF9; break; case Qt::Key_F10: key = mitk::InteractionEvent::KeyF10; break; case Qt::Key_F11: key = mitk::InteractionEvent::KeyF11; break; case Qt::Key_F12: key = mitk::InteractionEvent::KeyF12; break; case Qt::Key_End: key = mitk::InteractionEvent::KeyEnd; break; case Qt::Key_Home: key = mitk::InteractionEvent::KeyPos1; break; case Qt::Key_Insert: key = mitk::InteractionEvent::KeyInsert; break; case Qt::Key_PageDown: key = mitk::InteractionEvent::KeyPageDown; break; case Qt::Key_PageUp: key = mitk::InteractionEvent::KeyPageUp; break; case Qt::Key_Space: key = mitk::InteractionEvent::KeySpace; break; } } return key; } int QmitkRenderWindow::GetDelta(QWheelEvent *we) const { return we->delta(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp index 3ff2deca91..36be1473bc 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp @@ -1,652 +1,652 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindowMenu.h" // mitk core #include "mitkProperties.h" #include "mitkResliceMethodProperty.h" // qt #include #include #include #include #include #include #include #include #include //#include"iconClose.xpm" #include "iconCrosshairMode.xpm" #include "iconFullScreen.xpm" //#include"iconHoriSplit.xpm" #include "iconSettings.xpm" //#include"iconVertiSplit.xpm" #include "iconLeaveFullScreen.xpm" // c++ #include unsigned int QmitkRenderWindowMenu::m_DefaultThickMode(1); #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget* parent, Qt::WindowFlags, mitk::BaseRenderer* baseRenderer) : QWidget(nullptr, Qt::Tool | Qt::FramelessWindowHint) #else QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget* parent, Qt::WindowFlags flags, mitk::BaseRenderer* baseRenderer) : QWidget(parent, flags) #endif , m_LayoutActionsMenu(nullptr) , m_CrosshairMenu(nullptr) , m_FullScreenMode(false) , m_Renderer(baseRenderer) , m_Parent(parent) , m_CrosshairRotationMode(0) , m_CrosshairVisibility(false) , m_Layout(LayoutIndex::AXIAL) , m_LayoutDesign(LayoutDesign::DEFAULT) , m_OldLayoutDesign(LayoutDesign::DEFAULT) { CreateMenuWidget(); setMinimumWidth(61); // DIRTY.. If you add or remove a button, you need to change the size. setMaximumWidth(61); setAutoFillBackground(true); // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows // for macOS see bug 3192 // for Windows see bug 12130 //... so macOS and Windows must be treated differently: #if defined(Q_OS_MAC) this->show(); this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif m_AutoRotationTimer = new QTimer(this); m_AutoRotationTimer->setInterval(75); m_HideTimer = new QTimer(this); m_HideTimer->setSingleShot(true); connect(m_AutoRotationTimer, &QTimer::timeout, this, &QmitkRenderWindowMenu::AutoRotateNextStep); connect(m_HideTimer, &QTimer::timeout, this, &QmitkRenderWindowMenu::DeferredHideMenu); connect(m_Parent, &QObject::destroyed, this, &QmitkRenderWindowMenu::deleteLater); } QmitkRenderWindowMenu::~QmitkRenderWindowMenu() { if (m_AutoRotationTimer->isActive()) { m_AutoRotationTimer->stop(); } } void QmitkRenderWindowMenu::SetLayoutIndex(LayoutIndex layoutIndex) { m_Layout = layoutIndex; } void QmitkRenderWindowMenu::UpdateLayoutDesignList(LayoutDesign layoutDesign) { m_LayoutDesign = layoutDesign; if (nullptr == m_LayoutActionsMenu) { CreateSettingsWidget(); } m_DefaultLayoutAction->setEnabled(true); m_All2DTop3DBottomLayoutAction->setEnabled(true); m_All2DLeft3DRightLayoutAction->setEnabled(true); m_OneBigLayoutAction->setEnabled(true); m_Only2DHorizontalLayoutAction->setEnabled(true); m_Only2DVerticalLayoutAction->setEnabled(true); m_OneTop3DBottomLayoutAction->setEnabled(true); m_OneLeft3DRightLayoutAction->setEnabled(true); m_AllHorizontalLayoutAction->setEnabled(true); m_AllVerticalLayoutAction->setEnabled(true); m_RemoveOneLayoutAction->setEnabled(true); switch (m_LayoutDesign) { case LayoutDesign::DEFAULT: { m_DefaultLayoutAction->setEnabled(false); break; } case LayoutDesign::ALL_2D_TOP_3D_BOTTOM: { m_All2DTop3DBottomLayoutAction->setEnabled(false); break; } case LayoutDesign::ALL_2D_LEFT_3D_RIGHT: { m_All2DLeft3DRightLayoutAction->setEnabled(false); break; } case LayoutDesign::ONE_BIG: { m_OneBigLayoutAction->setEnabled(false); break; } case LayoutDesign::ONLY_2D_HORIZONTAL: { m_Only2DHorizontalLayoutAction->setEnabled(false); break; } case LayoutDesign::ONLY_2D_VERTICAL: { m_Only2DVerticalLayoutAction->setEnabled(false); break; } case LayoutDesign::ONE_TOP_3D_BOTTOM: { m_OneTop3DBottomLayoutAction->setEnabled(false); break; } case LayoutDesign::ONE_LEFT_3D_RIGHT: { m_OneLeft3DRightLayoutAction->setEnabled(false); break; } case LayoutDesign::ALL_HORIZONTAL: { m_AllHorizontalLayoutAction->setEnabled(false); break; } case LayoutDesign::ALL_VERTICAL: { m_AllVerticalLayoutAction->setEnabled(false); break; } case LayoutDesign::REMOVE_ONE: { m_RemoveOneLayoutAction->setEnabled(false); break; } case LayoutDesign::NONE: { break; } } } #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float opacity) #else void QmitkRenderWindowMenu::MoveWidgetToCorrectPos(float /*opacity*/) #endif { #ifdef QMITK_USE_EXTERNAL_RENDERWINDOW_MENU int X = floor(double(this->m_Parent->width() - this->width() - 8.0)); int Y = 7; QPoint pos = this->m_Parent->mapToGlobal(QPoint(0, 0)); this->move(X + pos.x(), Y + pos.y()); if (opacity < 0) opacity = 0; else if (opacity > 1) opacity = 1; this->setWindowOpacity(opacity); #else int moveX = floor(double(this->m_Parent->width() - this->width() - 4.0)); this->move(moveX, 3); this->show(); #endif } void QmitkRenderWindowMenu::ShowMenu() { MITK_DEBUG << "menu showMenu"; DeferredShowMenu(); } void QmitkRenderWindowMenu::HideMenu() { MITK_DEBUG << "menu hideEvent"; DeferredHideMenu(); } void QmitkRenderWindowMenu::paintEvent(QPaintEvent * /*e*/) { QPainter painter(this); QColor semiTransparentColor = Qt::black; semiTransparentColor.setAlpha(255); painter.fillRect(rect(), semiTransparentColor); } void QmitkRenderWindowMenu::CreateMenuWidget() { QHBoxLayout *layout = new QHBoxLayout(this); layout->setAlignment(Qt::AlignRight); layout->setContentsMargins(1, 1, 1, 1); QSize size(13, 13); m_CrosshairMenu = new QMenu(this); connect(m_CrosshairMenu, &QMenu::aboutToShow, this, &QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow); m_CrosshairModeButton = new QToolButton(this); m_CrosshairModeButton->setMaximumSize(15, 15); m_CrosshairModeButton->setIconSize(size); m_CrosshairModeButton->setMenu(m_CrosshairMenu); m_CrosshairModeButton->setIcon(QIcon(QPixmap(iconCrosshairMode_xpm))); m_CrosshairModeButton->setPopupMode(QToolButton::InstantPopup); m_CrosshairModeButton->setStyleSheet("QToolButton::menu-indicator { image: none; }"); m_CrosshairModeButton->setAutoRaise(true); layout->addWidget(m_CrosshairModeButton); m_FullScreenButton = new QToolButton(this); m_FullScreenButton->setMaximumSize(15, 15); m_FullScreenButton->setIconSize(size); m_FullScreenButton->setIcon(QIcon(QPixmap(iconFullScreen_xpm))); m_FullScreenButton->setAutoRaise(true); layout->addWidget(m_FullScreenButton); m_LayoutDesignButton = new QToolButton(this); m_LayoutDesignButton->setMaximumSize(15, 15); m_LayoutDesignButton->setIconSize(size); m_LayoutDesignButton->setIcon(QIcon(QPixmap(iconSettings_xpm))); m_LayoutDesignButton->setAutoRaise(true); layout->addWidget(m_LayoutDesignButton); connect(m_FullScreenButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnFullScreenButton); connect(m_LayoutDesignButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnLayoutDesignButton); } void QmitkRenderWindowMenu::CreateSettingsWidget() { m_LayoutActionsMenu = new QMenu(this); m_DefaultLayoutAction = new QAction("Standard layout", m_LayoutActionsMenu); m_DefaultLayoutAction->setDisabled(true); m_All2DTop3DBottomLayoutAction = new QAction("All 2D top, 3D bottom", m_LayoutActionsMenu); m_All2DTop3DBottomLayoutAction->setDisabled(false); m_All2DLeft3DRightLayoutAction = new QAction("All 2D left, 3D right", m_LayoutActionsMenu); m_All2DLeft3DRightLayoutAction->setDisabled(false); m_OneBigLayoutAction = new QAction("This big", m_LayoutActionsMenu); m_OneBigLayoutAction->setDisabled(false); m_Only2DHorizontalLayoutAction = new QAction("Only 2D horizontal", m_LayoutActionsMenu); m_Only2DHorizontalLayoutAction->setDisabled(false); m_Only2DVerticalLayoutAction = new QAction("Only 2D vertical", m_LayoutActionsMenu); m_Only2DVerticalLayoutAction->setDisabled(false); m_OneTop3DBottomLayoutAction = new QAction("This top, 3D bottom", m_LayoutActionsMenu); m_OneTop3DBottomLayoutAction->setDisabled(false); m_OneLeft3DRightLayoutAction = new QAction("This left, 3D right", m_LayoutActionsMenu); m_OneLeft3DRightLayoutAction->setDisabled(false); m_AllHorizontalLayoutAction = new QAction("All horizontal", m_LayoutActionsMenu); m_AllHorizontalLayoutAction->setDisabled(false); m_AllVerticalLayoutAction = new QAction("All vertical", m_LayoutActionsMenu); m_AllVerticalLayoutAction->setDisabled(false); m_RemoveOneLayoutAction = new QAction("Remove this", m_LayoutActionsMenu); m_RemoveOneLayoutAction->setDisabled(false); m_LayoutActionsMenu->addAction(m_DefaultLayoutAction); m_LayoutActionsMenu->addAction(m_All2DTop3DBottomLayoutAction); m_LayoutActionsMenu->addAction(m_All2DLeft3DRightLayoutAction); m_LayoutActionsMenu->addAction(m_OneBigLayoutAction); m_LayoutActionsMenu->addAction(m_Only2DHorizontalLayoutAction); m_LayoutActionsMenu->addAction(m_Only2DVerticalLayoutAction); m_LayoutActionsMenu->addAction(m_OneTop3DBottomLayoutAction); m_LayoutActionsMenu->addAction(m_OneLeft3DRightLayoutAction); m_LayoutActionsMenu->addAction(m_AllHorizontalLayoutAction); m_LayoutActionsMenu->addAction(m_AllVerticalLayoutAction); m_LayoutActionsMenu->addAction(m_RemoveOneLayoutAction); m_LayoutActionsMenu->setVisible(false); connect(m_DefaultLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::DEFAULT); }); connect(m_All2DTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_TOP_3D_BOTTOM); }); connect(m_All2DLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_LEFT_3D_RIGHT); }); connect(m_OneBigLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_BIG); }); connect(m_Only2DHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_HORIZONTAL); }); connect(m_Only2DVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_VERTICAL); }); connect(m_OneTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_TOP_3D_BOTTOM); }); connect(m_OneLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_LEFT_3D_RIGHT); }); connect(m_AllHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_HORIZONTAL); }); connect(m_AllVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_VERTICAL); }); connect(m_RemoveOneLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::REMOVE_ONE); }); } void QmitkRenderWindowMenu::ChangeFullScreenIcon() { m_FullScreenButton->setIcon(m_FullScreenMode ? QPixmap(iconLeaveFullScreen_xpm) : QPixmap(iconFullScreen_xpm)); } void QmitkRenderWindowMenu::DeferredShowMenu() { MITK_DEBUG << "deferred show menu"; m_HideTimer->stop(); // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows // for macOS see bug 3192 // for Windows see bug 12130 //... so macOS and Windows must be treated differently: #if defined(Q_OS_MAC) this->setWindowOpacity(1.0f); #else this->setVisible(true); this->raise(); #endif } void QmitkRenderWindowMenu::DeferredHideMenu() { MITK_DEBUG << "menu deferredhidemenu"; // Else part fixes the render window menu issue on Linux bug but caused bugs on macOS and Windows // for macOS see bug 3192 // for Windows see bug 12130 //... so macOS and Windows must be treated differently: #if defined(Q_OS_MAC) this->setWindowOpacity(0.0f); #else this->setVisible(false); #endif } void QmitkRenderWindowMenu::smoothHide() { MITK_DEBUG << "menu leaveEvent"; m_HideTimer->start(10); } void QmitkRenderWindowMenu::enterEvent(QEvent * /*e*/) { MITK_DEBUG << "menu enterEvent"; DeferredShowMenu(); } void QmitkRenderWindowMenu::leaveEvent(QEvent * /*e*/) { MITK_DEBUG << "menu leaveEvent"; smoothHide(); } void QmitkRenderWindowMenu::AutoRotateNextStep() { if (m_Renderer->GetCameraRotationController()) { m_Renderer->GetCameraRotationController()->GetSlice()->Next(); } } void QmitkRenderWindowMenu::OnAutoRotationActionTriggered() { if (m_AutoRotationTimer->isActive()) { m_AutoRotationTimer->stop(); m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOff(); } else { m_Renderer->GetCameraRotationController()->GetSlice()->PingPongOn(); m_AutoRotationTimer->start(); } } void QmitkRenderWindowMenu::OnTSNumChanged(int num) { MITK_DEBUG << "Thickslices num: " << num << " on renderer " << m_Renderer.GetPointer(); if (m_Renderer.IsNotNull()) { unsigned int thickSlicesMode = 0; // determine the state of the thick-slice mode mitk::ResliceMethodProperty *resliceMethodEnumProperty = nullptr; if(m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty(resliceMethodEnumProperty, "reslice.thickslices") && resliceMethodEnumProperty) { thickSlicesMode = resliceMethodEnumProperty->GetValueAsId(); if(thickSlicesMode!=0) m_DefaultThickMode = thickSlicesMode; } if(thickSlicesMode==0 && num>0) //default mode only for single slices { thickSlicesMode = m_DefaultThickMode; //mip default m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(true)); } if(num<1) { thickSlicesMode = 0; m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea", mitk::BoolProperty::New(false)); } m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices", mitk::ResliceMethodProperty::New(thickSlicesMode)); m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.num", mitk::IntProperty::New(num)); m_TSLabel->setText(QString::number(num * 2 + 1)); m_Renderer->SendUpdateSlice(); - m_Renderer->GetRenderingManager()->RequestUpdateAll(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow() { QMenu *crosshairModesMenu = m_CrosshairMenu; crosshairModesMenu->clear(); QAction *resetViewAction = new QAction(crosshairModesMenu); resetViewAction->setText("Reset view"); crosshairModesMenu->addAction(resetViewAction); connect(resetViewAction, &QAction::triggered, this, &QmitkRenderWindowMenu::ResetView); // Show hide crosshairs { QAction *showHideCrosshairVisibilityAction = new QAction(crosshairModesMenu); showHideCrosshairVisibilityAction->setText("Show crosshair"); showHideCrosshairVisibilityAction->setCheckable(true); showHideCrosshairVisibilityAction->setChecked(m_CrosshairVisibility); crosshairModesMenu->addAction(showHideCrosshairVisibilityAction); connect(showHideCrosshairVisibilityAction, &QAction::toggled, this, &QmitkRenderWindowMenu::OnCrosshairVisibilityChanged); } // Rotation mode { QAction *rotationGroupSeparator = new QAction(crosshairModesMenu); rotationGroupSeparator->setSeparator(true); rotationGroupSeparator->setText("Rotation mode"); crosshairModesMenu->addAction(rotationGroupSeparator); QActionGroup *rotationModeActionGroup = new QActionGroup(crosshairModesMenu); rotationModeActionGroup->setExclusive(true); QAction *noCrosshairRotation = new QAction(crosshairModesMenu); noCrosshairRotation->setActionGroup(rotationModeActionGroup); noCrosshairRotation->setText("No crosshair rotation"); noCrosshairRotation->setCheckable(true); noCrosshairRotation->setChecked(m_CrosshairRotationMode == 0); noCrosshairRotation->setData(0); crosshairModesMenu->addAction(noCrosshairRotation); QAction *singleCrosshairRotation = new QAction(crosshairModesMenu); singleCrosshairRotation->setActionGroup(rotationModeActionGroup); singleCrosshairRotation->setText("Crosshair rotation"); singleCrosshairRotation->setCheckable(true); singleCrosshairRotation->setChecked(m_CrosshairRotationMode == 1); singleCrosshairRotation->setData(1); crosshairModesMenu->addAction(singleCrosshairRotation); QAction *coupledCrosshairRotation = new QAction(crosshairModesMenu); coupledCrosshairRotation->setActionGroup(rotationModeActionGroup); coupledCrosshairRotation->setText("Coupled crosshair rotation"); coupledCrosshairRotation->setCheckable(true); coupledCrosshairRotation->setChecked(m_CrosshairRotationMode == 2); coupledCrosshairRotation->setData(2); crosshairModesMenu->addAction(coupledCrosshairRotation); QAction *swivelMode = new QAction(crosshairModesMenu); swivelMode->setActionGroup(rotationModeActionGroup); swivelMode->setText("Swivel mode"); swivelMode->setCheckable(true); swivelMode->setChecked(m_CrosshairRotationMode == 3); swivelMode->setData(3); crosshairModesMenu->addAction(swivelMode); connect(rotationModeActionGroup, &QActionGroup::triggered, this, &QmitkRenderWindowMenu::OnCrosshairRotationModeSelected); } // auto rotation support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D) { QAction *autoRotationGroupSeparator = new QAction(crosshairModesMenu); autoRotationGroupSeparator->setSeparator(true); crosshairModesMenu->addAction(autoRotationGroupSeparator); QAction *autoRotationAction = crosshairModesMenu->addAction("Auto Rotation"); autoRotationAction->setCheckable(true); autoRotationAction->setChecked(m_AutoRotationTimer->isActive()); connect(autoRotationAction, &QAction::triggered, this, &QmitkRenderWindowMenu::OnAutoRotationActionTriggered); } // Thickslices support if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard2D) { QAction *thickSlicesGroupSeparator = new QAction(crosshairModesMenu); thickSlicesGroupSeparator->setSeparator(true); thickSlicesGroupSeparator->setText("ThickSlices mode"); crosshairModesMenu->addAction(thickSlicesGroupSeparator); QActionGroup *thickSlicesActionGroup = new QActionGroup(crosshairModesMenu); thickSlicesActionGroup->setExclusive(true); int currentMode = 0; { mitk::ResliceMethodProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices")); if (m.IsNotNull()) currentMode = m->GetValueAsId(); } int currentNum = 1; { mitk::IntProperty::Pointer m = dynamic_cast( m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices.num")); if (m.IsNotNull()) { currentNum = m->GetValue(); } } if (currentMode == 0) currentNum = 0; QSlider *m_TSSlider = new QSlider(crosshairModesMenu); m_TSSlider->setMinimum(0); m_TSSlider->setMaximum(50); m_TSSlider->setValue(currentNum); m_TSSlider->setOrientation(Qt::Horizontal); connect(m_TSSlider, &QSlider::valueChanged, this, &QmitkRenderWindowMenu::OnTSNumChanged); QHBoxLayout *tsLayout = new QHBoxLayout; tsLayout->setContentsMargins(4, 4, 4, 4); tsLayout->addWidget(new QLabel("TS: ")); tsLayout->addWidget(m_TSSlider); tsLayout->addWidget(m_TSLabel = new QLabel(QString::number(currentNum * 2 + 1), this)); QWidget *tsWidget = new QWidget; tsWidget->setLayout(tsLayout); QWidgetAction *m_TSSliderAction = new QWidgetAction(crosshairModesMenu); m_TSSliderAction->setDefaultWidget(tsWidget); crosshairModesMenu->addAction(m_TSSliderAction); } } void QmitkRenderWindowMenu::OnCrosshairVisibilityChanged(bool visible) { m_CrosshairVisibility = visible; emit CrosshairVisibilityChanged(visible); } void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction *action) { m_CrosshairRotationMode = action->data().toInt(); emit CrosshairRotationModeChanged(m_CrosshairRotationMode); } void QmitkRenderWindowMenu::OnFullScreenButton(bool /*checked*/) { if (!m_FullScreenMode) { m_FullScreenMode = true; m_OldLayoutDesign = m_LayoutDesign; emit LayoutDesignChanged(LayoutDesign::ONE_BIG); } else { m_FullScreenMode = false; emit LayoutDesignChanged(m_OldLayoutDesign); } MoveWidgetToCorrectPos(1.0f); ChangeFullScreenIcon(); DeferredShowMenu(); } void QmitkRenderWindowMenu::OnLayoutDesignButton(bool /*checked*/) { if (nullptr == m_LayoutActionsMenu) { CreateSettingsWidget(); } QPoint point = mapToGlobal(m_LayoutDesignButton->geometry().topLeft()); m_LayoutActionsMenu->setVisible(true); m_LayoutActionsMenu->exec(point); } void QmitkRenderWindowMenu::OnSetLayout(LayoutDesign layoutDesign) { m_FullScreenMode = false; ChangeFullScreenIcon(); m_LayoutDesign = layoutDesign; emit LayoutDesignChanged(m_LayoutDesign); DeferredShowMenu(); } diff --git a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp index 65f15b0593..e4f3596504 100644 --- a/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp +++ b/Modules/QtWidgets/src/QmitkRenderWindowWidget.cpp @@ -1,268 +1,258 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkRenderWindowWidget.h" // vtk #include #include QmitkRenderWindowWidget::QmitkRenderWindowWidget(QWidget* parent/* = nullptr*/, const QString& widgetName/* = ""*/, - mitk::DataStorage* dataStorage/* = nullptr*/, - mitk::RenderingManager* renderingManager/* = nullptr*/, - mitk::BaseRenderer::RenderingMode::Type renderingMode/* = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing*/) + mitk::DataStorage* dataStorage/* = nullptr*/) : QFrame(parent) , m_WidgetName(widgetName) , m_DataStorage(dataStorage) - , m_RenderingManager(renderingManager) - , m_RenderingMode(renderingMode) , m_RenderWindow(nullptr) , m_PointSetNode(nullptr) , m_PointSet(nullptr) { - InitializeGUI(); + this->InitializeGUI(); } QmitkRenderWindowWidget::~QmitkRenderWindowWidget() { auto sliceNavigationController = m_RenderWindow->GetSliceNavigationController(); if (nullptr != sliceNavigationController) { sliceNavigationController->SetCrosshairEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); } if (nullptr != m_DataStorage) { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::SetDataStorage(mitk::DataStorage* dataStorage) { if (dataStorage == m_DataStorage) { return; } m_DataStorage = dataStorage; if (nullptr != m_RenderWindow) { mitk::BaseRenderer::GetInstance(m_RenderWindow->GetRenderWindow())->SetDataStorage(dataStorage); } } mitk::SliceNavigationController* QmitkRenderWindowWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } void QmitkRenderWindowWidget::RequestUpdate() { - m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); } void QmitkRenderWindowWidget::ForceImmediateUpdate() { - m_RenderingManager->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->ForceImmediateUpdate(m_RenderWindow->GetRenderWindow()); } void QmitkRenderWindowWidget::SetGradientBackgroundColors(const mitk::Color& upper, const mitk::Color& lower) { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } m_GradientBackgroundColors.first = upper; m_GradientBackgroundColors.second = lower; vtkRenderer->SetBackground(lower[0], lower[1], lower[2]); vtkRenderer->SetBackground2(upper[0], upper[1], upper[2]); ShowGradientBackground(true); } void QmitkRenderWindowWidget::ShowGradientBackground(bool show) { m_RenderWindow->GetRenderer()->GetVtkRenderer()->SetGradientBackground(show); } bool QmitkRenderWindowWidget::IsGradientBackgroundOn() const { return m_RenderWindow->GetRenderer()->GetVtkRenderer()->GetGradientBackground(); } void QmitkRenderWindowWidget::SetDecorationColor(const mitk::Color& color) { m_DecorationColor = color; m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); } void QmitkRenderWindowWidget::ShowColoredRectangle(bool show) { if (show) { setFrameStyle(QFrame::Box | QFrame::Plain); } else { setFrameStyle(NoFrame); } } bool QmitkRenderWindowWidget::IsColoredRectangleVisible() const { return frameStyle() > 0; } void QmitkRenderWindowWidget::ShowCornerAnnotation(bool show) { m_CornerAnnotation->SetVisibility(show); } bool QmitkRenderWindowWidget::IsCornerAnnotationVisible() const { return m_CornerAnnotation->GetVisibility() > 0; } void QmitkRenderWindowWidget::SetCornerAnnotationText(const std::string& cornerAnnotation) { m_CornerAnnotation->SetText(0, cornerAnnotation.c_str()); } std::string QmitkRenderWindowWidget::GetCornerAnnotationText() const { return std::string(m_CornerAnnotation->GetText(0)); } bool QmitkRenderWindowWidget::IsRenderWindowMenuActivated() const { return m_RenderWindow->GetActivateMenuWidgetFlag(); } void QmitkRenderWindowWidget::ActivateCrosshair(bool activate) { if (nullptr == m_DataStorage) { return; } if (activate) { try { m_DataStorage->Add(m_PointSetNode); } catch(std::invalid_argument& /*e*/) { // crosshair already existing return; } } else { m_DataStorage->Remove(m_PointSetNode); } } void QmitkRenderWindowWidget::InitializeGUI() { m_Layout = new QHBoxLayout(this); m_Layout->setMargin(0); setLayout(m_Layout); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setContentsMargins(0, 0, 0, 0); if (nullptr == m_DataStorage) { return; } - if (nullptr == m_RenderingManager) - { - return; - } - - m_RenderingManager->SetDataStorage(m_DataStorage); + mitk::RenderingManager::GetInstance()->SetDataStorage(m_DataStorage); // create render window for this render window widget - m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr, m_RenderingManager, m_RenderingMode); + m_RenderWindow = new QmitkRenderWindow(this, m_WidgetName, nullptr); m_RenderWindow->SetLayoutIndex(mitk::BaseRenderer::ViewDirection::SAGITTAL); m_RenderWindow->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); - m_RenderWindow->GetSliceNavigationController()->SetRenderingManager(m_RenderingManager); m_RenderWindow->GetSliceNavigationController()->SetCrosshairEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowWidget::SetCrosshair)); connect(m_RenderWindow, &QVTKOpenGLWidget::mouseEvent, this, &QmitkRenderWindowWidget::MouseEvent); mitk::TimeGeometry::ConstPointer timeGeometry = m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()); - m_RenderingManager->InitializeViews(timeGeometry); + mitk::RenderingManager::GetInstance()->InitializeViews(timeGeometry); m_Layout->addWidget(m_RenderWindow); // add point set as a crosshair m_PointSetNode = mitk::DataNode::New(); m_PointSetNode->SetProperty("name", mitk::StringProperty::New("Crosshair of render window " + m_WidgetName.toStdString())); m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); // crosshair-node should typically be invisible // set the crosshair only visible for this specific renderer m_PointSetNode->SetBoolProperty("fixedLayer", true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(true, m_RenderWindow->GetRenderer()); m_PointSetNode->SetVisibility(false); m_PointSet = mitk::PointSet::New(); m_PointSetNode->SetData(m_PointSet); // set colors and corner annotation InitializeDecorations(); } void QmitkRenderWindowWidget::InitializeDecorations() { vtkRenderer* vtkRenderer = m_RenderWindow->GetRenderer()->GetVtkRenderer(); if (nullptr == vtkRenderer) { return; } // initialize background color gradients float black[3] = { 0.0f, 0.0f, 0.0f }; SetGradientBackgroundColors(black, black); // initialize decoration color, rectangle and annotation text float white[3] = { 1.0f, 1.0f, 1.0f }; m_DecorationColor = white; setFrameStyle(QFrame::Box | QFrame::Plain); QColor hexColor(m_DecorationColor[0] * 255, m_DecorationColor[1] * 255, m_DecorationColor[2] * 255); setStyleSheet("border: 2px solid " + hexColor.name(QColor::HexRgb)); m_CornerAnnotation = vtkSmartPointer::New(); m_CornerAnnotation->SetText(0, "Sagittal"); m_CornerAnnotation->SetMaximumFontSize(12); m_CornerAnnotation->GetTextProperty()->SetColor(m_DecorationColor[0], m_DecorationColor[1], m_DecorationColor[2]); if (0 == vtkRenderer->HasViewProp(m_CornerAnnotation)) { vtkRenderer->AddViewProp(m_CornerAnnotation); } } void QmitkRenderWindowWidget::SetCrosshair(mitk::Point3D selectedPoint) { m_PointSet->SetPoint(1, selectedPoint, 0); - m_RenderingManager->RequestUpdate(m_RenderWindow->GetRenderWindow()); + mitk::RenderingManager::GetInstance()->RequestUpdate(m_RenderWindow->GetRenderWindow()); } diff --git a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp index 7ec5518a21..e1a5a5a129 100644 --- a/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp +++ b/Modules/QtWidgets/src/QmitkStdMultiWidget.cpp @@ -1,808 +1,806 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #define SMW_INFO MITK_INFO("widget.stdmulti") #include "QmitkStdMultiWidget.h" #include "QmitkRenderWindowWidget.h" // mitk core #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // qt #include #include #include // vtk #include // c++ #include QmitkStdMultiWidget::QmitkStdMultiWidget(QWidget *parent, Qt::WindowFlags f/* = 0*/, - mitk::RenderingManager *renderingManager/* = nullptr*/, - mitk::BaseRenderer::RenderingMode renderingMode/* = mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing*/, const QString &name/* = "stdmulti"*/) - : QmitkAbstractMultiWidget(parent, f, renderingManager, renderingMode, name) + : QmitkAbstractMultiWidget(parent, f, name) , m_TimeNavigationController(nullptr) , m_PendingCrosshairPositionEvent(false) { - m_TimeNavigationController = GetRenderingManager()->GetTimeNavigationController(); + m_TimeNavigationController = mitk::RenderingManager::GetInstance()->GetTimeNavigationController(); } QmitkStdMultiWidget::~QmitkStdMultiWidget() { m_TimeNavigationController->Disconnect(GetRenderWindow1()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow2()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow3()->GetSliceNavigationController()); m_TimeNavigationController->Disconnect(GetRenderWindow4()->GetSliceNavigationController()); } void QmitkStdMultiWidget::InitializeMultiWidget() { // yellow is default color for widget4 m_DecorationColorWidget4[0] = 1.0f; m_DecorationColorWidget4[1] = 1.0f; m_DecorationColorWidget4[2] = 0.0f; SetLayout(2, 2); // transfer colors in WorldGeometry-Nodes of the associated Renderer mitk::IntProperty::Pointer layer; // of widget 1 m_PlaneNode1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetColor(GetDecorationColor(0)); layer = mitk::IntProperty::New(1000); m_PlaneNode1->SetProperty("layer", layer); // of widget 2 m_PlaneNode2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetColor(GetDecorationColor(1)); layer = mitk::IntProperty::New(1000); m_PlaneNode2->SetProperty("layer", layer); // of widget 3 m_PlaneNode3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetColor(GetDecorationColor(2)); layer = mitk::IntProperty::New(1000); m_PlaneNode3->SetProperty("layer", layer); // the parent node m_ParentNodeForGeometryPlanes = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCurrentWorldPlaneGeometryNode(); layer = mitk::IntProperty::New(1000); m_ParentNodeForGeometryPlanes->SetProperty("layer", layer); AddDisplayPlaneSubTree(); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const QString& widgetName) const { if ("axial" == widgetName) { return GetRenderWindow1(); } if ("sagittal" == widgetName) { return GetRenderWindow2(); } if ("coronal" == widgetName) { return GetRenderWindow3(); } if ("3d" == widgetName) { return GetRenderWindow4(); } return QmitkAbstractMultiWidget::GetRenderWindow(widgetName); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(const mitk::BaseRenderer::ViewDirection& viewDirection) const { return GetRenderWindow(static_cast(viewDirection)); } void QmitkStdMultiWidget::SetSelectedPosition(const mitk::Point3D& newPosition, const QString& /*widgetName*/) { GetRenderWindow1()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow2()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); GetRenderWindow3()->GetSliceNavigationController()->SelectSliceByPoint(newPosition); RequestUpdateAll(); } const mitk::Point3D QmitkStdMultiWidget::GetSelectedPosition(const QString& /*widgetName*/) const { const mitk::PlaneGeometry* plane1 = GetRenderWindow1()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane2 = GetRenderWindow2()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); const mitk::PlaneGeometry* plane3 = GetRenderWindow3()->GetSliceNavigationController()->GetCurrentPlaneGeometry(); mitk::Line3D line; if ((plane1 != nullptr) && (plane2 != nullptr) && (plane1->IntersectionLine(plane2, line))) { mitk::Point3D point; if ((plane3 != nullptr) && (plane3->IntersectionPoint(line, point))) { return point; } } return mitk::Point3D(); } void QmitkStdMultiWidget::SetCrosshairVisibility(bool visible) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible); } RequestUpdateAll(); } bool QmitkStdMultiWidget::GetCrosshairVisibility() const { bool crosshairVisibility = true; if (m_PlaneNode1.IsNotNull()) { bool visibilityProperty = false; m_PlaneNode1->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode2.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode2->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } if (m_PlaneNode3.IsNotNull()) { bool visibilityProperty = false; crosshairVisibility &= m_PlaneNode3->GetVisibility(visibilityProperty, nullptr); crosshairVisibility &= visibilityProperty; } return crosshairVisibility; } void QmitkStdMultiWidget::ResetCrosshair() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } - GetRenderingManager()->InitializeViewsByBoundingObjects(dataStorage); + mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); SetWidgetPlaneMode(mitk::InteractionSchemeSwitcher::MITKStandard); } void QmitkStdMultiWidget::SetWidgetPlaneMode(int userMode) { MITK_DEBUG << "Changing crosshair mode to " << userMode; switch (userMode) { case 0: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKStandard); break; case 1: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationUncoupled); break; case 2: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKRotationCoupled); break; case 3: SetInteractionScheme(mitk::InteractionSchemeSwitcher::MITKSwivel); break; } } mitk::SliceNavigationController* QmitkStdMultiWidget::GetTimeNavigationController() { return m_TimeNavigationController; } void QmitkStdMultiWidget::AddPlanesToDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Add(m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode1, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode2, m_ParentNodeForGeometryPlanes); dataStorage->Add(m_PlaneNode3, m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::RemovePlanesFromDataStorage() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } if (m_PlaneNode1.IsNotNull() && m_PlaneNode2.IsNotNull() && m_PlaneNode3.IsNotNull() && m_ParentNodeForGeometryPlanes.IsNotNull()) { dataStorage->Remove(m_PlaneNode1); dataStorage->Remove(m_PlaneNode2); dataStorage->Remove(m_PlaneNode3); dataStorage->Remove(m_ParentNodeForGeometryPlanes); } } void QmitkStdMultiWidget::HandleCrosshairPositionEvent() { if (!m_PendingCrosshairPositionEvent) { m_PendingCrosshairPositionEvent = true; QTimer::singleShot(0, this, SLOT(HandleCrosshairPositionEventDelayed())); } } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow(unsigned int number) const { switch (number) { case 0: return GetRenderWindow1(); case 1: return GetRenderWindow2(); case 2: return GetRenderWindow3(); case 3: return GetRenderWindow4(); default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow1() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow2() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(0, 1)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow3() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 0)); } QmitkRenderWindow* QmitkStdMultiWidget::GetRenderWindow4() const { return QmitkAbstractMultiWidget::GetRenderWindow(GetNameFromIndex(1, 1)); } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane1() const { return m_PlaneNode1; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane2() const { return m_PlaneNode2; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane3() const { return m_PlaneNode3; } mitk::DataNode::Pointer QmitkStdMultiWidget::GetWidgetPlane(unsigned number) const { switch (number) { case 1: return m_PlaneNode1; case 2: return m_PlaneNode2; case 3: return m_PlaneNode3; default: MITK_ERROR << "Requested unknown render window"; break; } return nullptr; } void QmitkStdMultiWidget::SetDecorationColor(unsigned int widgetNumber, mitk::Color color) { switch (widgetNumber) { case 0: if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetColor(color); } break; case 1: if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetColor(color); } break; case 2: if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetColor(color); } break; case 3: m_DecorationColorWidget4 = color; break; default: MITK_ERROR << "Decoration color for unknown widget!"; break; } } mitk::Color QmitkStdMultiWidget::GetDecorationColor(unsigned int widgetNumber) { // The implementation looks a bit messy here, but it avoids // synchronization of the color of the geometry nodes and an // internal member here. // Default colors were chosen for decent visibility. // Feel free to change your preferences in the workbench. float tmp[3] = { 0.0f, 0.0f, 0.0f }; switch (widgetNumber) { case 0: { if (m_PlaneNode1.IsNotNull()) { if (m_PlaneNode1->GetColor(tmp)) { return dynamic_cast(m_PlaneNode1->GetProperty("color"))->GetColor(); } } float red[3] = { 0.753f, 0.0f, 0.0f }; // This is #C00000 in hex return mitk::Color(red); } case 1: { if (m_PlaneNode2.IsNotNull()) { if (m_PlaneNode2->GetColor(tmp)) { return dynamic_cast(m_PlaneNode2->GetProperty("color"))->GetColor(); } } float green[3] = { 0.0f, 0.69f, 0.0f }; // This is #00B000 in hex return mitk::Color(green); } case 2: { if (m_PlaneNode3.IsNotNull()) { if (m_PlaneNode3->GetColor(tmp)) { return dynamic_cast(m_PlaneNode3->GetProperty("color"))->GetColor(); } } float blue[3] = { 0.0, 0.502f, 1.0f }; // This is #0080FF in hex return mitk::Color(blue); } case 3: { return m_DecorationColorWidget4; } default: MITK_ERROR << "Decoration color for unknown widget!"; float black[3] = { 0.0f, 0.0f, 0.0f }; return mitk::Color(black); } } void QmitkStdMultiWidget::mousePressEvent(QMouseEvent* e) { if (QEvent::MouseButtonPress != e->type()) { return; } auto renderWindowWidget = dynamic_cast(this->sender()); if (nullptr == renderWindowWidget) { return; } auto renderWindowWidgetPointer = GetRenderWindowWidget(renderWindowWidget->GetWidgetName()); SetActiveRenderWindowWidget(renderWindowWidgetPointer); } void QmitkStdMultiWidget::moveEvent(QMoveEvent* e) { QWidget::moveEvent(e); // it is necessary to readjust the position of the Annotation as the StdMultiWidget has moved // unfortunately it's not done by QmitkRenderWindow::moveEvent -> must be done here emit Moved(); } void QmitkStdMultiWidget::wheelEvent(QWheelEvent* e) { emit WheelMoved(e); } void QmitkStdMultiWidget::HandleCrosshairPositionEventDelayed() { auto dataStorage = GetDataStorage(); if (nullptr == dataStorage) { return; } m_PendingCrosshairPositionEvent = false; // find image with highest layer mitk::TNodePredicateDataType::Pointer isImageData = mitk::TNodePredicateDataType::New(); mitk::DataStorage::SetOfObjects::ConstPointer nodes = dataStorage->GetSubset(isImageData).GetPointer(); mitk::Point3D crosshairPos = GetSelectedPosition(""); mitk::BaseRenderer* baseRenderer = GetRenderWindow1()->GetSliceNavigationController()->GetRenderer(); auto globalCurrentTimePoint = baseRenderer->GetTime(); mitk::DataNode::Pointer node = mitk::FindTopmostVisibleNode(nodes, crosshairPos, globalCurrentTimePoint, baseRenderer); mitk::DataNode::Pointer topSourceNode; mitk::Image::Pointer image; bool isBinary = false; int component = 0; if (node.IsNotNull()) { node->GetBoolProperty("binary", isBinary); if (isBinary) { mitk::DataStorage::SetOfObjects::ConstPointer sourcenodes = dataStorage->GetSources(node, nullptr, true); if (!sourcenodes->empty()) { topSourceNode = mitk::FindTopmostVisibleNode(sourcenodes, crosshairPos, globalCurrentTimePoint, baseRenderer); } if (topSourceNode.IsNotNull()) { image = dynamic_cast(topSourceNode->GetData()); topSourceNode->GetIntProperty("Image.Displayed Component", component); } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } else { image = dynamic_cast(node->GetData()); node->GetIntProperty("Image.Displayed Component", component); } } std::string statusText; std::stringstream stream; itk::Index<3> p; unsigned int timestep = baseRenderer->GetTimeStep(); if (image.IsNotNull() && (image->GetTimeSteps() > timestep)) { image->GetGeometry()->WorldToIndex(crosshairPos, p); stream.precision(2); stream << "Position: <" << std::fixed << crosshairPos[0] << ", " << std::fixed << crosshairPos[1] << ", " << std::fixed << crosshairPos[2] << "> mm"; stream << "; Index: <" << p[0] << ", " << p[1] << ", " << p[2] << "> "; mitk::ScalarType pixelValue; mitkPixelTypeMultiplex5(mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(image->GetTimeGeometry()->TimePointToTimeStep(globalCurrentTimePoint)), p, pixelValue, component); if (fabs(pixelValue) > 1000000 || fabs(pixelValue) < 0.01) { stream << "; Time: " << globalCurrentTimePoint << " ms; Pixelvalue: " << std::scientific << pixelValue << " "; } else { stream << "; Time: " << globalCurrentTimePoint << " ms; Pixelvalue: " << pixelValue << " "; } } else { stream << "No image information at this position!"; } statusText = stream.str(); mitk::StatusBar::GetInstance()->DisplayGreyValueText(statusText.c_str()); } void QmitkStdMultiWidget::Fit() { vtkSmartPointer vtkrenderer; vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } vtkrenderer = mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetVtkRenderer(); if (nullptr != vtkrenderer) { vtkrenderer->ResetCamera(); } mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow())->GetCameraController()->Fit(); mitk::BaseRenderer::GetInstance(GetRenderWindow4()->GetRenderWindow())->GetCameraController()->Fit(); int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); vtkObject::SetGlobalWarningDisplay(w); } void QmitkStdMultiWidget::AddDisplayPlaneSubTree() { // add the displayed planes of the multiwidget to a node to which the subtree // @a planesSubTree points ... mitk::PlaneGeometryDataMapper2D::Pointer mapper; // ... of widget 1 mitk::BaseRenderer* renderer1 = mitk::BaseRenderer::GetInstance(GetRenderWindow1()->GetRenderWindow()); m_PlaneNode1 = renderer1->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode1->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode1->SetProperty("name", mitk::StringProperty::New(std::string(renderer1->GetName()) + ".plane")); m_PlaneNode1->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode1->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode1->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 2 mitk::BaseRenderer* renderer2 = mitk::BaseRenderer::GetInstance(GetRenderWindow2()->GetRenderWindow()); m_PlaneNode2 = renderer2->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode2->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode2->SetProperty("name", mitk::StringProperty::New(std::string(renderer2->GetName()) + ".plane")); m_PlaneNode2->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode2->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode2->SetMapper(mitk::BaseRenderer::Standard2D, mapper); // ... of widget 3 mitk::BaseRenderer *renderer3 = mitk::BaseRenderer::GetInstance(GetRenderWindow3()->GetRenderWindow()); m_PlaneNode3 = renderer3->GetCurrentWorldPlaneGeometryNode(); m_PlaneNode3->SetProperty("visible", mitk::BoolProperty::New(true)); m_PlaneNode3->SetProperty("name", mitk::StringProperty::New(std::string(renderer3->GetName()) + ".plane")); m_PlaneNode3->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); m_PlaneNode3->SetProperty("helper object", mitk::BoolProperty::New(true)); mapper = mitk::PlaneGeometryDataMapper2D::New(); m_PlaneNode3->SetMapper(mitk::BaseRenderer::Standard2D, mapper); m_ParentNodeForGeometryPlanes = mitk::DataNode::New(); m_ParentNodeForGeometryPlanes->SetProperty("name", mitk::StringProperty::New("Widgets")); m_ParentNodeForGeometryPlanes->SetProperty("helper object", mitk::BoolProperty::New(true)); } void QmitkStdMultiWidget::EnsureDisplayContainsPoint(mitk::BaseRenderer *renderer, const mitk::Point3D &p) { mitk::Point2D pointOnDisplay; renderer->WorldToDisplay(p, pointOnDisplay); if (pointOnDisplay[0] < renderer->GetVtkRenderer()->GetOrigin()[0] || pointOnDisplay[1] < renderer->GetVtkRenderer()->GetOrigin()[1] || pointOnDisplay[0] > renderer->GetVtkRenderer()->GetOrigin()[0] + renderer->GetViewportSize()[0] || pointOnDisplay[1] > renderer->GetVtkRenderer()->GetOrigin()[1] + renderer->GetViewportSize()[1]) { mitk::Point2D pointOnPlane; renderer->GetCurrentWorldPlaneGeometry()->Map(p, pointOnPlane); renderer->GetCameraController()->MoveCameraToPoint(pointOnPlane); } } void QmitkStdMultiWidget::SetWidgetPlaneVisibility(const char *widgetName, bool visible, mitk::BaseRenderer *renderer) { auto dataStorage = GetDataStorage(); if (nullptr != dataStorage) { mitk::DataNode* dataNode = dataStorage->GetNamedNode(widgetName); if (dataNode != nullptr) { dataNode->SetVisibility(visible, renderer); } } } void QmitkStdMultiWidget::SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer) { if (m_PlaneNode1.IsNotNull()) { m_PlaneNode1->SetVisibility(visible, renderer); } if (m_PlaneNode2.IsNotNull()) { m_PlaneNode2->SetVisibility(visible, renderer); } if (m_PlaneNode3.IsNotNull()) { m_PlaneNode3->SetVisibility(visible, renderer); } - GetRenderingManager()->RequestUpdateAll(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkStdMultiWidget::SetLayoutImpl() { CreateRenderWindowWidgets(); GetMultiWidgetLayoutManager()->SetLayoutDesign(QmitkMultiWidgetLayoutManager::LayoutDesign::DEFAULT); // Initialize views as axial, sagittal, coronal to all data objects in DataStorage auto geo = GetDataStorage()->ComputeBoundingGeometry3D(GetDataStorage()->GetAll()); - GetRenderingManager()->InitializeViews(geo); + mitk::RenderingManager::GetInstance()->InitializeViews(geo); } void QmitkStdMultiWidget::CreateRenderWindowWidgets() { // create axial render window (widget) QString renderWindowWidgetName = GetNameFromIndex(0, 0); - RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + RenderWindowWidgetPointer renderWindowWidget1 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow1 = renderWindowWidget1->GetRenderWindow(); renderWindow1->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); renderWindowWidget1->SetDecorationColor(GetDecorationColor(0)); renderWindowWidget1->SetCornerAnnotationText("Axial"); renderWindowWidget1->GetRenderWindow()->SetLayoutIndex(ViewDirection::AXIAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget1); // create sagittal render window (widget) renderWindowWidgetName = GetNameFromIndex(0, 1); - RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + RenderWindowWidgetPointer renderWindowWidget2 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow2 = renderWindowWidget2->GetRenderWindow(); renderWindow2->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); renderWindowWidget2->SetDecorationColor(GetDecorationColor(1)); renderWindowWidget2->setStyleSheet("border: 0px"); renderWindowWidget2->SetCornerAnnotationText("Sagittal"); renderWindowWidget2->GetRenderWindow()->SetLayoutIndex(ViewDirection::SAGITTAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget2); // create coronal render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 0); - RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + RenderWindowWidgetPointer renderWindowWidget3 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow3 = renderWindowWidget3->GetRenderWindow(); renderWindow3->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); renderWindowWidget3->SetDecorationColor(GetDecorationColor(2)); renderWindowWidget3->SetCornerAnnotationText("Coronal"); renderWindowWidget3->GetRenderWindow()->SetLayoutIndex(ViewDirection::CORONAL); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget3); // create 3D render window (widget) renderWindowWidgetName = GetNameFromIndex(1, 1); - RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage(), GetRenderingManager()); + RenderWindowWidgetPointer renderWindowWidget4 = std::make_shared(this, renderWindowWidgetName, GetDataStorage()); auto renderWindow4 = renderWindowWidget4->GetRenderWindow(); renderWindow4->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); renderWindowWidget4->SetDecorationColor(GetDecorationColor(3)); renderWindowWidget4->SetCornerAnnotationText("3D"); renderWindowWidget4->GetRenderWindow()->SetLayoutIndex(ViewDirection::THREE_D); mitk::BaseRenderer::GetInstance(renderWindowWidget4->GetRenderWindow()->GetRenderWindow())->SetMapperID(mitk::BaseRenderer::Standard3D); AddRenderWindowWidget(renderWindowWidgetName, renderWindowWidget4); SetActiveRenderWindowWidget(renderWindowWidget1); // connect to the "time navigation controller": send time via sliceNavigationControllers m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow1->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow2->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow3->GetSliceNavigationController(), false); m_TimeNavigationController->ConnectGeometryTimeEvent(renderWindow4->GetSliceNavigationController(), false); renderWindow1->GetSliceNavigationController()->ConnectGeometrySendEvent( mitk::BaseRenderer::GetInstance(renderWindow4->GetRenderWindow())); // reverse connection between sliceNavigationControllers and timeNavigationController renderWindow1->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); renderWindow2->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); renderWindow3->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); //renderWindow4->GetSliceNavigationController()->ConnectGeometryTimeEvent(m_TimeNavigationController, false); auto layoutManager = GetMultiWidgetLayoutManager(); connect(renderWindowWidget1.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow1, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow1, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow1, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow1, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget2.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow2, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow2, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow2, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow2, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget3.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow3, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow3, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow3, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow3, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); connect(renderWindowWidget4.get(), &QmitkRenderWindowWidget::MouseEvent, this, &QmitkStdMultiWidget::mousePressEvent); connect(renderWindow4, &QmitkRenderWindow::ResetView, this, &QmitkStdMultiWidget::ResetCrosshair); connect(renderWindow4, &QmitkRenderWindow::CrosshairVisibilityChanged, this, &QmitkStdMultiWidget::SetCrosshairVisibility); connect(renderWindow4, &QmitkRenderWindow::CrosshairRotationModeChanged, this, &QmitkStdMultiWidget::SetWidgetPlaneMode); connect(renderWindow4, &QmitkRenderWindow::LayoutDesignChanged, layoutManager, &QmitkMultiWidgetLayoutManager::SetLayoutDesign); } diff --git a/Modules/QtWidgetsExt/src/QmitkSelectableGLWidget.cpp b/Modules/QtWidgetsExt/src/QmitkSelectableGLWidget.cpp index ab310990b4..5f1811d3dd 100644 --- a/Modules/QtWidgetsExt/src/QmitkSelectableGLWidget.cpp +++ b/Modules/QtWidgetsExt/src/QmitkSelectableGLWidget.cpp @@ -1,106 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkSelectableGLWidget.h" #include "QmitkRenderWindow.h" #include QmitkSelectableGLWidget::QmitkSelectableGLWidget(QWidget *parent) : QWidget(parent), m_Ui(new Ui::QmitkSelectableGLWidget) { m_Ui->setupUi(this); QLayout *hlayout; hlayout = m_Ui->hboxLayout; hlayout->setMargin(3); QString rendererName("Renderer::"); rendererName += objectName(); // create Renderer - m_Renderer = mitk::VtkPropRenderer::New( - qPrintable(rendererName), nullptr, mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing); + m_Renderer = mitk::VtkPropRenderer::New(qPrintable(rendererName), nullptr); // create widget QString composedName("QSGLWt::"); if (!objectName().isEmpty()) composedName += objectName(); else composedName += "QmitkGLWidget"; /* * here is the place to define QT-Flags to enable and disable certain OpenGL elements, like StencilBuffer, RGBA and so * on. * See QGLFormat for futher informations * QGL::AlphaChannel: Enable Alpha in Framebuffer * QGL::Rgba enable use of rgba rather than color_index * QGL::StencilBuffer for use of stencilbuffer in OpenGL */ m_RenderWindow = new QmitkRenderWindow(this, composedName, m_Renderer); hlayout->addWidget(m_RenderWindow); } QmitkSelectableGLWidget::~QmitkSelectableGLWidget() { delete m_Ui; } mitk::VtkPropRenderer *QmitkSelectableGLWidget::GetRenderer() { return m_Renderer.GetPointer(); } QmitkRenderWindow *QmitkSelectableGLWidget::GetRenderWindow() const { return m_RenderWindow; } void QmitkSelectableGLWidget::wheelEvent(QWheelEvent *e) { if (m_RenderWindow->GetSliceNavigationController()->GetSliceLocked()) return; mitk::Stepper *stepper = m_RenderWindow->GetSliceNavigationController()->GetSlice(); if (stepper->GetSteps() <= 1) { stepper = m_RenderWindow->GetSliceNavigationController()->GetTime(); } if (e->orientation() * e->delta() > 0) { stepper->Next(); } else { stepper->Previous(); } } mitk::SliceNavigationController *QmitkSelectableGLWidget::GetSliceNavigationController() const { return m_RenderWindow->GetSliceNavigationController(); } mitk::CameraRotationController *QmitkSelectableGLWidget::GetCameraRotationController() const { return m_RenderWindow->GetCameraRotationController(); } mitk::BaseController *QmitkSelectableGLWidget::GetController() const { return m_RenderWindow->GetController(); } diff --git a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp index 3de4745c14..8db32bf0e9 100644 --- a/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp +++ b/Modules/Segmentation/Interactions/mitkLiveWireTool2D.cpp @@ -1,590 +1,590 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, LiveWireTool2D, "LiveWire tool"); } mitk::LiveWireTool2D::LiveWireTool2D() : SegTool2D("LiveWireTool"), m_CreateAndUseDynamicCosts(false) { } mitk::LiveWireTool2D::~LiveWireTool2D() { this->ClearSegmentation(); } void mitk::LiveWireTool2D::RemoveHelperObjects() { auto dataStorage = m_ToolManager->GetDataStorage(); if (nullptr == dataStorage) return; for (const auto &editingContour : m_EditingContours) dataStorage->Remove(editingContour.first); for (const auto &workingContour : m_WorkingContours) dataStorage->Remove(workingContour.first); if (m_EditingContourNode.IsNotNull()) dataStorage->Remove(m_EditingContourNode); if (m_LiveWireContourNode.IsNotNull()) dataStorage->Remove(m_LiveWireContourNode); if (m_ContourNode.IsNotNull()) dataStorage->Remove(m_ContourNode); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::LiveWireTool2D::ReleaseHelperObjects() { this->RemoveHelperObjects(); m_EditingContours.clear(); m_WorkingContours.clear(); m_EditingContourNode = nullptr; m_EditingContour = nullptr; m_LiveWireContourNode = nullptr; m_LiveWireContour = nullptr; m_ContourNode = nullptr; m_Contour = nullptr; } void mitk::LiveWireTool2D::ReleaseInteractors() { this->EnableContourLiveWireInteraction(false); m_LiveWireInteractors.clear(); } void mitk::LiveWireTool2D::ConnectActionsAndFunctions() { CONNECT_CONDITION("CheckContourClosed", OnCheckPoint); CONNECT_FUNCTION("InitObject", OnInitLiveWire); CONNECT_FUNCTION("AddPoint", OnAddPoint); CONNECT_FUNCTION("CtrlAddPoint", OnAddPoint); CONNECT_FUNCTION("MovePoint", OnMouseMoveNoDynamicCosts); CONNECT_FUNCTION("FinishContour", OnFinish); CONNECT_FUNCTION("DeletePoint", OnLastSegmentDelete); CONNECT_FUNCTION("CtrlMovePoint", OnMouseMoved); } const char **mitk::LiveWireTool2D::GetXPM() const { return mitkLiveWireTool2D_xpm; } us::ModuleResource mitk::LiveWireTool2D::GetIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire_48x48.png"); } us::ModuleResource mitk::LiveWireTool2D::GetCursorIconResource() const { return us::GetModuleContext()->GetModule()->GetResource("LiveWire_Cursor_32x32.png"); } const char *mitk::LiveWireTool2D::GetName() const { return "Live Wire"; } void mitk::LiveWireTool2D::Activated() { Superclass::Activated(); this->ResetToStartState(); this->EnableContourLiveWireInteraction(true); } void mitk::LiveWireTool2D::Deactivated() { this->ConfirmSegmentation(); Superclass::Deactivated(); } void mitk::LiveWireTool2D::EnableContourLiveWireInteraction(bool on) { for (const auto &interactor : m_LiveWireInteractors) interactor->EnableInteraction(on); } void mitk::LiveWireTool2D::ConfirmSegmentation() { auto workingNode = m_ToolManager->GetWorkingData(0); if (nullptr == workingNode) return; auto workingImage = dynamic_cast(workingNode->GetData()); if (nullptr == workingImage) return; std::vector sliceInfos; sliceInfos.reserve(m_WorkingContours.size()); for (const auto &workingContour : m_WorkingContours) { auto contour = dynamic_cast(workingContour.first->GetData()); if (nullptr == contour) continue; const auto numberOfTimeSteps = contour->GetTimeSteps(); for (std::remove_const_t t = 0; t < numberOfTimeSteps; ++t) { if (contour->IsEmptyTimeStep(t)) continue; auto workingSlice = this->GetAffectedImageSliceAs2DImage(workingContour.second, workingImage, t); auto projectedContour = ContourModelUtils::ProjectContourTo2DSlice(workingSlice, contour, true, false); ContourModelUtils::FillContourInSlice(projectedContour, t, workingSlice, workingImage, 1); sliceInfos.emplace_back(workingSlice, workingContour.second, t); this->WriteSliceToVolume(sliceInfos.back()); } } this->WriteBackSegmentationResult(sliceInfos, false); this->ClearSegmentation(); } void mitk::LiveWireTool2D::ClearSegmentation() { this->ReleaseHelperObjects(); this->ReleaseInteractors(); this->ResetToStartState(); } bool mitk::LiveWireTool2D::IsPositionEventInsideImageRegion(mitk::InteractionPositionEvent *positionEvent, mitk::BaseData *data) { bool isPositionEventInsideImageRegion = nullptr != data && data->GetGeometry()->IsInside(positionEvent->GetPositionInWorld()); if (!isPositionEventInsideImageRegion) MITK_WARN("LiveWireTool2D") << "PositionEvent is outside ImageRegion!"; return isPositionEventInsideImageRegion; } void mitk::LiveWireTool2D::OnInitLiveWire(StateMachineAction *, InteractionEvent *interactionEvent) { auto positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) return; auto workingDataNode = m_ToolManager->GetWorkingData(0); if (!IsPositionEventInsideImageRegion(positionEvent, workingDataNode->GetData())) { this->ResetToStartState(); return; } m_LastEventSender = positionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); auto t = positionEvent->GetSender()->GetTimeStep(); m_Contour = mitk::ContourModel::New(); m_Contour->Expand(t + 1); m_ContourNode = mitk::DataNode::New(); m_ContourNode->SetData(m_Contour); m_ContourNode->SetName("working contour node"); m_ContourNode->SetProperty("layer", IntProperty::New(100)); m_ContourNode->AddProperty("fixedLayer", BoolProperty::New(true)); m_ContourNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_ContourNode->AddProperty("contour.color", ColorProperty::New(1.0f, 1.0f, 0.0f), nullptr, true); m_ContourNode->AddProperty("contour.points.color", ColorProperty::New(1.0f, 0.0f, 0.1f), nullptr, true); m_ContourNode->AddProperty("contour.controlpoints.show", BoolProperty::New(true), nullptr, true); m_LiveWireContour = mitk::ContourModel::New(); m_LiveWireContour->Expand(t + 1); m_LiveWireContourNode = mitk::DataNode::New(); m_LiveWireContourNode->SetData(m_LiveWireContour); m_LiveWireContourNode->SetName("active livewire node"); m_LiveWireContourNode->SetProperty("layer", IntProperty::New(101)); m_LiveWireContourNode->AddProperty("fixedLayer", BoolProperty::New(true)); m_LiveWireContourNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_LiveWireContourNode->AddProperty("contour.color", ColorProperty::New(0.1f, 1.0f, 0.1f), nullptr, true); m_LiveWireContourNode->AddProperty("contour.width", mitk::FloatProperty::New(4.0f), nullptr, true); m_EditingContour = mitk::ContourModel::New(); m_EditingContour->Expand(t + 1); m_EditingContourNode = mitk::DataNode::New(); m_EditingContourNode->SetData(m_EditingContour); m_EditingContourNode->SetName("editing node"); m_EditingContourNode->SetProperty("layer", IntProperty::New(102)); m_EditingContourNode->AddProperty("fixedLayer", BoolProperty::New(true)); m_EditingContourNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_EditingContourNode->AddProperty("contour.color", ColorProperty::New(0.1f, 1.0f, 0.1f), nullptr, true); m_EditingContourNode->AddProperty("contour.points.color", ColorProperty::New(0.0f, 0.0f, 1.0f), nullptr, true); m_EditingContourNode->AddProperty("contour.width", mitk::FloatProperty::New(4.0f), nullptr, true); auto dataStorage = m_ToolManager->GetDataStorage(); dataStorage->Add(m_ContourNode, workingDataNode); dataStorage->Add(m_LiveWireContourNode, workingDataNode); dataStorage->Add(m_EditingContourNode, workingDataNode); // Set current slice as input for ImageToLiveWireContourFilter m_WorkingSlice = this->GetAffectedReferenceSlice(positionEvent); auto origin = m_WorkingSlice->GetSlicedGeometry()->GetOrigin(); m_WorkingSlice->GetSlicedGeometry()->WorldToIndex(origin, origin); m_WorkingSlice->GetSlicedGeometry()->IndexToWorld(origin, origin); m_WorkingSlice->GetSlicedGeometry()->SetOrigin(origin); m_LiveWireFilter = ImageLiveWireContourModelFilter::New(); m_LiveWireFilter->SetInput(m_WorkingSlice); // Map click to pixel coordinates auto click = positionEvent->GetPositionInWorld(); itk::Index<3> idx; m_WorkingSlice->GetGeometry()->WorldToIndex(click, idx); // Get the pixel with the highest gradient in a 7x7 region itk::Index<3> indexWithHighestGradient; AccessFixedDimensionByItk_2(m_WorkingSlice, FindHighestGradientMagnitudeByITK, 2, idx, indexWithHighestGradient); click[0] = indexWithHighestGradient[0]; click[1] = indexWithHighestGradient[1]; click[2] = indexWithHighestGradient[2]; m_WorkingSlice->GetGeometry()->IndexToWorld(click, click); // Set initial start point m_Contour->AddVertex(click, true, t); m_LiveWireFilter->SetStartPoint(click); // Remember PlaneGeometry to determine if events were triggered in the same plane m_PlaneGeometry = interactionEvent->GetSender()->GetCurrentWorldPlaneGeometry(); m_CreateAndUseDynamicCosts = true; mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } void mitk::LiveWireTool2D::OnAddPoint(StateMachineAction *, InteractionEvent *interactionEvent) { // Complete LiveWire interaction for the last segment. Add current LiveWire contour to // the finished contour and reset to start a new segment and computation. auto positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) return; if (m_PlaneGeometry.IsNotNull()) { // Check if the point is in the correct slice if (m_PlaneGeometry->DistanceFromPlane(positionEvent->GetPositionInWorld()) > mitk::sqrteps) return; } auto t = static_cast(positionEvent->GetSender()->GetTimeStep()); // Add repulsive points to avoid getting the same path again std::for_each(m_LiveWireContour->IteratorBegin(), m_LiveWireContour->IteratorEnd(), [this](ContourElement::VertexType *vertex) { ImageLiveWireContourModelFilter::InternalImageType::IndexType idx; this->m_WorkingSlice->GetGeometry()->WorldToIndex(vertex->Coordinates, idx); this->m_LiveWireFilter->AddRepulsivePoint(idx); }); // Remove duplicate first vertex, it's already contained in m_Contour m_LiveWireContour->RemoveVertexAt(0, t); // Set last point as control point m_LiveWireContour->SetControlVertexAt(m_LiveWireContour->GetNumberOfVertices(t) - 1, t); // Merge contours m_Contour->Concatenate(m_LiveWireContour, t); // Clear the LiveWire contour and reset the corresponding DataNode m_LiveWireContour->Clear(t); // Set new start point m_LiveWireFilter->SetStartPoint(positionEvent->GetPositionInWorld()); if (m_CreateAndUseDynamicCosts) { // Use dynamic cost map for next update m_LiveWireFilter->CreateDynamicCostMap(m_Contour); m_LiveWireFilter->SetUseDynamicCostMap(true); } mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } void mitk::LiveWireTool2D::OnMouseMoved(StateMachineAction *, InteractionEvent *interactionEvent) { // Compute LiveWire segment from last control point to current mouse position auto positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) return; auto t = positionEvent->GetSender()->GetTimeStep(); m_LiveWireFilter->SetEndPoint(positionEvent->GetPositionInWorld()); m_LiveWireFilter->SetTimeStep(t); m_LiveWireFilter->Update(); m_LiveWireContour = this->m_LiveWireFilter->GetOutput(); m_LiveWireContourNode->SetData(this->m_LiveWireContour); - positionEvent->GetSender()->GetRenderingManager()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); + RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); } void mitk::LiveWireTool2D::OnMouseMoveNoDynamicCosts(StateMachineAction *, InteractionEvent *interactionEvent) { m_LiveWireFilter->SetUseDynamicCostMap(false); this->OnMouseMoved(nullptr, interactionEvent); m_LiveWireFilter->SetUseDynamicCostMap(true); } bool mitk::LiveWireTool2D::OnCheckPoint(const InteractionEvent *interactionEvent) { // Check double click on first control point to finish the LiveWire tool auto positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) return false; auto t = static_cast(positionEvent->GetSender()->GetTimeStep()); mitk::Point3D click = positionEvent->GetPositionInWorld(); mitk::Point3D first = this->m_Contour->GetVertexAt(0, t)->Coordinates; return first.EuclideanDistanceTo(click) < 4.5; } void mitk::LiveWireTool2D::OnFinish(StateMachineAction *, InteractionEvent *interactionEvent) { // Finish LiveWire tool interaction auto positionEvent = dynamic_cast(interactionEvent); if (nullptr == positionEvent) return; // Have to do that here so that the m_LastEventSender is set correctly mitk::SegTool2D::AddContourmarker(); auto t = static_cast(positionEvent->GetSender()->GetTimeStep()); // Remove last control point added by double click m_Contour->RemoveVertexAt(m_Contour->GetNumberOfVertices(t) - 1, t); // Save contour and corresponding plane geometry to list this->m_WorkingContours.emplace_back(std::make_pair(m_ContourNode, positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()->Clone())); this->m_EditingContours.emplace_back(std::make_pair(m_EditingContourNode, positionEvent->GetSender()->GetCurrentWorldPlaneGeometry()->Clone())); m_LiveWireFilter->SetUseDynamicCostMap(false); this->FinishTool(); } void mitk::LiveWireTool2D::FinishTool() { auto numberOfTimesteps = static_cast(m_Contour->GetTimeGeometry()->CountTimeSteps()); for (int i = 0; i <= numberOfTimesteps; ++i) m_Contour->Close(i); m_ToolManager->GetDataStorage()->Remove(m_LiveWireContourNode); m_LiveWireContourNode = nullptr; m_LiveWireContour = nullptr; m_ContourInteractor = mitk::ContourModelLiveWireInteractor::New(); m_ContourInteractor->SetDataNode(m_ContourNode); m_ContourInteractor->LoadStateMachine("ContourModelModificationInteractor.xml", us::GetModuleContext()->GetModule()); m_ContourInteractor->SetEventConfig("ContourModelModificationConfig.xml", us::GetModuleContext()->GetModule()); m_ContourInteractor->SetWorkingImage(this->m_WorkingSlice); m_ContourInteractor->SetEditingContourModelNode(this->m_EditingContourNode); m_ContourNode->SetDataInteractor(m_ContourInteractor.GetPointer()); this->m_LiveWireInteractors.push_back(m_ContourInteractor); } void mitk::LiveWireTool2D::OnLastSegmentDelete(StateMachineAction *, InteractionEvent *interactionEvent) { int t = static_cast(interactionEvent->GetSender()->GetTimeStep()); // If last point of current contour will be removed go to start state and remove nodes if (m_Contour->GetNumberOfVertices(t) <= 1) { auto dataStorage = m_ToolManager->GetDataStorage(); dataStorage->Remove(m_LiveWireContourNode); dataStorage->Remove(m_ContourNode); dataStorage->Remove(m_EditingContourNode); m_LiveWireContour = mitk::ContourModel::New(); m_LiveWireContourNode->SetData(m_LiveWireContour); m_Contour = mitk::ContourModel::New(); m_ContourNode->SetData(m_Contour); this->ResetToStartState(); } else // Remove last segment from contour and reset LiveWire contour { m_LiveWireContour = mitk::ContourModel::New(); m_LiveWireContourNode->SetData(m_LiveWireContour); auto newContour = mitk::ContourModel::New(); newContour->Expand(m_Contour->GetTimeSteps()); auto begin = m_Contour->IteratorBegin(); // Iterate from last point to next active point auto newLast = m_Contour->IteratorBegin() + (m_Contour->GetNumberOfVertices() - 1); // Go at least one down if (newLast != begin) --newLast; // Search next active control point while (newLast != begin && !((*newLast)->IsControlPoint)) --newLast; // Set position of start point for LiveWire filter to coordinates of the new last point m_LiveWireFilter->SetStartPoint((*newLast)->Coordinates); auto it = m_Contour->IteratorBegin(); // Fll new Contour while (it <= newLast) { newContour->AddVertex((*it)->Coordinates, (*it)->IsControlPoint, t); ++it; } newContour->SetClosed(m_Contour->IsClosed()); m_ContourNode->SetData(newContour); m_Contour = newContour; mitk::RenderingManager::GetInstance()->RequestUpdate(interactionEvent->GetSender()->GetRenderWindow()); } } template void mitk::LiveWireTool2D::FindHighestGradientMagnitudeByITK(itk::Image *inputImage, itk::Index<3> &index, itk::Index<3> &returnIndex) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; const auto MAX_X = inputImage->GetLargestPossibleRegion().GetSize()[0]; const auto MAX_Y = inputImage->GetLargestPossibleRegion().GetSize()[1]; returnIndex[0] = index[0]; returnIndex[1] = index[1]; returnIndex[2] = 0.0; double gradientMagnitude = 0.0; double maxGradientMagnitude = 0.0; // The size and thus the region of 7x7 is only used to calculate the gradient magnitude in that region, // not for searching the maximum value. // Maximum value in each direction for size typename InputImageType::SizeType size; size[0] = 7; size[1] = 7; // Minimum value in each direction for startRegion IndexType startRegion; startRegion[0] = index[0] - 3; startRegion[1] = index[1] - 3; if (startRegion[0] < 0) startRegion[0] = 0; if (startRegion[1] < 0) startRegion[1] = 0; if (MAX_X - index[0] < 7) startRegion[0] = MAX_X - 7; if (MAX_Y - index[1] < 7) startRegion[1] = MAX_Y - 7; index[0] = startRegion[0] + 3; index[1] = startRegion[1] + 3; typename InputImageType::RegionType region; region.SetSize(size); region.SetIndex(startRegion); typedef typename itk::GradientMagnitudeImageFilter GradientMagnitudeFilterType; typename GradientMagnitudeFilterType::Pointer gradientFilter = GradientMagnitudeFilterType::New(); gradientFilter->SetInput(inputImage); gradientFilter->GetOutput()->SetRequestedRegion(region); gradientFilter->Update(); typename InputImageType::Pointer gradientMagnitudeImage; gradientMagnitudeImage = gradientFilter->GetOutput(); IndexType currentIndex; currentIndex[0] = 0; currentIndex[1] = 0; // Search max (approximate) gradient magnitude for (int x = -1; x <= 1; ++x) { currentIndex[0] = index[0] + x; for (int y = -1; y <= 1; ++y) { currentIndex[1] = index[1] + y; gradientMagnitude = gradientMagnitudeImage->GetPixel(currentIndex); // Check for new max if (maxGradientMagnitude < gradientMagnitude) { maxGradientMagnitude = gradientMagnitude; returnIndex[0] = currentIndex[0]; returnIndex[1] = currentIndex[1]; returnIndex[2] = 0.0; } } currentIndex[1] = index[1]; } } diff --git a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp index 5cfa6801d4..a1b7a7735e 100644 --- a/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp +++ b/Modules/Segmentation/Interactions/mitkSegmentationInteractor.cpp @@ -1,65 +1,65 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkSegmentationInteractor.h" #include "mitkInteractionPositionEvent.h" #include "mitkLabelSetImage.h" #include "mitkToolManager.h" #include "mitkToolManagerProvider.h" #include #include void mitk::SegmentationInteractor::ConnectActionsAndFunctions() { Superclass::ConnectActionsAndFunctions(); // CONNECT_FUNCTION("change_active_label", ChangeActiveLabel); } bool mitk::SegmentationInteractor::ChangeActiveLabel(StateMachineAction *, InteractionEvent *interactionEvent) { BaseRenderer::Pointer sender = interactionEvent->GetSender(); auto *positionEvent = static_cast(interactionEvent); // MLI TODO // m_LastDisplayCoordinate = m_CurrentDisplayCoordinate; // m_CurrentDisplayCoordinate = positionEvent->GetPointerPositionOnScreen(); mitk::ToolManager *toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(toolManager); DataNode *workingNode(toolManager->GetWorkingData(0)); if (workingNode) { auto *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); int timestep = positionEvent->GetSender()->GetTimeStep(); int pixelValue = static_cast(workingImage->GetPixelValueByWorldCoordinate(positionEvent->GetPositionInWorld(), timestep)); workingImage->GetActiveLabelSet()->SetActiveLabel(pixelValue); // can be the background // Call Events // workingImage->ActiveLabelEvent.Send(pixelValue); // MLI TODO // toolManager->WorkingDataModified.Send(); } - sender->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); return true; } diff --git a/Modules/Segmentation/Testing/mitkContourMapper2DTest.cpp b/Modules/Segmentation/Testing/mitkContourMapper2DTest.cpp index 8506ace53e..e06c23cbd3 100644 --- a/Modules/Segmentation/Testing/mitkContourMapper2DTest.cpp +++ b/Modules/Segmentation/Testing/mitkContourMapper2DTest.cpp @@ -1,80 +1,80 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCommon.h" #include "mitkContour.h" #include "mitkContourMapper2D.h" #include "mitkDataNode.h" #include "mitkStandaloneDataStorage.h" #include "mitkVtkPropRenderer.h" #include int mitkContourMapper2DTest(int /*argc*/, char * /*argv*/ []) { mitk::Contour::Pointer contour; mitk::ContourMapper2D::Pointer contourMapper; mitk::DataNode::Pointer node; contourMapper = mitk::ContourMapper2D::New(); node = mitk::DataNode::New(); std::cout << "Testing mitk::ContourMapper2D::New(): "; contour = mitk::Contour::New(); node->SetData(contour); if (contour.IsNull()) { std::cout << "[FAILED]" << std::endl; return EXIT_FAILURE; } else { std::cout << "[PASSED]" << std::endl; } contourMapper->SetDataNode(node); contourMapper->Update(nullptr); auto *testContour = (mitk::Contour *)contourMapper->GetInput(); std::cout << testContour << std::endl; mitk::StandaloneDataStorage::Pointer ds = mitk::StandaloneDataStorage::New(); ds->Add(node); mitk::BoundingBox::Pointer bounds = ds->ComputeBoundingBox(); std::cout << "bounds: " << bounds << std::endl; bounds = ds->ComputeVisibleBoundingBox(); std::cout << "visible bounds: " << bounds << std::endl; vtkRenderWindow *renWin = vtkRenderWindow::New(); - mitk::VtkPropRenderer::Pointer renderer = mitk::VtkPropRenderer::New( - "ContourRenderer", renWin, mitk::RenderingManager::GetInstance(), mitk::BaseRenderer::RenderingMode::NoAntiAliasing); + mitk::RenderingManager::GetInstance()->SetAntiAliasing(mitk::AntiAliasing::None); + auto renderer = mitk::VtkPropRenderer::New("ContourRenderer", renWin); std::cout << "Testing mitk::BaseRenderer::SetData()" << std::endl; renderer->SetDataStorage(ds); std::cout << "[TEST DONE]" << std::endl; renWin->Delete(); return EXIT_SUCCESS; } diff --git a/Modules/TubeGraph/src/Interactions/mitkTubeGraphDataInteractor.cpp b/Modules/TubeGraph/src/Interactions/mitkTubeGraphDataInteractor.cpp index d1011562f2..4927b08e83 100644 --- a/Modules/TubeGraph/src/Interactions/mitkTubeGraphDataInteractor.cpp +++ b/Modules/TubeGraph/src/Interactions/mitkTubeGraphDataInteractor.cpp @@ -1,289 +1,289 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTubeGraphDataInteractor.h" #include #include #include #include "mitkTubeGraphPicker.h" #include #include #include #include #include mitk::TubeGraphDataInteractor::TubeGraphDataInteractor() : m_LastPickedTube(TubeGraph::ErrorId), m_SecondLastPickedTube(TubeGraph::ErrorId), m_ActivationMode(None), m_ActionMode(AttributationMode) { } mitk::TubeGraphDataInteractor::~TubeGraphDataInteractor() {} void mitk::TubeGraphDataInteractor::ConnectActionsAndFunctions() { // **Conditions** that can be used in the state machine, to ensure that certain conditions are met, before actually // executing an action CONNECT_CONDITION("isOverTube", CheckOverTube); // **Function** in the statmachine patterns also referred to as **Actions** CONNECT_FUNCTION("selectTube", SelectTube); CONNECT_FUNCTION("deselectTube", DeselectTube); } void mitk::TubeGraphDataInteractor::DataNodeChanged() { if (GetDataNode() != nullptr) { if (GetDataNode()->GetData() != nullptr) { m_TubeGraph = dynamic_cast(GetDataNode()->GetData()); m_TubeGraphProperty = dynamic_cast( m_TubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer()); if (m_TubeGraphProperty.IsNull()) MITK_ERROR << "Something went wrong! No tube graph property!"; } else m_TubeGraph = nullptr; } else m_TubeGraph = nullptr; } bool mitk::TubeGraphDataInteractor::CheckOverTube(const InteractionEvent *interactionEvent) { const auto *positionEvent = dynamic_cast(interactionEvent); if (positionEvent == nullptr) return false; auto *picker = new mitk::TubeGraphPicker(); picker->SetTubeGraph(m_TubeGraph); auto pickedTube = picker->GetPickedTube(positionEvent->GetPositionInWorld()); TubeGraph::TubeDescriptorType tubeDescriptor = pickedTube.first; if (tubeDescriptor != TubeGraph::ErrorId) { m_LastPickedElement = pickedTube.second; m_SecondLastPickedTube = m_LastPickedTube; m_LastPickedTube = tubeDescriptor; return true; } else // nothing picked return false; } -void mitk::TubeGraphDataInteractor::SelectTube(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::TubeGraphDataInteractor::SelectTube(StateMachineAction *, InteractionEvent *) { if (m_TubeGraph.IsNull()) return; this->SelectTubesByActivationModus(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); if (m_ActivationMode != None) { // show tube id on status bar std::stringstream displayText; displayText << "Picked tube: ID [" << m_LastPickedTube.first << "," << m_LastPickedTube.second << "]"; StatusBar::GetInstance()->DisplayText(displayText.str().c_str()); // TODO!!! this->InvokeEvent(SelectionChangedTubeGraphEvent()); } } -void mitk::TubeGraphDataInteractor::DeselectTube(StateMachineAction *, InteractionEvent *interactionEvent) +void mitk::TubeGraphDataInteractor::DeselectTube(StateMachineAction *, InteractionEvent *) { if (m_TubeGraph.IsNull()) return; if ((m_ActivationMode != Multiple) && (m_ActivationMode != Points)) { m_TubeGraphProperty->DeactivateAllTubes(); - interactionEvent->GetSender()->GetRenderingManager()->RequestUpdateAll(); + RenderingManager::GetInstance()->RequestUpdateAll(); // TODO!!!this->InvokeEvent(SelectionChangedTubeGraphEvent()); } // show info on status bar StatusBar::GetInstance()->DisplayText("No tube hit!"); } void mitk::TubeGraphDataInteractor::SetActivationMode(const ActivationMode &activationMode) { m_ActivationMode = activationMode; if (m_TubeGraph.IsNotNull()) if (m_LastPickedTube != mitk::TubeGraph::ErrorId) this->UpdateActivation(); } mitk::TubeGraphDataInteractor::ActivationMode mitk::TubeGraphDataInteractor::GetActivationMode() { return m_ActivationMode; } void mitk::TubeGraphDataInteractor::SetActionMode(const ActionMode &actionMode) { m_ActionMode = actionMode; } mitk::TubeGraphDataInteractor::ActionMode mitk::TubeGraphDataInteractor::GetActionMode() { return m_ActionMode; } void mitk::TubeGraphDataInteractor::SelectTubesByActivationModus() { if (m_LastPickedTube != mitk::TubeGraph::ErrorId) { this->UpdateActivation(); } } void mitk::TubeGraphDataInteractor::UpdateActivation() { if (m_ActionMode == RootMode) { m_TubeGraphProperty->DeactivateAllTubes(); m_TubeGraphProperty->SetTubeActive(m_LastPickedTube, true); // QmitkTubeGraphSelectRootDialog* dialog = new QmitkTubeGraphSelectRootDialog(m_Parent); // int dialogReturnValue = dialog->exec(); // delete dialog; // if ( dialogReturnValue != QDialog::Rejected ) // user doesn't clicked cancel or pressed Esc or something similar //{ m_TubeGraph->SetRootTube(m_LastPickedTube); //} m_TubeGraphProperty->DeactivateAllTubes(); RenderingManager::GetInstance()->RequestUpdateAll(); } else { switch (m_ActivationMode) { case None: { m_TubeGraphProperty->DeactivateAllTubes(); } break; case Single: { m_TubeGraphProperty->DeactivateAllTubes(); m_TubeGraphProperty->SetTubeActive(m_LastPickedTube, true); } break; case Multiple: { // special deactivation for multiple modus // if activated--> deactivate; if not activated--> activate if (m_TubeGraphProperty->IsTubeActive(m_LastPickedTube)) m_TubeGraphProperty->SetTubeActive(m_LastPickedTube, false); else m_TubeGraphProperty->SetTubeActive(m_LastPickedTube, true); } break; case ToRoot: { m_TubeGraphProperty->DeactivateAllTubes(); std::vector activeTubes = this->GetTubesToRoot(); m_TubeGraphProperty->SetTubesActive(activeTubes); } break; case ToPeriphery: { m_TubeGraphProperty->DeactivateAllTubes(); std::vector activeTubes = this->GetPathToPeriphery(); m_TubeGraphProperty->SetTubesActive(activeTubes); } break; case Points: { m_TubeGraphProperty->DeactivateAllTubes(); std::vector activeTubes = this->GetTubesBetweenPoints(); m_TubeGraphProperty->SetTubesActive(activeTubes); } break; default: MITK_WARN << "Unknown tube graph interaction mode!"; break; } } } std::vector mitk::TubeGraphDataInteractor::GetTubesToRoot() { TubeGraph::TubeDescriptorType root = m_TubeGraph->GetRootTube(); if (root == TubeGraph::ErrorId) { root = m_TubeGraph->GetThickestTube(); m_TubeGraph->SetRootTube(root); } return this->GetPathBetweenTubes(m_LastPickedTube, root); } std::vector mitk::TubeGraphDataInteractor::GetTubesBetweenPoints() { return this->GetPathBetweenTubes(m_LastPickedTube, m_SecondLastPickedTube); } std::vector mitk::TubeGraphDataInteractor::GetPathBetweenTubes( const mitk::TubeGraph::TubeDescriptorType &start, const mitk::TubeGraph::TubeDescriptorType &end) { std::vector solutionPath; if ((start != TubeGraph::ErrorId) && (end != TubeGraph::ErrorId)) { if (start != end) solutionPath = m_TubeGraph->SearchAllPathBetweenVertices(start, end); else solutionPath.push_back(start); } return solutionPath; } std::vector mitk::TubeGraphDataInteractor::GetPathToPeriphery() { std::vector solutionPath; if (m_LastPickedTube != TubeGraph::ErrorId) solutionPath = m_TubeGraph->SearchPathToPeriphery(m_LastPickedTube); return solutionPath; } void mitk::TubeGraphDataInteractor::ResetPickedTubes() { m_LastPickedTube = TubeGraph::ErrorId; m_SecondLastPickedTube = TubeGraph::ErrorId; } mitk::Point3D mitk::TubeGraphDataInteractor::GetLastPickedPosition() { if (m_LastPickedElement) return m_LastPickedElement->GetCoordinates(); else return mitk::Point3D(); } diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp index 45d9071259..fa6f8f7f1d 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/QmitkMxNMultiWidgetEditor.cpp @@ -1,186 +1,183 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMxNMultiWidgetEditor.h" #include #include #include #include #include // mxn multi widget editor plugin #include "QmitkMultiWidgetDecorationManager.h" // mitk qt widgets module #include #include #include // qt #include const QString QmitkMxNMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.mxnmultiwidget"; struct QmitkMxNMultiWidgetEditor::Impl final { Impl(); ~Impl() = default; QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; QmitkMultiWidgetConfigurationToolBar* m_ConfigurationToolBar; }; QmitkMxNMultiWidgetEditor::Impl::Impl() : m_InteractionSchemeToolBar(nullptr) , m_ConfigurationToolBar(nullptr) { // nothing here } ////////////////////////////////////////////////////////////////////////// // QmitkMxNMultiWidgetEditor ////////////////////////////////////////////////////////////////////////// QmitkMxNMultiWidgetEditor::QmitkMxNMultiWidgetEditor() : QmitkAbstractMultiWidgetEditor() , m_Impl(std::make_unique()) { // nothing here } QmitkMxNMultiWidgetEditor::~QmitkMxNMultiWidgetEditor() { GetSite()->GetPage()->RemovePartListener(this); } void QmitkMxNMultiWidgetEditor::OnLayoutSet(int row, int column) { const auto &multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->SetCrosshairVisibility(true); QmitkAbstractMultiWidgetEditor::OnLayoutSet(row, column); } } void QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { const auto &multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } if (mitk::InteractionSchemeSwitcher::PACSStandard == scheme) { m_Impl->m_InteractionSchemeToolBar->setVisible(true); } else { m_Impl->m_InteractionSchemeToolBar->setVisible(false); } QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(scheme); } ////////////////////////////////////////////////////////////////////////// // PRIVATE ////////////////////////////////////////////////////////////////////////// void QmitkMxNMultiWidgetEditor::SetFocus() { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->setFocus(); } } void QmitkMxNMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { QHBoxLayout *layout = new QHBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); berry::IBerryPreferences *preferences = dynamic_cast(GetPreferences().GetPointer()); auto multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { - auto renderingMode = static_cast( - preferences->GetInt("Rendering Mode", static_cast(mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing))); - - multiWidget = new QmitkMxNMultiWidget(parent, 0, nullptr, renderingMode); + multiWidget = new QmitkMxNMultiWidget(parent, 0, nullptr); // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves in PACS mode if (nullptr == m_Impl->m_InteractionSchemeToolBar) { m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); layout->addWidget(m_Impl->m_InteractionSchemeToolBar); } m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(multiWidget->GetInteractionEventHandler()); // show / hide PACS mouse mode interaction scheme toolbar bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); m_Impl->m_InteractionSchemeToolBar->setVisible(PACSInteractionScheme); multiWidget->SetDataStorage(GetDataStorage()); multiWidget->InitializeMultiWidget(); SetMultiWidget(multiWidget); } layout->addWidget(multiWidget); // create right toolbar: configuration toolbar to change the render window widget layout if (nullptr == m_Impl->m_ConfigurationToolBar) { m_Impl->m_ConfigurationToolBar = new QmitkMultiWidgetConfigurationToolBar(multiWidget); layout->addWidget(m_Impl->m_ConfigurationToolBar); } connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::LayoutSet, this, &QmitkMxNMultiWidgetEditor::OnLayoutSet); connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::Synchronized, this, &QmitkMxNMultiWidgetEditor::OnSynchronize); connect(m_Impl->m_ConfigurationToolBar, &QmitkMultiWidgetConfigurationToolBar::InteractionSchemeChanged, this, &QmitkMxNMultiWidgetEditor::OnInteractionSchemeChanged); GetSite()->GetPage()->AddPartListener(this); OnPreferencesChanged(preferences); } void QmitkMxNMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } // update decoration preferences //m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); OnInteractionSchemeChanged(PACSInteractionScheme ? mitk::InteractionSchemeSwitcher::PACSStandard : mitk::InteractionSchemeSwitcher::MITKStandard); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp index 3d52dd803c..7df622d277 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.cpp @@ -1,128 +1,105 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkMxNMultiWidgetEditorPreferencePage.h" #include // berry framework #include #include QmitkMxNMultiWidgetEditorPreferencePage::QmitkMxNMultiWidgetEditorPreferencePage() : m_Preferences(nullptr) { // nothing here } QmitkMxNMultiWidgetEditorPreferencePage::~QmitkMxNMultiWidgetEditorPreferencePage() { //nothing here } void QmitkMxNMultiWidgetEditorPreferencePage::Init(berry::IWorkbench::Pointer) { // nothing here } void QmitkMxNMultiWidgetEditorPreferencePage::CreateQtControl(QWidget* parent) { m_MainControl = new QWidget(parent); m_Ui.setupUi(m_MainControl); berry::IPreferencesService* preferenceService = berry::Platform::GetPreferencesService(); Q_ASSERT(preferenceService); m_Preferences = preferenceService->GetSystemPreferences()->Node(QmitkMxNMultiWidgetEditor::EDITOR_ID); - connect(m_Ui.m_RenderingModeComboBox, SIGNAL(activated(int)), SLOT(ChangeRenderingMode(int))); connect(m_Ui.m_ColormapComboBox, SIGNAL(activated(int)), SLOT(ChangeColormap(int))); connect(m_Ui.m_ResetButton, SIGNAL(clicked()), SLOT(ResetPreferencesAndGUI())); Update(); } QWidget* QmitkMxNMultiWidgetEditorPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkMxNMultiWidgetEditorPreferencePage::PerformOk() { m_Preferences->PutBool("Use constrained zooming and panning", m_Ui.m_EnableFlexibleZooming->isChecked()); m_Preferences->PutBool("Show level/window widget", m_Ui.m_ShowLevelWindowWidget->isChecked()); m_Preferences->PutBool("PACS like mouse interaction", m_Ui.m_PACSLikeMouseMode->isChecked()); - - m_Preferences->PutInt("Rendering Mode", m_Ui.m_RenderingModeComboBox->currentIndex()); - m_Preferences->PutInt("Render window widget colormap", m_Ui.m_ColormapComboBox->currentIndex()); m_Preferences->PutBool("Render window individual decorations", m_Ui.m_IndividualDecorations->isChecked()); m_Preferences->PutInt("crosshair gap size", m_Ui.m_CrosshairGapSize->value()); return true; } void QmitkMxNMultiWidgetEditorPreferencePage::PerformCancel() { // nothing here } void QmitkMxNMultiWidgetEditorPreferencePage::Update() { m_Ui.m_EnableFlexibleZooming->setChecked(m_Preferences->GetBool("Use constrained zooming and panning", true)); m_Ui.m_ShowLevelWindowWidget->setChecked(m_Preferences->GetBool("Show level/window widget", true)); m_Ui.m_PACSLikeMouseMode->setChecked(m_Preferences->GetBool("PACS like mouse interaction", false)); - int renderingMode = m_Preferences->GetInt("Rendering Mode", 0); - m_Ui.m_RenderingModeComboBox->setCurrentIndex(renderingMode); - int colormap = m_Preferences->GetInt("Render window widget colormap", 0); m_Ui.m_ColormapComboBox->setCurrentIndex(colormap); m_Ui.m_IndividualDecorations->setChecked(m_Preferences->GetBool("Render window individual decorations", false)); m_Ui.m_CrosshairGapSize->setValue(m_Preferences->GetInt("crosshair gap size", 32)); } void QmitkMxNMultiWidgetEditorPreferencePage::ResetPreferencesAndGUI() { m_Preferences->Clear(); Update(); } -void QmitkMxNMultiWidgetEditorPreferencePage::ChangeRenderingMode(int i) -{ - if (0 == i) - { - m_CurrentRenderingMode = "Standard"; - } - else if (1 == i) - { - m_CurrentRenderingMode = "Multisampling"; - } - else if (2 == i) - { - m_CurrentRenderingMode = "DepthPeeling"; - } -} - void QmitkMxNMultiWidgetEditorPreferencePage::ChangeColormap(int i) { if (0 == i) { m_CurrentColormap = "Black and white"; } -} \ No newline at end of file +} diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h index 8eb7d973c2..04e1575ac0 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.h @@ -1,80 +1,69 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H #define QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H #include "ui_QmitkMxNMultiWidgetEditorPreferencePage.h" #include #include #include #include #include class QmitkMxNMultiWidgetEditorPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkMxNMultiWidgetEditorPreferencePage(); ~QmitkMxNMultiWidgetEditorPreferencePage() override; void Init(berry::IWorkbench::Pointer) override; void CreateQtControl(QWidget* parent) override; QWidget* GetQtControl() const override; bool PerformOk() override; void PerformCancel() override; void Update() override; public slots: /** * @brief ResetColors set default colors and refresh the GUI. */ void ResetPreferencesAndGUI(); - /** - * @brief ChangeRenderingMode slot to chose the rendering mode via QComboBox. - * @param i index of the box. - */ - void ChangeRenderingMode(int i); - void ChangeColormap(int i); protected: - /** - * @brief m_CurrentRenderingMode String for the rendering mode. - */ - std::string m_CurrentRenderingMode; - std::string m_CurrentColormap; /** * @brief m_Preferences the berry preferences. */ berry::IPreferences::Pointer m_Preferences; private: Ui::QmitkMxNMultiWidgetEditorPreferencePage m_Ui; QWidget* m_MainControl; }; #endif // QMITKMXNMULTIWIDGETEDITORPREFERENCEPAGE_H diff --git a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui index 0bf3df7077..8a7b812846 100644 --- a/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui +++ b/Plugins/org.mitk.gui.qt.mxnmultiwidgeteditor/src/internal/QmitkMxNMultiWidgetEditorPreferencePage.ui @@ -1,163 +1,133 @@ QmitkMxNMultiWidgetEditorPreferencePage 0 0 520 - 320 + 354 External Programs <html><head/><body><p>If activated, zooming and panning is limited to a certain space around each image.</p></body></html> Qt::LeftToRight Use constraint zooming and panning true - - - - Qt::LeftToRight - - - Show level/window widget - - - true - - - - - - - Qt::LeftToRight - - - Use PACS like mouse interaction (select left mouse button action) - - - - + Qt::Horizontal - - - - Rendering Mode* + + + + <html><head/><body><p>The gap in the middle of the crosshair in pixels.</p></body></html> - - - - - - - Standard Rendering - - - - - Enable Multisampling (Antialiasing) - - - - - Enable Depth Peeling - - - - - - - * Changes require restart of MITK. - Depth Peeling is only supported by Windows. - For other OS, use Standard Rendering and enable - the property 'Depth Sorting' in the property list of the surface data node. - - - - - - - Qt::Horizontal + Crosshair gap size - + Colormap - - - - - Black and white - - + + + + Reset preferences + - + 0 0 Allow render window individual decorations - - - - <html><head/><body><p>The gap in the middle of the crosshair in pixels.</p></body></html> - - - Crosshair gap size - - - - + 32 - - + + + + Qt::LeftToRight + - Reset preferences + Show level/window widget + + + true + + + + + + + Qt::LeftToRight + + + Use PACS like mouse interaction (select left mouse button action) + + + + + Black and white + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp index 1fb88d109c..66d3120fe5 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/QmitkStdMultiWidgetEditor.cpp @@ -1,412 +1,409 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkStdMultiWidgetEditor.h" #include #include #include #include #include #include #include #include #include // mitk qt widgets module #include #include #include #include // mitk gui qt common plugin #include const QString QmitkStdMultiWidgetEditor::EDITOR_ID = "org.mitk.editors.stdmultiwidget"; struct QmitkStdMultiWidgetEditor::Impl final { Impl(); ~Impl() = default; QmitkInteractionSchemeToolBar* m_InteractionSchemeToolBar; QmitkLevelWindowWidget* m_LevelWindowWidget; std::unique_ptr m_MultiWidgetDecorationManager; }; QmitkStdMultiWidgetEditor::Impl::Impl() : m_InteractionSchemeToolBar(nullptr) , m_LevelWindowWidget(nullptr) { // nothing here } ////////////////////////////////////////////////////////////////////////// // QmitkStdMultiWidgetEditor ////////////////////////////////////////////////////////////////////////// QmitkStdMultiWidgetEditor::QmitkStdMultiWidgetEditor() : QmitkAbstractMultiWidgetEditor() , m_Impl(std::make_unique()) { // nothing here } QmitkStdMultiWidgetEditor::~QmitkStdMultiWidgetEditor() { GetSite()->GetPage()->RemovePartListener(this); } berry::IPartListener::Events::Types QmitkStdMultiWidgetEditor::GetPartEventTypes() const { return Events::CLOSED | Events::OPENED | Events::HIDDEN | Events::VISIBLE; } void QmitkStdMultiWidgetEditor::PartClosed(const berry::IWorkbenchPartReference::Pointer& partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->RemovePlanesFromDataStorage(); multiWidget->ActivateMenuWidget(false); } } } void QmitkStdMultiWidgetEditor::PartOpened(const berry::IWorkbenchPartReference::Pointer& partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->AddPlanesToDataStorage(); multiWidget->ActivateMenuWidget(true); } } } void QmitkStdMultiWidgetEditor::PartHidden(const berry::IWorkbenchPartReference::Pointer& partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->ActivateMenuWidget(false); } } } void QmitkStdMultiWidgetEditor::PartVisible(const berry::IWorkbenchPartReference::Pointer& partRef) { if (partRef->GetId() == QmitkStdMultiWidgetEditor::EDITOR_ID) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr != multiWidget) { multiWidget->ActivateMenuWidget(true); } } } QmitkLevelWindowWidget* QmitkStdMultiWidgetEditor::GetLevelWindowWidget() const { return m_Impl->m_LevelWindowWidget; } void QmitkStdMultiWidgetEditor::EnableSlicingPlanes(bool enable) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr == multiWidget) { return; } multiWidget->SetWidgetPlanesVisibility(enable); } bool QmitkStdMultiWidgetEditor::IsSlicingPlanesEnabled() const { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr == multiWidget) { return false; } mitk::DataNode::Pointer node = multiWidget->GetWidgetPlane1(); if (node.IsNotNull()) { bool visible = false; node->GetVisibility(visible, nullptr); return visible; } else { return false; } } void QmitkStdMultiWidgetEditor::OnInteractionSchemeChanged(mitk::InteractionSchemeSwitcher::InteractionScheme scheme) { const auto& multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } if (mitk::InteractionSchemeSwitcher::PACSStandard == scheme) { m_Impl->m_InteractionSchemeToolBar->setVisible(true); } else { m_Impl->m_InteractionSchemeToolBar->setVisible(false); } QmitkAbstractMultiWidgetEditor::OnInteractionSchemeChanged(scheme); } void QmitkStdMultiWidgetEditor::ShowLevelWindowWidget(bool show) { if (show) { m_Impl->m_LevelWindowWidget->disconnect(this); m_Impl->m_LevelWindowWidget->SetDataStorage(GetDataStorage()); m_Impl->m_LevelWindowWidget->show(); } else { m_Impl->m_LevelWindowWidget->disconnect(this); m_Impl->m_LevelWindowWidget->hide(); } } void QmitkStdMultiWidgetEditor::SetFocus() { const auto& multiWidget = GetMultiWidget(); if (nullptr != multiWidget) { multiWidget->setFocus(); } } void QmitkStdMultiWidgetEditor::CreateQtPartControl(QWidget* parent) { QHBoxLayout* layout = new QHBoxLayout(parent); layout->setContentsMargins(0, 0, 0, 0); berry::IBerryPreferences* preferences = dynamic_cast(GetPreferences().GetPointer()); auto multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { - auto renderingMode = static_cast( - prefs->GetInt("Rendering Mode", static_cast(mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing))); - - multiWidget = new QmitkStdMultiWidget(parent, 0, nullptr, renderingMode); + multiWidget = new QmitkStdMultiWidget(parent, 0, nullptr); // create left toolbar: interaction scheme toolbar to switch how the render window navigation behaves (in PACS mode) if (nullptr == m_Impl->m_InteractionSchemeToolBar) { m_Impl->m_InteractionSchemeToolBar = new QmitkInteractionSchemeToolBar(parent); layout->addWidget(m_Impl->m_InteractionSchemeToolBar); } m_Impl->m_InteractionSchemeToolBar->SetInteractionEventHandler(multiWidget->GetInteractionEventHandler()); multiWidget->SetDataStorage(GetDataStorage()); multiWidget->InitializeMultiWidget(); SetMultiWidget(multiWidget); } layout->addWidget(multiWidget); // create level window slider on the right side if (nullptr == m_Impl->m_LevelWindowWidget) { m_Impl->m_LevelWindowWidget = new QmitkLevelWindowWidget(parent); m_Impl->m_LevelWindowWidget->setObjectName(QString::fromUtf8("levelWindowWidget")); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); sizePolicy.setHorizontalStretch(0); sizePolicy.setVerticalStretch(0); sizePolicy.setHeightForWidth(m_Impl->m_LevelWindowWidget->sizePolicy().hasHeightForWidth()); m_Impl->m_LevelWindowWidget->setSizePolicy(sizePolicy); m_Impl->m_LevelWindowWidget->setMaximumWidth(50); } layout->addWidget(m_Impl->m_LevelWindowWidget); m_Impl->m_MultiWidgetDecorationManager = std::make_unique(multiWidget); GetSite()->GetPage()->AddPartListener(this); InitializePreferences(preferences); OnPreferencesChanged(preferences); } void QmitkStdMultiWidgetEditor::OnPreferencesChanged(const berry::IBerryPreferences* preferences) { const auto& multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr == multiWidget) { return; } // change and apply decoration preferences GetPreferenceDecorations(preferences); m_Impl->m_MultiWidgetDecorationManager->DecorationPreferencesChanged(preferences); QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); int i = 0; for (const auto& renderWindowWidget : renderWindowWidgets) { auto decorationColor = renderWindowWidget.second->GetDecorationColor(); multiWidget->SetDecorationColor(i, decorationColor); ++i; } int crosshairgapsize = preferences->GetInt("crosshair gap size", 32); multiWidget->GetWidgetPlane1()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); multiWidget->GetWidgetPlane2()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); multiWidget->GetWidgetPlane3()->SetIntProperty("Crosshair.Gap Size", crosshairgapsize); // zooming and panning preferences bool constrainedZooming = preferences->GetBool("Use constrained zooming and panning", true); mitk::RenderingManager::GetInstance()->SetConstrainedPanningZooming(constrainedZooming); // mouse modes switcher toolbar bool PACSInteractionScheme = preferences->GetBool("PACS like mouse interaction", false); OnInteractionSchemeChanged(PACSInteractionScheme ? mitk::InteractionSchemeSwitcher::PACSStandard : mitk::InteractionSchemeSwitcher::MITKStandard); // level window setting bool showLevelWindowWidget = preferences->GetBool("Show level/window widget", true); ShowLevelWindowWidget(showLevelWindowWidget); mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(GetDataStorage()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkStdMultiWidgetEditor::InitializePreferences(berry::IBerryPreferences * preferences) { auto multiWidget = GetMultiWidget(); if (nullptr == multiWidget) { return; } GetPreferenceDecorations(preferences); //overwrite if preferences are defined QmitkAbstractMultiWidget::RenderWindowWidgetMap renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); int i = 0; for (const auto& renderWindowWidget : renderWindowWidgets) { QString widgetName = "widget" + QString::number(i + 1); auto gradientBackgroundColors = renderWindowWidget.second->GetGradientBackgroundColors(); preferences->Put(widgetName + " first background color", MitkColorToHex(gradientBackgroundColors.first)); preferences->Put(widgetName + " second background color", MitkColorToHex(gradientBackgroundColors.second)); auto decorationColor = renderWindowWidget.second->GetDecorationColor(); preferences->Put(widgetName + " decoration color", MitkColorToHex(decorationColor)); auto cornerAnnotation = renderWindowWidget.second->GetCornerAnnotationText(); preferences->Put(widgetName + " corner annotation", QString::fromStdString(cornerAnnotation)); ++i; } } void QmitkStdMultiWidgetEditor::GetPreferenceDecorations(const berry::IBerryPreferences * preferences) { auto multiWidget = dynamic_cast(GetMultiWidget()); if (nullptr == multiWidget) { return; } auto hexBlack = "#000000"; auto gradientBlack = "#191919"; auto gradientGray = "#7F7F7F"; auto renderWindowWidgets = multiWidget->GetRenderWindowWidgets(); int i = 0; for (const auto& renderWindowWidget : renderWindowWidgets) { QString widgetName = renderWindowWidget.second->GetWidgetName(); if (mitk::BaseRenderer::Standard3D == mitk::BaseRenderer::GetInstance(renderWindowWidget.second->GetRenderWindow()->GetVtkRenderWindow())->GetMapperID()) { auto upper = preferences->Get(widgetName + " first background color", gradientBlack); auto lower = preferences->Get(widgetName + " second background color", gradientGray); renderWindowWidget.second->SetGradientBackgroundColors(HexColorToMitkColor(upper), HexColorToMitkColor(lower)); } else { auto upper = preferences->Get(widgetName + " first background color", hexBlack); auto lower = preferences->Get(widgetName + " second background color", hexBlack); renderWindowWidget.second->SetGradientBackgroundColors(HexColorToMitkColor(upper), HexColorToMitkColor(lower)); } auto defaultDecorationColor = multiWidget->GetDecorationColor(i); auto decorationColor = preferences->Get(widgetName + " decoration color", MitkColorToHex(defaultDecorationColor)); renderWindowWidget.second->SetDecorationColor(HexColorToMitkColor(decorationColor)); auto defaultCornerAnnotation = renderWindowWidget.second->GetCornerAnnotationText(); auto cornerAnnotation = preferences->Get(widgetName + " corner annotation", QString::fromStdString(defaultCornerAnnotation)); renderWindowWidget.second->SetCornerAnnotationText(cornerAnnotation.toStdString()); ++i; } } mitk::Color QmitkStdMultiWidgetEditor::HexColorToMitkColor(const QString& hexColor) { QColor qColor(hexColor); mitk::Color returnColor; float colorMax = 255.0f; if (hexColor.isEmpty()) // default value { returnColor[0] = 1.0; returnColor[1] = 1.0; returnColor[2] = 1.0; MITK_ERROR << "Using default color for unknown hex color " << qPrintable(hexColor); } else { returnColor[0] = qColor.red() / colorMax; returnColor[1] = qColor.green() / colorMax; returnColor[2] = qColor.blue() / colorMax; } return returnColor; } QString QmitkStdMultiWidgetEditor::MitkColorToHex(const mitk::Color& color) { QColor returnColor; float colorMax = 255.0f; returnColor.setRed(static_cast(color[0] * colorMax + 0.5)); returnColor.setGreen(static_cast(color[1] * colorMax + 0.5)); returnColor.setBlue(static_cast(color[2] * colorMax + 0.5)); return returnColor.name(); } diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp index 203887ca51..af90a3b051 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.cpp @@ -1,294 +1,249 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkStdMultiWidgetEditorPreferencePage.h" #include #include -#include - #include #include -#include -#include - #include - -namespace -{ - void ChangeRenderingMode(mitk::BaseRenderer::RenderingMode renderingMode) - { - auto renderingManager = mitk::RenderingManager::GetInstance(); - - if (nullptr == renderingManager) - return; - - auto renderWindows = renderingManager->GetAllRegisteredRenderWindows(); - - for (auto renderWindow : renderWindows) - { - auto renderers = renderWindow->GetRenderers(); - - if (nullptr != renderers) - { - renderers->InitTraversal(); - auto renderer = renderers->GetNextItem(); - - while (nullptr != renderer) - { - renderer->SetUseFXAA(mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing == renderingMode); - renderer = renderers->GetNextItem(); - } - - renderingManager->RequestUpdate(renderWindow); - } - } - } -} - QmitkStdMultiWidgetEditorPreferencePage::QmitkStdMultiWidgetEditorPreferencePage() : m_Preferences(nullptr), m_Ui(new Ui::QmitkStdMultiWidgetEditorPreferencePage), m_Control(nullptr) { } QmitkStdMultiWidgetEditorPreferencePage::~QmitkStdMultiWidgetEditorPreferencePage() { } void QmitkStdMultiWidgetEditorPreferencePage::CreateQtControl(QWidget* parent) { m_Control = new QWidget(parent); m_Ui->setupUi(m_Control); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); Q_ASSERT(prefService); m_Preferences = prefService->GetSystemPreferences()->Node(QmitkStdMultiWidgetEditor::EDITOR_ID); QObject::connect( m_Ui->m_ColorButton1, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_ColorButton2, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_ResetButton, SIGNAL( clicked() ) , this, SLOT( ResetPreferencesAndGUI() ) ); QObject::connect( m_Ui->m_RenderWindowDecorationColor, SIGNAL( clicked() ) , this, SLOT( ColorChooserButtonClicked() ) ); QObject::connect( m_Ui->m_RenderWindowChooser, SIGNAL(activated(int) ) , this, SLOT( OnWidgetComboBoxChanged(int) ) ); QObject::connect( m_Ui->m_RenderWindowDecorationText, SIGNAL(textChanged(QString) ) , this, SLOT( AnnotationTextChanged(QString) ) ); this->Update(); } QWidget* QmitkStdMultiWidgetEditorPreferencePage::GetQtControl() const { return m_Control; } void QmitkStdMultiWidgetEditorPreferencePage::Init(berry::IWorkbench::Pointer) { } void QmitkStdMultiWidgetEditorPreferencePage::PerformCancel() { } bool QmitkStdMultiWidgetEditorPreferencePage::PerformOk() { m_Preferences->Put("stdmulti.widget0 corner annotation", m_WidgetAnnotation[0]); m_Preferences->Put("stdmulti.widget1 corner annotation", m_WidgetAnnotation[1]); m_Preferences->Put("stdmulti.widget2 corner annotation", m_WidgetAnnotation[2]); m_Preferences->Put("stdmulti.widget3 corner annotation", m_WidgetAnnotation[3]); m_Preferences->Put("stdmulti.widget0 decoration color", m_WidgetDecorationColor[0]); m_Preferences->Put("stdmulti.widget1 decoration color", m_WidgetDecorationColor[1]); m_Preferences->Put("stdmulti.widget2 decoration color", m_WidgetDecorationColor[2]); m_Preferences->Put("stdmulti.widget3 decoration color", m_WidgetDecorationColor[3]); m_Preferences->Put("stdmulti.widget0 first background color", m_WidgetBackgroundColor1[0]); m_Preferences->Put("stdmulti.widget1 first background color", m_WidgetBackgroundColor1[1]); m_Preferences->Put("stdmulti.widget2 first background color", m_WidgetBackgroundColor1[2]); m_Preferences->Put("stdmulti.widget3 first background color", m_WidgetBackgroundColor1[3]); m_Preferences->Put("stdmulti.widget0 second background color", m_WidgetBackgroundColor2[0]); m_Preferences->Put("stdmulti.widget1 second background color", m_WidgetBackgroundColor2[1]); m_Preferences->Put("stdmulti.widget2 second background color", m_WidgetBackgroundColor2[2]); m_Preferences->Put("stdmulti.widget3 second background color", m_WidgetBackgroundColor2[3]); m_Preferences->PutInt("crosshair gap size", m_Ui->m_CrosshairGapSize->value()); m_Preferences->PutBool("Use constrained zooming and panning" , m_Ui->m_EnableFlexibleZooming->isChecked()); m_Preferences->PutBool("Show level/window widget", m_Ui->m_ShowLevelWindowWidget->isChecked()); m_Preferences->PutBool("PACS like mouse interaction", m_Ui->m_PACSLikeMouseMode->isChecked()); - auto renderingMode = static_cast(m_Ui->m_RenderingMode->currentIndex()); - m_Preferences->PutInt("Rendering Mode", static_cast(renderingMode)); - ChangeRenderingMode(renderingMode); // Change the rendering mode now, no restart required - return true; } void QmitkStdMultiWidgetEditorPreferencePage::Update() { //Note: there should be default preferences already defined in the //QmitkStdMultiWidgetEditor::InitializePreferences(). Therefore, //all default values here are not relevant. //gradient background colors m_WidgetBackgroundColor1[0] = m_Preferences->Get("stdmulti.widget0 first background color", "#1d1d1c"); m_WidgetBackgroundColor2[0] = m_Preferences->Get("stdmulti.widget0 second background color", "#1d1d1c"); m_WidgetBackgroundColor1[1] = m_Preferences->Get("stdmulti.widget1 first background color", "#1d1d1c"); m_WidgetBackgroundColor2[1] = m_Preferences->Get("stdmulti.widget1 second background color", "#1d1d1c"); m_WidgetBackgroundColor1[2] = m_Preferences->Get("stdmulti.widget2 first background color", "#1d1d1c"); m_WidgetBackgroundColor2[2] = m_Preferences->Get("stdmulti.widget2 second background color", "#1d1d1c"); m_WidgetBackgroundColor1[3] = m_Preferences->Get("stdmulti.widget3 first background color", "#1d1d1c"); m_WidgetBackgroundColor2[3] = m_Preferences->Get("stdmulti.widget3 second background color", "#adb1b6"); //decoration colors m_WidgetDecorationColor[0] = m_Preferences->Get("stdmulti.widget0 decoration color", "#c00000"); m_WidgetDecorationColor[1] = m_Preferences->Get("stdmulti.widget1 decoration color", "#0fad00"); m_WidgetDecorationColor[2] = m_Preferences->Get("stdmulti.widget2 decoration color", "#0080ff"); m_WidgetDecorationColor[3] = m_Preferences->Get("stdmulti.widget3 decoration color", "#fec500"); //annotation text m_WidgetAnnotation[0] = m_Preferences->Get("stdmulti.widget0 corner annotation", "Axial"); m_WidgetAnnotation[1] = m_Preferences->Get("stdmulti.widget1 corner annotation", "Sagittal"); m_WidgetAnnotation[2] = m_Preferences->Get("stdmulti.widget2 corner annotation", "Coronal"); m_WidgetAnnotation[3] = m_Preferences->Get("stdmulti.widget3 corner annotation", "3D"); //Ui stuff int index = m_Ui->m_RenderWindowChooser->currentIndex(); QColor firstBackgroundColor(m_WidgetBackgroundColor1[index]); QColor secondBackgroundColor(m_WidgetBackgroundColor2[index]); QColor widgetColor(m_WidgetDecorationColor[index]); this->SetStyleSheetToColorChooserButton(firstBackgroundColor, m_Ui->m_ColorButton1); this->SetStyleSheetToColorChooserButton(secondBackgroundColor, m_Ui->m_ColorButton2); this->SetStyleSheetToColorChooserButton(widgetColor, m_Ui->m_RenderWindowDecorationColor); m_Ui->m_RenderWindowDecorationText->setText(m_WidgetAnnotation[index]); m_Ui->m_EnableFlexibleZooming->setChecked(m_Preferences->GetBool("Use constrained zooming and panning", true)); m_Ui->m_ShowLevelWindowWidget->setChecked(m_Preferences->GetBool("Show level/window widget", true)); m_Ui->m_PACSLikeMouseMode->setChecked(m_Preferences->GetBool("PACS like mouse interaction", false)); m_Ui->m_CrosshairGapSize->setValue(m_Preferences->GetInt("crosshair gap size", 32)); - - auto renderingMode = m_Preferences->GetInt("Rendering Mode", static_cast(mitk::BaseRenderer::RenderingMode::FastApproximateAntiAliasing)); - m_Ui->m_RenderingMode->setCurrentIndex(renderingMode); } void QmitkStdMultiWidgetEditorPreferencePage::ColorChooserButtonClicked() { unsigned int widgetIndex = m_Ui->m_RenderWindowChooser->currentIndex(); if(widgetIndex > 3) { MITK_ERROR << "Selected index for unknown."; return; } QObject *senderObj = sender(); // This will give Sender button //find out last used color and set it QColor initialColor; if( senderObj->objectName() == m_Ui->m_ColorButton1->objectName()) { initialColor = QColor(m_WidgetBackgroundColor1[widgetIndex]); }else if( senderObj->objectName() == m_Ui->m_ColorButton2->objectName()) { initialColor = QColor(m_WidgetBackgroundColor2[widgetIndex]); }else if( senderObj->objectName() == m_Ui->m_RenderWindowDecorationColor->objectName()) { initialColor = QColor(m_WidgetDecorationColor[widgetIndex]); } //get the new color QColor newcolor = QColorDialog::getColor(initialColor); if(!newcolor.isValid()) { newcolor = initialColor; } this->SetStyleSheetToColorChooserButton(newcolor, static_cast(senderObj)); //convert it to std string and apply it if( senderObj->objectName() == m_Ui->m_ColorButton1->objectName()) { m_WidgetBackgroundColor1[widgetIndex] = newcolor.name(); } else if( senderObj->objectName() == m_Ui->m_ColorButton2->objectName()) { m_WidgetBackgroundColor2[widgetIndex] = newcolor.name(); } else if( senderObj->objectName() == m_Ui->m_RenderWindowDecorationColor->objectName()) { m_WidgetDecorationColor[widgetIndex] = newcolor.name(); } } void QmitkStdMultiWidgetEditorPreferencePage::SetStyleSheetToColorChooserButton(QColor backgroundcolor, QPushButton* button) { button->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(backgroundcolor.red())); styleSheet.append(","); styleSheet.append(QString::number(backgroundcolor.green())); styleSheet.append(","); styleSheet.append(QString::number(backgroundcolor.blue())); styleSheet.append(")"); button->setStyleSheet(styleSheet); } void QmitkStdMultiWidgetEditorPreferencePage::AnnotationTextChanged(QString text) { unsigned int widgetIndex = m_Ui->m_RenderWindowChooser->currentIndex(); if( widgetIndex > 3) { MITK_INFO << "Selected index for unknown widget."; return; } m_WidgetAnnotation[widgetIndex] = text; } void QmitkStdMultiWidgetEditorPreferencePage::ResetPreferencesAndGUI() { m_Preferences->Clear(); this->Update(); } void QmitkStdMultiWidgetEditorPreferencePage::OnWidgetComboBoxChanged(int i) { if( i > 3) { MITK_ERROR << "Selected unknown widget."; return; } QColor widgetColor(m_WidgetDecorationColor[i]); QColor gradientBackground1(m_WidgetBackgroundColor1[i]); QColor gradientBackground2(m_WidgetBackgroundColor2[i]); this->SetStyleSheetToColorChooserButton(widgetColor, m_Ui->m_RenderWindowDecorationColor); this->SetStyleSheetToColorChooserButton(gradientBackground1, m_Ui->m_ColorButton1); this->SetStyleSheetToColorChooserButton(gradientBackground2, m_Ui->m_ColorButton2); m_Ui->m_RenderWindowDecorationText->setText(m_WidgetAnnotation[i]); } diff --git a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.ui b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.ui index 8f9ed01e88..9093f8e611 100644 --- a/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.ui +++ b/Plugins/org.mitk.gui.qt.stdmultiwidgeteditor/src/internal/QmitkStdMultiWidgetEditorPreferencePage.ui @@ -1,223 +1,195 @@ QmitkStdMultiWidgetEditorPreferencePage 0 0 518 - 730 + 330 External Programs - + The small text on the button left of each renderwindow. Corner annotation - - - - <html><head/><body><p>If two colors are set, a gradient background is generated.</p></body></html> - - - Background color - - - - - - - - - - - - - - - stdmulti.widget1 - - - - - stdmulti.widget2 - - - - - stdmulti.widget3 - - - - - stdmulti.widget4 - - - - - - - - <html><head/><body><p>The color is used for the following decorations (of each renderwindow):</p><p>Rectangle border</p><p>Corner annotation</p><p>Crosshair</p><p>Plane geometry helper objects (3D Planes)</p><p>Image navigator borders</p><p><br/></p></body></html> - - - Decoration color - - - - - - - 32 - - - - - - - Qt::Horizontal - - - - - - - Qt::Horizontal - - - Qt::LeftToRight Use PACS like mouse interaction (select left mouse button action) false - - - - Reset preferences - - - <html><head/><body><p>If activated, zooming and panning is limited to a certain space arround each image.</p></body></html> Qt::LeftToRight Use constraint zooming and panning true - - + + - <html><head/><body><p>Choose the renderwindow from the multi widget.</p></body></html> + <html><head/><body><p>If two colors are set, a gradient background is generated.</p></body></html> - Render windows - - - - - - - + Background color - - - - - - - - No anti-aliasing - - - - - Fast Approximate Anti-Aliasing (FXAA) - - - - - + <html><head/><body><p>The gap in the middle of the crosshair in pixels.</p></body></html> Crosshair gap size + + + + + + + + + + + Qt::Horizontal + + + - + - - + + + + 32 + + + + + + + <html><head/><body><p>The color is used for the following decorations (of each renderwindow):</p><p>Rectangle border</p><p>Corner annotation</p><p>Crosshair</p><p>Plane geometry helper objects (3D Planes)</p><p>Image navigator borders</p><p><br/></p></body></html> + - Rendering mode + Decoration color + + + + + + + Reset preferences Qt::LeftToRight Show level/window widget true - + + + + <html><head/><body><p>Choose the renderwindow from the multi widget.</p></body></html> + + + Render windows + + + + + + + + + + + + + + Qt::Vertical 20 40 + + + + + stdmulti.widget1 + + + + + stdmulti.widget2 + + + + + stdmulti.widget3 + + + + + stdmulti.widget4 + + + +