diff --git a/Modules/Annotation/src/mitkLogoAnnotation.cpp b/Modules/Annotation/src/mitkLogoAnnotation.cpp index be68ef00db..59f2617ef0 100644 --- a/Modules/Annotation/src/mitkLogoAnnotation.cpp +++ b/Modules/Annotation/src/mitkLogoAnnotation.cpp @@ -1,279 +1,279 @@ /*=================================================================== 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 "mitkLogoAnnotation.h" #include "mitkEqual.h" #include "vtkUnicodeString.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class vtkWindowModifiedCallback : public vtkCommand { public: static vtkWindowModifiedCallback *New() { return new vtkWindowModifiedCallback; } mitk::LogoAnnotation::LocalStorage* ls; double relativeSize = 0.; - virtual void Execute(vtkObject *caller, unsigned long, void* calldata) + virtual void Execute(vtkObject *caller, unsigned long, void* /*calldata*/) { vtkRenderWindow* window = static_cast(caller); int dims[3]; ls->m_LogoImage->GetDimensions(dims); int *size = window->GetSize(); double currentFactor = double(dims[0]) / double(size[0]); double desiredFactor = relativeSize; double scaleFactor = desiredFactor / currentFactor; double magnificationFactor[3]; ls->m_ImageResize->GetMagnificationFactors(magnificationFactor); if (!mitk::Equal(scaleFactor, magnificationFactor[0])){ ls->m_ImageResize->SetMagnificationFactors(scaleFactor, scaleFactor, scaleFactor); ls->m_ImageResize->Update(); } /*ls->m_ImageActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); ls->m_ImageActor->GetPosition2Coordinate()->SetCoordinateSystemToNormalizedViewport(); ls->m_ImageActor->SetPosition(0.75, 0.05);*/ } vtkWindowModifiedCallback() { this->ls = 0; } }; mitk::LogoAnnotation::LogoAnnotation() { m_readerFactory = vtkSmartPointer::New(); mitk::Point2D offset; offset.Fill(0.03); SetOffsetVector(offset); SetRelativeSize(0.2); SetLogoImagePath("mbiLogo"); SetCornerPosition(3); m_VtkImageImport = vtkSmartPointer::New(); } mitk::LogoAnnotation::~LogoAnnotation() { for (BaseRenderer *renderer : m_LSH.GetRegisteredBaseRenderer()) { if (renderer) { this->RemoveFromBaseRenderer(renderer); } } } mitk::LogoAnnotation::LocalStorage::~LocalStorage() { } mitk::LogoAnnotation::LocalStorage::LocalStorage() { m_ImageActor = vtkSmartPointer::New(); m_ImageMapper = vtkSmartPointer::New(); m_ImageActor->SetMapper(m_ImageMapper); m_ImageResize = vtkSmartPointer::New(); } void mitk::LogoAnnotation::UpdateVtkAnnotation(mitk::BaseRenderer *renderer) { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); if (ls->IsGenerateDataRequired(renderer, this)) { if (GetLogoImagePath().empty()) { ls->m_ImageActor->SetVisibility(0); return; } vtkImageReader2 *imageReader = m_readerFactory->CreateImageReader2(GetLogoImagePath().c_str()); if (imageReader) { imageReader->SetFileName(GetLogoImagePath().c_str()); imageReader->Update(); ls->m_LogoImage = imageReader->GetOutput(); imageReader->Delete(); } else { ls->m_LogoImage = CreateMbiLogo(); } ls->m_ImageMapper->SetInputConnection(ls->m_ImageResize->GetOutputPort()); ls->m_ImageMapper->SetColorWindow(255); ls->m_ImageMapper->SetColorLevel(127.5); ls->m_ImageResize->SetInputData(ls->m_LogoImage); ls->m_ImageResize->SetResizeMethodToMagnificationFactors(); ls->m_ImageResize->SetMagnificationFactors(1., 1., 1.); vtkSmartPointer wCallback = vtkSmartPointer::New(); wCallback->ls = ls; wCallback->relativeSize = GetRelativeSize(); renderer->GetRenderWindow()->AddObserver(vtkCommand::ModifiedEvent, wCallback); float opacity; this->GetOpacity(opacity); ls->m_ImageActor->GetProperty()->SetOpacity(opacity); ls->m_ImageActor->GetPositionCoordinate()->SetCoordinateSystemToDisplay(); ls->m_ImageActor->GetPosition2Coordinate()->SetCoordinateSystemToDisplay(); ls->UpdateGenerateDataTime(); } } vtkImageData *mitk::LogoAnnotation::CreateMbiLogo() { m_VtkImageImport->SetDataScalarTypeToUnsignedChar(); m_VtkImageImport->SetNumberOfScalarComponents(mbiLogo_NumberOfScalars); m_VtkImageImport->SetWholeExtent(0, mbiLogo_Width - 1, 0, mbiLogo_Height - 1, 0, 1 - 1); m_VtkImageImport->SetDataExtentToWholeExtent(); char *ImageData; // flip mbi logo around y axis and change color order ImageData = new char[mbiLogo_Height * mbiLogo_Width * mbiLogo_NumberOfScalars]; unsigned int column, row; char *dest = ImageData; char *source = (char *)&mbiLogo_Data[0]; ; char r, g, b, a; for (column = 0; column < mbiLogo_Height; column++) for (row = 0; row < mbiLogo_Width; row++) { // change r with b b = *source++; g = *source++; r = *source++; a = *source++; *dest++ = r; *dest++ = g; *dest++ = b; *dest++ = a; } m_VtkImageImport->SetImportVoidPointer(ImageData); m_VtkImageImport->Modified(); m_VtkImageImport->Update(); return m_VtkImageImport->GetOutput(); } void mitk::LogoAnnotation::SetLogoImagePath(std::string path) { SetStringProperty("Annotation.LogoImagePath", path.c_str()); Modified(); } std::string mitk::LogoAnnotation::GetLogoImagePath() const { std::string path; GetPropertyList()->GetStringProperty("Annotation.LogoImagePath", path); return path; } mitk::Annotation::Bounds mitk::LogoAnnotation::GetBoundsOnDisplay(mitk::BaseRenderer *renderer) const { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); mitk::Annotation::Bounds bounds; bounds.Position = ls->m_ImageActor->GetPosition(); int size[3]; ls->m_ImageResize->GetOutput()->GetDimensions(size); bounds.Size[0] = size[0]; bounds.Size[1] = size[1]; return bounds; } void mitk::LogoAnnotation::SetBoundsOnDisplay(mitk::BaseRenderer *renderer, const mitk::Annotation::Bounds &bounds) { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); mitk::Point2D posT; posT[0] = bounds.Position[0]; posT[1] = bounds.Position[1]; ls->m_ImageActor->SetDisplayPosition(posT[0], posT[1]); } void mitk::LogoAnnotation::SetOffsetVector(const Point2D &OffsetVector) { mitk::Point2dProperty::Pointer OffsetVectorProperty = mitk::Point2dProperty::New(OffsetVector); SetProperty("Annotation.OffsetVector", OffsetVectorProperty.GetPointer()); Modified(); } mitk::Point2D mitk::LogoAnnotation::GetOffsetVector() const { mitk::Point2D OffsetVector; OffsetVector.Fill(0); GetPropertyValue("Annotation.OffsetVector", OffsetVector); return OffsetVector; } void mitk::LogoAnnotation::SetCornerPosition(const int &corner) { SetIntProperty("Annotation.CornerPosition", corner); Modified(); } int mitk::LogoAnnotation::GetCornerPosition() const { int corner = 0; GetIntProperty("Annotation.CornerPosition", corner); return corner; } void mitk::LogoAnnotation::SetRelativeSize(const float &size) { SetFloatProperty("Annotation.RelativeSize", size); Modified(); } float mitk::LogoAnnotation::GetRelativeSize() const { float size = 0; GetFloatProperty("Annotation.RelativeSize", size); return size; } vtkProp *mitk::LogoAnnotation::GetVtkProp(BaseRenderer *renderer) const { LocalStorage *ls = this->m_LSH.GetLocalStorage(renderer); return ls->m_ImageActor; } diff --git a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2D.cpp b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2D.cpp index 4bcfa4dd3e..2a459e7c33 100644 --- a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2D.cpp +++ b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2D.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 "mitkContourModelGLMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "mitkContourModel.h" #include "mitkContourModelSubDivisionFilter.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include "mitkGL.h" mitk::ContourModelGLMapper2D::ContourModelGLMapper2D() : m_SubdivisionContour(mitk::ContourModel::New()), m_InitSubdivisionCurve(true) { } mitk::ContourModelGLMapper2D::~ContourModelGLMapper2D() { } -void mitk::ContourModelGLMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) +void mitk::ContourModelGLMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType /*type*/) { BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer); mitk::DataNode *dataNode = this->GetDataNode(); bool visible = true; dataNode->GetVisibility(visible, renderer, "visible"); if (!visible) return; mitk::ContourModel *input = this->GetInput(); mitk::ContourModel::Pointer renderingContour = input; bool subdivision = false; dataNode->GetBoolProperty("subdivision curve", subdivision, renderer); if (subdivision) { if (this->m_SubdivisionContour->GetMTime() < renderingContour->GetMTime() || m_InitSubdivisionCurve) { // mitk::ContourModel::Pointer subdivContour = mitk::ContourModel::New(); mitk::ContourModelSubDivisionFilter::Pointer subdivFilter = mitk::ContourModelSubDivisionFilter::New(); subdivFilter->SetInput(input); subdivFilter->Update(); this->m_SubdivisionContour = subdivFilter->GetOutput(); m_InitSubdivisionCurve = false; } renderingContour = this->m_SubdivisionContour; } this->DrawContour(renderingContour, renderer); ls->UpdateGenerateDataTime(); } mitk::ContourModel *mitk::ContourModelGLMapper2D::GetInput(void) { return const_cast(static_cast(GetDataNode()->GetData())); } void mitk::ContourModelGLMapper2D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { node->AddProperty("contour.color", ColorProperty::New(0.9, 1.0, 0.1), renderer, overwrite); node->AddProperty("contour.points.color", ColorProperty::New(1.0, 0.0, 0.1), renderer, overwrite); node->AddProperty("contour.points.show", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.segments.show", mitk::BoolProperty::New(true), renderer, overwrite); node->AddProperty("contour.controlpoints.show", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.width", mitk::FloatProperty::New(1.0), renderer, overwrite); node->AddProperty("contour.hovering.width", mitk::FloatProperty::New(3.0), renderer, overwrite); node->AddProperty("contour.hovering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.points.text", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.controlpoints.text", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("subdivision curve", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.project-onto-plane", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp index 8252017c36..a41b53241d 100644 --- a/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp +++ b/Modules/ContourModel/Rendering/mitkContourModelGLMapper2DBase.cpp @@ -1,396 +1,396 @@ /*=================================================================== 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 "mitkContourModelSetGLMapper2D.h" #include "mitkColorProperty.h" #include "mitkContourModelSet.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include "vtkPen.h" #include "vtkContext2D.h" #include "vtkContextDevice2D.h" #include "vtkOpenGLContextDevice2D.h" #include "mitkManualPlacementAnnotationRenderer.h" #include "mitkBaseRenderer.h" #include "mitkContourModel.h" #include "mitkTextAnnotation2D.h" mitk::ContourModelGLMapper2DBase::ContourModelGLMapper2DBase(): m_Initialized(false) { m_PointNumbersAnnotation = mitk::TextAnnotation2D::New(); m_ControlPointNumbersAnnotation = mitk::TextAnnotation2D::New(); } mitk::ContourModelGLMapper2DBase::~ContourModelGLMapper2DBase() { } -void mitk::ContourModelGLMapper2DBase::Initialize(mitk::BaseRenderer *renderer) +void mitk::ContourModelGLMapper2DBase::Initialize(mitk::BaseRenderer */*renderer*/) { vtkOpenGLContextDevice2D *device = NULL; device = vtkOpenGLContextDevice2D::New(); if (device) { this->m_Context->Begin(device); device->Delete(); this->m_Initialized = true; } else { } } void mitk::ContourModelGLMapper2DBase::ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor * /*actor*/) { float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // check for color prop and use it for rendering if it exists GetDataNode()->GetColor(rgba, renderer, "color"); // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(rgba[3], renderer, "opacity"); this->m_Context->GetPen()->SetColorF((double)rgba[0], (double)rgba[1], (double)rgba[2], (double)rgba[3]); } void mitk::ContourModelGLMapper2DBase::DrawContour(mitk::ContourModel *renderingContour, mitk::BaseRenderer *renderer) { if (std::find(m_RendererList.begin(), m_RendererList.end(), renderer) == m_RendererList.end()) { m_RendererList.push_back(renderer); } mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_PointNumbersAnnotation.GetPointer(), renderer); m_PointNumbersAnnotation->SetVisibility(false); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_ControlPointNumbersAnnotation.GetPointer(), renderer); m_ControlPointNumbersAnnotation->SetVisibility(false); InternalDrawContour(renderingContour, renderer); } void mitk::ContourModelGLMapper2DBase::InternalDrawContour(mitk::ContourModel *renderingContour, mitk::BaseRenderer *renderer) { if (!renderingContour) return; if (!this->m_Initialized) { this->Initialize(renderer); } vtkOpenGLContextDevice2D::SafeDownCast( this->m_Context->GetDevice())->Begin(renderer->GetVtkRenderer()); mitk::DataNode *dataNode = this->GetDataNode(); renderingContour->UpdateOutputInformation(); unsigned int timestep = renderer->GetTimeStep(); if (!renderingContour->IsEmptyTimeStep(timestep)) { // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(dataNode->GetProperty("contour.color", renderer)); float opacity = 0.5; dataNode->GetFloatProperty("opacity", opacity, renderer); if (colorprop) { // set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); this->m_Context->GetPen()->SetColorF(red, green, blue, opacity); } mitk::ColorProperty::Pointer selectedcolor = dynamic_cast(dataNode->GetProperty("contour.points.color", renderer)); if (!selectedcolor) { selectedcolor = mitk::ColorProperty::New(1.0, 0.0, 0.1); } vtkLinearTransform *transform = dataNode->GetVtkTransform(); // ContourModel::OutputType point; mitk::Point3D point; mitk::Point3D p; float vtkp[3]; float lineWidth = 3.0; bool drawit = false; bool isHovering = false; dataNode->GetBoolProperty("contour.hovering", isHovering); if (isHovering) dataNode->GetFloatProperty("contour.hovering.width", lineWidth); else dataNode->GetFloatProperty("contour.width", lineWidth); bool showSegments = false; dataNode->GetBoolProperty("contour.segments.show", showSegments); bool showControlPoints = false; dataNode->GetBoolProperty("contour.controlpoints.show", showControlPoints); bool showPoints = false; dataNode->GetBoolProperty("contour.points.show", showPoints); bool showPointsNumbers = false; dataNode->GetBoolProperty("contour.points.text", showPointsNumbers); bool showControlPointsNumbers = false; dataNode->GetBoolProperty("contour.controlpoints.text", showControlPointsNumbers); bool projectmode = false; dataNode->GetVisibility(projectmode, renderer, "contour.project-onto-plane"); mitk::ContourModel::VertexIterator pointsIt = renderingContour->IteratorBegin(timestep); Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; int index = 0; mitk::ScalarType maxDiff = 0.25; while (pointsIt != renderingContour->IteratorEnd(timestep)) { lastPt2d = pt2d; point = (*pointsIt)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); - renderer->WorldToDisplay(p, pt2d); + renderer->WorldToView(p, pt2d); ScalarType scalardiff = fabs(renderer->GetCurrentWorldPlaneGeometry()->SignedDistance(p)); // project to plane if (projectmode) { drawit = true; } else if (scalardiff < maxDiff) // point is close enough to be drawn { drawit = true; } else { drawit = false; } // draw line if (drawit) { if (showSegments) { // lastPt2d is not valid in first step if (!(pointsIt == renderingContour->IteratorBegin(timestep))) { this->m_Context->GetPen()->SetWidth(lineWidth); this->m_Context->DrawLine(pt2d[0], pt2d[1], lastPt2d[0], lastPt2d[1]); this->m_Context->GetPen()->SetWidth(1); } } if (showControlPoints) { // draw ontrol points if ((*pointsIt)->IsControlPoint) { float pointsize = 4; Point2D tmp; Vector2D horz, vert; horz[1] = 0; vert[0] = 0; horz[0] = pointsize; vert[1] = pointsize; this->m_Context->GetPen()->SetColorF(selectedcolor->GetColor().GetRed(), selectedcolor->GetColor().GetBlue(), selectedcolor->GetColor().GetGreen()); this->m_Context->GetPen()->SetWidth(1); // a rectangle around the point with the selected color float* rectPts = new float[8]; tmp = pt2d - horz; rectPts[0] = tmp[0]; rectPts[1] = tmp[1]; tmp = pt2d + vert; rectPts[2] = tmp[0]; rectPts[3] = tmp[1]; tmp = pt2d + horz; rectPts[4] = tmp[0]; rectPts[5] = tmp[1]; tmp = pt2d - vert; rectPts[6] = tmp[0]; rectPts[7] = tmp[1]; this->m_Context->DrawPolygon(rectPts,4); // the actual point in the specified color to see the usual color of the point this->m_Context->GetPen()->SetColorF( colorprop->GetColor().GetRed(), colorprop->GetColor().GetGreen(), colorprop->GetColor().GetBlue()); this->m_Context->DrawPoint(pt2d[0], pt2d[1]); } } if (showPoints) { float pointsize = 3; Point2D tmp; Vector2D horz, vert; horz[1] = 0; vert[0] = 0; horz[0] = pointsize; vert[1] = pointsize; this->m_Context->GetPen()->SetColorF(0.0, 0.0, 0.0); this->m_Context->GetPen()->SetWidth(1); // a rectangle around the point with the selected color float* rectPts = new float[8]; tmp = pt2d - horz; rectPts[0] = tmp[0]; rectPts[1] = tmp[1]; tmp = pt2d + vert; rectPts[2] = tmp[0]; rectPts[3] = tmp[1]; tmp = pt2d + horz; rectPts[4] = tmp[0]; rectPts[5] = tmp[1]; tmp = pt2d - vert; rectPts[6] = tmp[0]; rectPts[7] = tmp[1]; this->m_Context->DrawPolygon(rectPts, 4); // the actual point in the specified color to see the usual color of the point this->m_Context->GetPen()->SetColorF( colorprop->GetColor().GetRed(), colorprop->GetColor().GetGreen(), colorprop->GetColor().GetBlue()); this->m_Context->DrawPoint(pt2d[0], pt2d[1]); } if (showPointsNumbers) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); float rgb[3]; rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0; WriteTextWithAnnotation(m_PointNumbersAnnotation, l.c_str(), rgb, pt2d, renderer); } if (showControlPointsNumbers && (*pointsIt)->IsControlPoint) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); float rgb[3]; rgb[0] = 1.0; rgb[1] = 1.0; rgb[2] = 0.0; WriteTextWithAnnotation(m_ControlPointNumbersAnnotation, l.c_str(), rgb, pt2d, renderer); } index++; } pointsIt++; } // end while iterate over controlpoints // close contour if necessary if (renderingContour->IsClosed(timestep) && drawit && showSegments) { lastPt2d = pt2d; point = renderingContour->GetVertexAt(0, timestep)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, pt2d); this->m_Context->GetPen()->SetWidth(lineWidth); this->m_Context->DrawLine(lastPt2d[0], lastPt2d[1], pt2d[0], pt2d[1]); this->m_Context->GetPen()->SetWidth(1); } // draw selected vertex if exists if (renderingContour->GetSelectedVertex()) { // transform selected vertex point = renderingContour->GetSelectedVertex()->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, pt2d); ScalarType scalardiff = fabs(renderer->GetCurrentWorldPlaneGeometry()->SignedDistance(p)); //---------------------------------- // draw point if close to plane if (scalardiff < maxDiff) { float pointsize = 5; Point2D tmp; this->m_Context->GetPen()->SetColorF(0.0, 1.0, 0.0); this->m_Context->GetPen()->SetWidth(1); // a rectangle around the point with the selected color float* rectPts = new float[8]; // a diamond around the point // begin from upper left corner and paint clockwise rectPts[0] = pt2d[0] - pointsize; rectPts[1] = pt2d[1] + pointsize; rectPts[2] = pt2d[0] + pointsize; rectPts[3] = pt2d[1] + pointsize; rectPts[4] = pt2d[0] + pointsize; rectPts[5] = pt2d[1] - pointsize; rectPts[6] = pt2d[0] - pointsize; rectPts[7] = pt2d[1] - pointsize; this->m_Context->DrawPolygon(rectPts, 4); } //------------------------------------ } } this->m_Context->GetDevice()->End(); } void mitk::ContourModelGLMapper2DBase::WriteTextWithAnnotation(TextAnnotationPointerType textAnnotation, const char *text, float rgb[3], Point2D /*pt2d*/, mitk::BaseRenderer * /*renderer*/) { textAnnotation->SetText(text); textAnnotation->SetColor(rgb); textAnnotation->SetOpacity(1); textAnnotation->SetFontSize(16); textAnnotation->SetBoolProperty("drawShadow", false); textAnnotation->SetVisibility(true); } diff --git a/Modules/ContourModel/Rendering/mitkContourModelSetGLMapper2D.cpp b/Modules/ContourModel/Rendering/mitkContourModelSetGLMapper2D.cpp index a12a6e0901..b51290694e 100644 --- a/Modules/ContourModel/Rendering/mitkContourModelSetGLMapper2D.cpp +++ b/Modules/ContourModel/Rendering/mitkContourModelSetGLMapper2D.cpp @@ -1,396 +1,396 @@ /*=================================================================== 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 "mitkContourModelSetGLMapper2D.h" #include "mitkColorProperty.h" #include "mitkContourModelSet.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include "mitkGL.h" mitk::ContourModelSetGLMapper2D::ContourModelSetGLMapper2D() { } mitk::ContourModelSetGLMapper2D::~ContourModelSetGLMapper2D() { } -void mitk::ContourModelSetGLMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) +void mitk::ContourModelSetGLMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType /*type*/) { BaseLocalStorage *ls = m_LSH.GetLocalStorage(renderer); mitk::DataNode::Pointer dataNode = this->GetDataNode(); bool visible = true; dataNode->GetVisibility(visible, nullptr); if (!visible) return; mitk::ContourModelSet::Pointer input = this->GetInput(); auto centerOfViewPointZ = renderer->GetCurrentWorldPlaneGeometry()->GetCenter()[2]; mitk::ContourModelSet::ContourModelSetIterator it = input->Begin(); mitk::ContourModelSet::ContourModelSetIterator end = input->End(); while (it != end) { //we have the assumption that each contour model vertex has the same z coordinate auto currentZValue = (*it)->GetVertexAt(0)->Coordinates[2]; double acceptedDeviationInMM = 5.0; //only draw contour if it is visible if (currentZValue - acceptedDeviationInMM < centerOfViewPointZ && currentZValue + acceptedDeviationInMM > centerOfViewPointZ){ this->DrawContour(it->GetPointer(), renderer); } ++it; } if (input->GetSize() < 1) return; ls->UpdateGenerateDataTime(); } mitk::ContourModelSet *mitk::ContourModelSetGLMapper2D::GetInput(void) { return const_cast(static_cast(GetDataNode()->GetData())); } void mitk::ContourModelSetGLMapper2D::InternalDrawContour(mitk::ContourModel *renderingContour, mitk::BaseRenderer *renderer) { if (!renderingContour) return; mitk::DataNode::Pointer dataNode = this->GetDataNode(); renderingContour->UpdateOutputInformation(); unsigned int timestep = renderer->GetTimeStep(); if (!renderingContour->IsEmptyTimeStep(timestep)) { // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); mitk::ColorProperty::Pointer colorprop = dynamic_cast(dataNode->GetProperty("contour.color", renderer)); float opacity = 0.5; dataNode->GetFloatProperty("opacity", opacity, renderer); if (colorprop) { // set the color of the contour double red = colorprop->GetColor().GetRed(); double green = colorprop->GetColor().GetGreen(); double blue = colorprop->GetColor().GetBlue(); glColor4f(red, green, blue, opacity); } mitk::ColorProperty::Pointer selectedcolor = dynamic_cast(dataNode->GetProperty("contour.points.color", renderer)); if (!selectedcolor) { selectedcolor = mitk::ColorProperty::New(1.0, 0.0, 0.1); } vtkLinearTransform *transform = dataNode->GetVtkTransform(); // ContourModel::OutputType point; mitk::Point3D point; mitk::Point3D p; float vtkp[3]; float lineWidth = 3.0; bool drawit = false; bool isHovering = false; dataNode->GetBoolProperty("contour.hovering", isHovering); if (isHovering) dataNode->GetFloatProperty("contour.hovering.width", lineWidth); else dataNode->GetFloatProperty("contour.width", lineWidth); bool showSegments = false; dataNode->GetBoolProperty("contour.segments.show", showSegments); bool showControlPoints = false; dataNode->GetBoolProperty("contour.controlpoints.show", showControlPoints); bool showPoints = false; dataNode->GetBoolProperty("contour.points.show", showPoints); bool showPointsNumbers = false; dataNode->GetBoolProperty("contour.points.text", showPointsNumbers); bool showControlPointsNumbers = false; dataNode->GetBoolProperty("contour.controlpoints.text", showControlPointsNumbers); bool projectmode = false; dataNode->GetVisibility(projectmode, renderer, "contour.project-onto-plane"); mitk::ContourModel::VertexIterator pointsIt = renderingContour->IteratorBegin(timestep); Point2D pt2d; // projected_p in display coordinates Point2D lastPt2d; int index = 0; mitk::ScalarType maxDiff = 0.25; while (pointsIt != renderingContour->IteratorEnd(timestep)) { lastPt2d = pt2d; point = (*pointsIt)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, pt2d); ScalarType scalardiff = fabs(renderer->GetCurrentWorldPlaneGeometry()->SignedDistance(p)); // project to plane if (projectmode) { drawit = true; } else if (scalardiff < maxDiff) // point is close enough to be drawn { drawit = true; } else { drawit = false; } // draw line if (drawit) { if (showSegments) { // lastPt2d is not valid in first step if (!(pointsIt == renderingContour->IteratorBegin(timestep))) { glLineWidth(lineWidth); glBegin(GL_LINES); glVertex2f(pt2d[0], pt2d[1]); glVertex2f(lastPt2d[0], lastPt2d[1]); glEnd(); glLineWidth(1); } } if (showControlPoints) { // draw control points if ((*pointsIt)->IsControlPoint) { float pointsize = 4; Point2D tmp; Vector2D horz, vert; horz[1] = 0; vert[0] = 0; horz[0] = pointsize; vert[1] = pointsize; glColor3f(selectedcolor->GetColor().GetRed(), selectedcolor->GetColor().GetBlue(), selectedcolor->GetColor().GetGreen()); glLineWidth(1); // a rectangle around the point with the selected color glBegin(GL_LINE_LOOP); tmp = pt2d - horz; glVertex2dv(&tmp[0]); tmp = pt2d + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz; glVertex2dv(&tmp[0]); tmp = pt2d - vert; glVertex2dv(&tmp[0]); glEnd(); glLineWidth(1); // the actual point in the specified color to see the usual color of the point glColor3f( colorprop->GetColor().GetRed(), colorprop->GetColor().GetGreen(), colorprop->GetColor().GetBlue()); glPointSize(1); glBegin(GL_POINTS); tmp = pt2d; glVertex2dv(&tmp[0]); glEnd(); } } if (showPoints) { float pointsize = 3; Point2D tmp; Vector2D horz, vert; horz[1] = 0; vert[0] = 0; horz[0] = pointsize; vert[1] = pointsize; glColor3f(0.0, 0.0, 0.0); glLineWidth(1); // a rectangle around the point with the selected color glBegin(GL_LINE_LOOP); tmp = pt2d - horz; glVertex2dv(&tmp[0]); tmp = pt2d + vert; glVertex2dv(&tmp[0]); tmp = pt2d + horz; glVertex2dv(&tmp[0]); tmp = pt2d - vert; glVertex2dv(&tmp[0]); glEnd(); glLineWidth(1); // the actual point in the specified color to see the usual color of the point glColor3f(colorprop->GetColor().GetRed(), colorprop->GetColor().GetGreen(), colorprop->GetColor().GetBlue()); glPointSize(1); glBegin(GL_POINTS); tmp = pt2d; glVertex2dv(&tmp[0]); glEnd(); } if (showPointsNumbers) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); float rgb[3]; rgb[0] = 0.0; rgb[1] = 0.0; rgb[2] = 0.0; WriteTextWithAnnotation(m_PointNumbersAnnotation, l.c_str(), rgb, pt2d, renderer); } if (showControlPointsNumbers && (*pointsIt)->IsControlPoint) { std::string l; std::stringstream ss; ss << index; l.append(ss.str()); float rgb[3]; rgb[0] = 1.0; rgb[1] = 1.0; rgb[2] = 0.0; WriteTextWithAnnotation(m_ControlPointNumbersAnnotation, l.c_str(), rgb, pt2d, renderer); } index++; } pointsIt++; } // end while iterate over controlpoints // close contour if necessary if (renderingContour->IsClosed(timestep) && drawit && showSegments) { lastPt2d = pt2d; point = renderingContour->GetVertexAt(0, timestep)->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, pt2d); glLineWidth(lineWidth); glBegin(GL_LINES); glVertex2f(lastPt2d[0], lastPt2d[1]); glVertex2f(pt2d[0], pt2d[1]); glEnd(); glLineWidth(1); } // draw selected vertex if exists if (renderingContour->GetSelectedVertex()) { // transform selected vertex point = renderingContour->GetSelectedVertex()->Coordinates; itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->WorldToDisplay(p, pt2d); ScalarType scalardiff = fabs(renderer->GetCurrentWorldPlaneGeometry()->SignedDistance(p)); //---------------------------------- // draw point if close to plane if (scalardiff < maxDiff) { float pointsize = 5; Point2D tmp; glColor3f(0.0, 1.0, 0.0); glLineWidth(1); // a diamond around the point glBegin(GL_LINE_LOOP); // begin from upper left corner and paint clockwise tmp[0] = pt2d[0] - pointsize; tmp[1] = pt2d[1] + pointsize; glVertex2dv(&tmp[0]); tmp[0] = pt2d[0] + pointsize; tmp[1] = pt2d[1] + pointsize; glVertex2dv(&tmp[0]); tmp[0] = pt2d[0] + pointsize; tmp[1] = pt2d[1] - pointsize; glVertex2dv(&tmp[0]); tmp[0] = pt2d[0] - pointsize; tmp[1] = pt2d[1] - pointsize; glVertex2dv(&tmp[0]); glEnd(); } //------------------------------------ } } } void mitk::ContourModelSetGLMapper2D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { node->AddProperty("contour.color", ColorProperty::New(0.9, 1.0, 0.1), renderer, overwrite); node->AddProperty("contour.points.color", ColorProperty::New(1.0, 0.0, 0.1), renderer, overwrite); node->AddProperty("contour.points.show", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.segments.show", mitk::BoolProperty::New(true), renderer, overwrite); node->AddProperty("contour.controlpoints.show", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.width", mitk::FloatProperty::New(1.0), renderer, overwrite); node->AddProperty("contour.hovering.width", mitk::FloatProperty::New(3.0), renderer, overwrite); node->AddProperty("contour.hovering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.points.text", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.controlpoints.text", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("contour.project-onto-plane", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("opacity", mitk::FloatProperty::New(1.0f), renderer, overwrite); Superclass::SetDefaultProperties(node, renderer, overwrite); } diff --git a/Modules/Core/include/mitkBaseRenderer.h b/Modules/Core/include/mitkBaseRenderer.h index cd126b3c0d..46a372528d 100644 --- a/Modules/Core/include/mitkBaseRenderer.h +++ b/Modules/Core/include/mitkBaseRenderer.h @@ -1,547 +1,558 @@ /*=================================================================== 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. */ struct RenderingMode { enum Type { Standard = 0, // no multi-sampling, no depth-peeling MultiSampling, // multi-sampling (antialiasing), no depth-peeling DepthPeeling // no multi-sampling, depth-peeling is on (order-independant transparency) }; }; 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::Type mode = RenderingMode::Standard); //##Documentation //## @brief MapperSlotId defines which kind of mapper (e.g., 2D or 3D) shoud be used. typedef int MapperSlotId; enum StandardMapperSlot { Standard2D = 1, Standard3D = 2 }; 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(BaseGeometry *geometry); virtual void SetWorldTimeGeometry(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) itkGetObjectMacro(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: virtual ~BaseRenderer(); //##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(PlaneGeometry *geometry2d); /** * \deprecatedSince{2014_10} Please use SetCurrentWorldPlaneGeometry */ DEPRECATED(void SetCurrentWorldGeometry2D(PlaneGeometry *geometry2d)) { SetCurrentWorldPlaneGeometry(geometry2d); }; //##Documentation //## @brief Sets m_CurrentWorldGeometry virtual void SetCurrentWorldGeometry(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::Pointer m_WorldTimeGeometry; //##Documentation //## Pointer to the current 3D-worldgeometry. BaseGeometry::Pointer 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: virtual 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/src/Rendering/mitkBaseRenderer.cpp b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp index 047df06e48..cde6d18e19 100644 --- a/Modules/Core/src/Rendering/mitkBaseRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkBaseRenderer.cpp @@ -1,758 +1,787 @@ /*=================================================================== 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 (BaseRendererMapType::iterator 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) { BaseRendererMapType::iterator mapit = baseRendererMap.find(renWin); if (mapit != baseRendererMap.end()) baseRendererMap.erase(mapit); } mitk::BaseRenderer *mitk::BaseRenderer::GetByName(const std::string &name) { for (BaseRendererMapType::iterator 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 (BaseRendererMapType::iterator 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::Type renderingMode) : 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(); if (renderingMode == RenderingMode::DepthPeeling) { m_VtkRenderer->SetUseDepthPeeling(1); m_VtkRenderer->SetMaximumNumberOfPeels(8); m_VtkRenderer->SetOcclusionRatio(0.0); } if (mitk::VtkLayerController::GetInstance(m_RenderWindow) == nullptr) { 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(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(mitk::BaseGeometry *geometry) { itkDebugMacro("setting WorldGeometry3D to " << geometry); if (geometry->GetBoundingBox()->GetDiagonalLength2() == 0) return; SlicedGeometry3D *slicedWorldGeometry; slicedWorldGeometry = dynamic_cast(geometry); PlaneGeometry::Pointer 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(mitk::PlaneGeometry *geometry2d) { if (m_CurrentWorldPlaneGeometry != geometry2d) { m_CurrentWorldPlaneGeometry = geometry2d; 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(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 SliceNavigationController::GeometrySendEvent *sendEvent = dynamic_cast(&geometrySendEvent); assert(sendEvent != nullptr); SetWorldTimeGeometry(sendEvent->GetTimeGeometry()); } void mitk::BaseRenderer::UpdateGeometry(const itk::EventObject &geometryUpdateEvent) { const SliceNavigationController::GeometryUpdateEvent *updateEvent = dynamic_cast(&geometryUpdateEvent); if (updateEvent == nullptr) return; if (m_CurrentWorldGeometry.IsNotNull()) { SlicedGeometry3D *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 SliceNavigationController::GeometrySliceEvent *sliceEvent = dynamic_cast(&geometrySliceEvent); assert(sliceEvent != nullptr); SetSlice(sliceEvent->GetPos()); } void mitk::BaseRenderer::SetGeometryTime(const itk::EventObject &geometryTimeEvent) { const SliceNavigationController::GeometryTimeEvent *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); } void mitk::BaseRenderer::ForceImmediateUpdate() { m_RenderingManager->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/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp index 8b254c25d6..870318191f 100644 --- a/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp +++ b/Modules/MapperExt/src/mitkVolumeMapperVtkSmart3D.cpp @@ -1,255 +1,255 @@ /*=================================================================== 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 "mitkVolumeMapperVtkSmart3D.h" #include "mitkTransferFunctionProperty.h" #include "mitkTransferFunctionInitializer.h" #include "mitkLevelWindowProperty.h" #include #include #include #include #include void mitk::VolumeMapperVtkSmart3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { if (this->GetDataNode()->GetMTime() < this->GetMTime()) { return; } bool value; this->GetDataNode()->GetBoolProperty("volumerendering", value, renderer); if (!value) { m_Volume->VisibilityOff(); return; } else { m_Volume->VisibilityOn(); } UpdateTransferFunctions(renderer); UpdateRenderMode(renderer); this->Modified(); } -vtkProp* mitk::VolumeMapperVtkSmart3D::GetVtkProp(mitk::BaseRenderer *renderer) +vtkProp* mitk::VolumeMapperVtkSmart3D::GetVtkProp(mitk::BaseRenderer */*renderer*/) { if (!m_Volume->GetMapper()) { createMapper(GetInputImage()); createVolume(); createVolumeProperty(); } return m_Volume; } -void mitk::VolumeMapperVtkSmart3D::ApplyProperties(vtkActor *actor, mitk::BaseRenderer *renderer) +void mitk::VolumeMapperVtkSmart3D::ApplyProperties(vtkActor */*actor*/, mitk::BaseRenderer */*renderer*/) { } void mitk::VolumeMapperVtkSmart3D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { // GPU_INFO << "SetDefaultProperties"; node->AddProperty("volumerendering", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.usemip", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.cpu.ambient", mitk::FloatProperty::New(0.10f), renderer, overwrite); node->AddProperty("volumerendering.cpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.cpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("volumerendering.usegpu", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.useray", mitk::BoolProperty::New(false), renderer, overwrite); node->AddProperty("volumerendering.gpu.ambient", mitk::FloatProperty::New(0.25f), renderer, overwrite); node->AddProperty("volumerendering.gpu.diffuse", mitk::FloatProperty::New(0.50f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular", mitk::FloatProperty::New(0.40f), renderer, overwrite); node->AddProperty("volumerendering.gpu.specular.power", mitk::FloatProperty::New(16.0f), renderer, overwrite); node->AddProperty("binary", mitk::BoolProperty::New(false), renderer, overwrite); mitk::Image::Pointer image = dynamic_cast(node->GetData()); if (image.IsNotNull() && image->IsInitialized()) { if ((overwrite) || (node->GetProperty("levelwindow", renderer) == nullptr)) { mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetAuto(image); levWinProp->SetLevelWindow(levelwindow); node->SetProperty("levelwindow", levWinProp, renderer); } if ((overwrite) || (node->GetProperty("TransferFunction", renderer) == nullptr)) { // add a default transfer function mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); mitk::TransferFunctionInitializer::Pointer tfInit = mitk::TransferFunctionInitializer::New(tf); tfInit->SetTransferFunctionMode(0); node->SetProperty("TransferFunction", mitk::TransferFunctionProperty::New(tf.GetPointer())); } } Superclass::SetDefaultProperties(node, renderer, overwrite); } vtkImageData* mitk::VolumeMapperVtkSmart3D::GetInputImage() { mitk::Image *input = const_cast(static_cast(this->GetDataNode()->GetData())); vtkImageData* img = input->GetVtkImageData(this->GetTimestep()); img->SetSpacing(1,1,1); return img; } void mitk::VolumeMapperVtkSmart3D::createMapper(vtkImageData* imageData) { m_SmartVolumeMapper->SetBlendModeToComposite(); m_SmartVolumeMapper->SetInputData(imageData); } void mitk::VolumeMapperVtkSmart3D::createVolume() { m_Volume->VisibilityOff(); m_Volume->SetMapper(m_SmartVolumeMapper); m_Volume->SetProperty(m_VolumeProperty); } void mitk::VolumeMapperVtkSmart3D::createVolumeProperty() { m_VolumeProperty->ShadeOn(); m_VolumeProperty->SetInterpolationType(VTK_LINEAR_INTERPOLATION); } void mitk::VolumeMapperVtkSmart3D::UpdateTransferFunctions(mitk::BaseRenderer *renderer) { vtkSmartPointer opacityTransferFunction; vtkSmartPointer gradientTransferFunction; vtkSmartPointer colorTransferFunction; bool isBinary = false; this->GetDataNode()->GetBoolProperty("binary", isBinary, renderer); if (isBinary) { colorTransferFunction = vtkSmartPointer::New(); float rgb[3]; if (!GetDataNode()->GetColor(rgb, renderer)) rgb[0] = rgb[1] = rgb[2] = 1; colorTransferFunction->AddRGBPoint(0, rgb[0], rgb[1], rgb[2]); colorTransferFunction->Modified(); opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); } else { mitk::TransferFunctionProperty *transferFunctionProp = dynamic_cast(this->GetDataNode()->GetProperty("TransferFunction", renderer)); if (transferFunctionProp) { opacityTransferFunction = transferFunctionProp->GetValue()->GetScalarOpacityFunction(); gradientTransferFunction = transferFunctionProp->GetValue()->GetGradientOpacityFunction(); colorTransferFunction = transferFunctionProp->GetValue()->GetColorTransferFunction(); } else { opacityTransferFunction = vtkSmartPointer::New(); gradientTransferFunction = vtkSmartPointer::New(); colorTransferFunction = vtkSmartPointer::New(); } } m_VolumeProperty->SetColor(colorTransferFunction); m_VolumeProperty->SetScalarOpacity(opacityTransferFunction); m_VolumeProperty->SetGradientOpacity(gradientTransferFunction); } void mitk::VolumeMapperVtkSmart3D::UpdateRenderMode(mitk::BaseRenderer *renderer) { bool usegpu = false; bool useray = false; bool usemip = false; this->GetDataNode()->GetBoolProperty("volumerendering.usegpu", usegpu); this->GetDataNode()->GetBoolProperty("volumerendering.useray", useray); this->GetDataNode()->GetBoolProperty("volumerendering.usemip", usemip); if (usegpu) m_SmartVolumeMapper->SetRequestedRenderModeToGPU(); else if (useray) m_SmartVolumeMapper->SetRequestedRenderModeToRayCast(); else m_SmartVolumeMapper->SetRequestedRenderModeToDefault(); int blendMode; if (this->GetDataNode()->GetIntProperty("volumerendering.blendmode", blendMode)) m_SmartVolumeMapper->SetBlendMode(blendMode); else if (usemip) m_SmartVolumeMapper->SetBlendMode(vtkSmartVolumeMapper::MAXIMUM_INTENSITY_BLEND); // shading parameter if (m_SmartVolumeMapper->GetRequestedRenderMode() == vtkSmartVolumeMapper::GPURenderMode) { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.gpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } else { float value = 0; if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.ambient", value, renderer)) m_VolumeProperty->SetAmbient(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.diffuse", value, renderer)) m_VolumeProperty->SetDiffuse(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular", value, renderer)) m_VolumeProperty->SetSpecular(value); if (this->GetDataNode()->GetFloatProperty("volumerendering.cpu.specular.power", value, renderer)) m_VolumeProperty->SetSpecularPower(value); } } mitk::VolumeMapperVtkSmart3D::VolumeMapperVtkSmart3D() { vtkObjectFactory::RegisterFactory(vtkRenderingOpenGL2ObjectFactory::New()); vtkObjectFactory::RegisterFactory(vtkRenderingVolumeOpenGL2ObjectFactory::New()); m_SmartVolumeMapper = vtkSmartPointer::New(); m_SmartVolumeMapper->SetBlendModeToComposite(); m_VolumeProperty = vtkSmartPointer::New(); m_Volume = vtkSmartPointer::New(); } mitk::VolumeMapperVtkSmart3D::~VolumeMapperVtkSmart3D() { } diff --git a/Modules/PlanarFigure/include/mitkPlanarFigureMapper2D.h b/Modules/PlanarFigure/include/mitkPlanarFigureMapper2D.h index 1900011700..3b3d7fa55f 100644 --- a/Modules/PlanarFigure/include/mitkPlanarFigureMapper2D.h +++ b/Modules/PlanarFigure/include/mitkPlanarFigureMapper2D.h @@ -1,324 +1,320 @@ /*=================================================================== 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 MITK_PLANAR_FIGURE_MAPPER_2D_H_ #define MITK_PLANAR_FIGURE_MAPPER_2D_H_ #include "mitkCommon.h" #include "mitkMapper.h" #include "mitkPlanarFigure.h" #include "mitkPlanarFigureControlPointStyleProperty.h" #include #include "vtkNew.h" #include "vtkPen.h" class vtkContext2D; namespace mitk { class BaseRenderer; class Contour; - class TextAnnotation2D; /** * \brief OpenGL-based mapper to render display sub-class instances of mitk::PlanarFigure * * The appearance of planar figures can be configured through properties. If no properties are specified, * default values will be used. There are four elements a planar figure consists of: * *
    *
  1. "line": the main line segments of the planar figure (note: text is drawn in the same style) *
  2. "helperline": additional line segments of planar figures, such as arrow tips, arches of angles, etc. *
  3. "outline": background which is drawn behind the lines and helperlines of the planar figure (optional) *
  4. "marker": the markers (control points) of a planar figure *
  5. "markerline": the lines by which markers (control points) are surrounded *
* * In the following, all appearance-related planar figure properties are listed: * *
    *
  1. General properties for the planar figure *
      *
    • "planarfigure.drawoutline": if true, the "outline" lines is drawn *
    • "planarfigure.drawquantities": if true, the quantities (text) associated with the planar figure is drawn *
    • "planarfigure.drawname": if true, the name specified by the dataNode is drawn *
    • "planarfigure.drawshadow": if true, a black shadow is drawn around the planar figure *
    • "planarfigure.controlpointshape": style of the control points (enum) *
    *
  2. Line widths of planar figure elements *
      *
    • "planarfigure.line.width": width of "line" segments (float value, in mm) *
    • "planarfigure.shadow.widthmodifier": the width of the shadow is defined by width of the "line" * this * modifier *
    • "planarfigure.outline.width": width of "outline" segments (float value, in mm) *
    • "planarfigure.helperline.width": width of "helperline" segments (float value, in mm) *
    *
  3. Color/opacity of planar figure elements in normal mode (unselected) *
      *
    • "planarfigure.default.line.color" *
    • "planarfigure.default.line.opacity" *
    • "planarfigure.default.outline.color" *
    • "planarfigure.default.outline.opacity" *
    • "planarfigure.default.helperline.color" *
    • "planarfigure.default.helperline.opacity" *
    • "planarfigure.default.markerline.color" *
    • "planarfigure.default.markerline.opacity" *
    • "planarfigure.default.marker.color" *
    • "planarfigure.default.marker.opacity" *
    *
  4. Color/opacity of planar figure elements in hover mode (mouse-over) *
      *
    • "planarfigure.hover.line.color" *
    • "planarfigure.hover.line.opacity" *
    • "planarfigure.hover.outline.color" *
    • "planarfigure.hover.outline.opacity" *
    • "planarfigure.hover.helperline.color" *
    • "planarfigure.hover.helperline.opacity" *
    • "planarfigure.hover.markerline.color" *
    • "planarfigure.hover.markerline.opacity" *
    • "planarfigure.hover.marker.color" *
    • "planarfigure.hover.marker.opacity" *
    *
  5. Color/opacity of planar figure elements in selected mode *
      *
    • "planarfigure.selected.line.color" *
    • "planarfigure.selected.line.opacity" *
    • "planarfigure.selected.outline.color" *
    • "planarfigure.selected.outline.opacity" *
    • "planarfigure.selected.helperline.color" *
    • "planarfigure.selected.helperline.opacity" *
    • "planarfigure.selected.markerline.color;" *
    • "planarfigure.selected.markerline.opacity" *
    • "planarfigure.selected.marker.color" *
    • "planarfigure.selected.marker.opacity" *
    *
* * @ingroup MitkPlanarFigureModule */ class MITKPLANARFIGURE_EXPORT PlanarFigureMapper2D : public Mapper { public: mitkClassMacro(PlanarFigureMapper2D, Mapper); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** * reimplemented from Baseclass */ void MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) override; static void SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer = nullptr, bool overwrite = false); /** \brief Apply color and opacity properties read from the PropertyList. * The actor is not used in the GLMappers. Called by mapper subclasses. */ virtual void ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor *actor = nullptr) override; protected: enum PlanarFigureDisplayMode { PF_DEFAULT = 0, PF_HOVER = 1, PF_SELECTED = 2, PF_COUNT = 3 // helper variable }; PlanarFigureMapper2D(); virtual ~PlanarFigureMapper2D(); /** * \brief Renders all the lines defined by the PlanarFigure. * * This method renders all the lines that are defined by the PlanarFigure. * That includes the mainlines and helperlines as well as their shadows * and the outlines. * * This method already takes responsibility for the setting of the relevant * openGL attributes to reduce unnecessary setting of these attributes. * (e.g. no need to set color twice if it's the same) */ void RenderLines(const PlanarFigureDisplayMode lineDisplayMode, mitk::PlanarFigure *planarFigure, mitk::Point2D &anchorPoint, const mitk::PlaneGeometry *planarFigurePlaneGeometry, const mitk::PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer); /** * \brief Renders the quantities of the figure below the text annotations. */ void RenderQuantities(const mitk::PlanarFigure *planarFigure, mitk::BaseRenderer *renderer, const mitk::Point2D anchorPoint, double &annotationOffset, float globalOpacity, const PlanarFigureDisplayMode lineDisplayMode); /** * \brief Renders the text annotations. */ void RenderAnnotations(mitk::BaseRenderer *renderer, const std::string name, const mitk::Point2D anchorPoint, float globalOpacity, const PlanarFigureDisplayMode lineDisplayMode, double &annotationOffset); /** * \brief Renders the control-points. */ void RenderControlPoints(const mitk::PlanarFigure *planarFigure, const PlanarFigureDisplayMode lineDisplayMode, const mitk::PlaneGeometry *planarFigurePlaneGeometry, const mitk::PlaneGeometry *rendererPlaneGeometry, mitk::BaseRenderer *renderer); void TransformObjectToDisplay(const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::PlaneGeometry *objectGeometry, const mitk::PlaneGeometry *, const mitk::BaseRenderer *renderer); void DrawMarker(const mitk::Point2D &point, float *lineColor, float lineOpacity, float *markerColor, float markerOpacity, float lineWidth, PlanarFigureControlPointStyleProperty::Shape shape, const mitk::PlaneGeometry *objectGeometry, const mitk::PlaneGeometry *rendererGeometry, const mitk::BaseRenderer *renderer); /** * \brief Actually paints the polyline defined by the figure. */ void PaintPolyLine(const mitk::PlanarFigure::PolyLineType vertices, bool closed, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer); /** * \brief Internally used by RenderLines() to draw the mainlines using * PaintPolyLine(). */ void DrawMainLines(mitk::PlanarFigure *figure, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer); /** * \brief Internally used by RenderLines() to draw the helperlines using * PaintPolyLine(). */ void DrawHelperLines(mitk::PlanarFigure *figure, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer); void InitializeDefaultPlanarFigureProperties(); void InitializePlanarFigurePropertiesFromDataNode(const mitk::DataNode *node); void SetColorProperty(float property[3][3], PlanarFigureDisplayMode mode, float red, float green, float blue) { property[mode][0] = red; property[mode][1] = green; property[mode][2] = blue; } void SetFloatProperty(float *property, PlanarFigureDisplayMode mode, float value) { property[mode] = value; } /** * \brief Callback that sets m_NodeModified to true. * * This method set the bool flag m_NodeModified to true. It's a callback * that is executed when a itk::ModifiedEvet is invoked on our * DataNode. */ void OnNodeModified(); void Initialize(mitk::BaseRenderer *renderer); private: bool m_IsSelected; bool m_IsHovering; bool m_DrawOutline; bool m_DrawQuantities; bool m_DrawShadow; bool m_DrawControlPoints; bool m_DrawName; bool m_DrawDashed; bool m_DrawHelperDashed; bool m_AnnotationsShadow; std::string m_AnnotationFontFamily; bool m_DrawAnnotationBold; bool m_DrawAnnotationItalic; int m_AnnotationSize; // the width of the shadow is defined as 'm_LineWidth * m_ShadowWidthFactor' float m_LineWidth; float m_ShadowWidthFactor; float m_OutlineWidth; float m_HelperlineWidth; // float m_PointWidth; float m_DevicePixelRatio; PlanarFigureControlPointStyleProperty::Shape m_ControlPointShape; float m_LineColor[3][3]; float m_LineOpacity[3]; float m_OutlineColor[3][3]; float m_OutlineOpacity[3]; float m_HelperlineColor[3][3]; float m_HelperlineOpacity[3]; float m_MarkerlineColor[3][3]; float m_MarkerlineOpacity[3]; float m_MarkerColor[3][3]; float m_MarkerOpacity[3]; float m_AnnotationColor[3][3]; // Bool flag that represents whether or not the DataNode has been modified. bool m_NodeModified; // Observer-tag for listening to itk::ModifiedEvents on the DataNode unsigned long m_NodeModifiedObserverTag; // Bool flag that indicates if a node modified observer was added bool m_NodeModifiedObserverAdded; bool m_Initialized; - itk::SmartPointer m_AnnotationAnnotation; - itk::SmartPointer m_QuantityAnnotation; - vtkNew m_Context; vtkSmartPointer m_Pen; }; } // namespace mitk #endif /* MITK_PLANAR_FIGURE_MAPPER_2D_H_ */ diff --git a/Modules/PlanarFigure/src/Rendering/mitkPlanarFigureMapper2D.cpp b/Modules/PlanarFigure/src/Rendering/mitkPlanarFigureMapper2D.cpp index 488cd5caa3..4ed57913d4 100644 --- a/Modules/PlanarFigure/src/Rendering/mitkPlanarFigureMapper2D.cpp +++ b/Modules/PlanarFigure/src/Rendering/mitkPlanarFigureMapper2D.cpp @@ -1,973 +1,975 @@ ïğż/*=================================================================== 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 "mitkPlanarFigureMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "vtkContext2D.h" #include "vtkContextDevice2D.h" #include "vtkOpenGLContextDevice2D.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" - -#include "mitkTextAnnotation2D.h" +#include "vtkTextProperty.h" #define _USE_MATH_DEFINES #include // offset which moves the planarfigures on top of the other content // the crosshair is rendered into the z = 1 layer. static const float PLANAR_OFFSET = 0.5f; mitk::PlanarFigureMapper2D::PlanarFigureMapper2D() : m_NodeModified(true), m_NodeModifiedObserverTag(0), m_NodeModifiedObserverAdded(false), m_Initialized(false) { - m_AnnotationAnnotation = mitk::TextAnnotation2D::New(); - m_QuantityAnnotation = mitk::TextAnnotation2D::New(); this->InitializeDefaultPlanarFigureProperties(); } mitk::PlanarFigureMapper2D::~PlanarFigureMapper2D() { if (m_NodeModifiedObserverAdded && GetDataNode() != nullptr) { GetDataNode()->RemoveObserver(m_NodeModifiedObserverTag); } } void mitk::PlanarFigureMapper2D::ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor * /*actor*/) { float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // check for color prop and use it for rendering if it exists GetDataNode()->GetColor(rgba, renderer, "color"); // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(rgba[3], renderer, "opacity"); this->m_Pen->SetColorF((double)rgba[0], (double)rgba[1], (double)rgba[2], (double)rgba[3]); } -void mitk::PlanarFigureMapper2D::Initialize(mitk::BaseRenderer *renderer) +void mitk::PlanarFigureMapper2D::Initialize(mitk::BaseRenderer */*renderer*/) { this->m_Pen = vtkSmartPointer::New(); vtkOpenGLContextDevice2D *device = NULL; device = vtkOpenGLContextDevice2D::New(); if (device) { this->m_Context->Begin(device); device->Delete(); this->m_Initialized = true; this->m_Context->ApplyPen(this->m_Pen); } else { } } void mitk::PlanarFigureMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) { if (type != mitk::VtkPropRenderer::Overlay) return; if (!this->m_Initialized) { this->Initialize(renderer); } vtkOpenGLContextDevice2D::SafeDownCast( this->m_Context->GetDevice())->Begin(renderer->GetVtkRenderer()); bool visible = true; - m_AnnotationAnnotation->SetVisibility(false); - - m_QuantityAnnotation->SetVisibility(false); - GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) return; // Get PlanarFigure from input mitk::PlanarFigure *planarFigure = const_cast(static_cast(GetDataNode()->GetData())); // Check if PlanarFigure has already been placed; otherwise, do nothing if (!planarFigure->IsPlaced()) { return; } // Get 2D geometry frame of PlanarFigure const mitk::PlaneGeometry *planarFigurePlaneGeometry = planarFigure->GetPlaneGeometry(); if (planarFigurePlaneGeometry == nullptr) { MITK_ERROR << "PlanarFigure does not have valid PlaneGeometry!"; return; } // Get current world 2D geometry from renderer const mitk::PlaneGeometry *rendererPlaneGeometry = renderer->GetCurrentWorldPlaneGeometry(); // If the PlanarFigure geometry is a plane geometry, check if current // world plane is parallel to and within the planar figure geometry bounds // (otherwise, display nothing) if ((planarFigurePlaneGeometry != nullptr) && (rendererPlaneGeometry != nullptr)) { double planeThickness = planarFigurePlaneGeometry->GetExtentInMM(2); if (!planarFigurePlaneGeometry->IsParallel(rendererPlaneGeometry) || !(planarFigurePlaneGeometry->DistanceFromPlane(rendererPlaneGeometry) < planeThickness / 3.0)) { // Planes are not parallel or renderer plane is not within PlanarFigure // geometry bounds --> exit return; } } else { // Plane is not valid (curved reformations are not possible yet) return; } // Apply visual appearance properties from the PropertyList ApplyColorAndOpacityProperties(renderer); // Get properties from node (if present) const mitk::DataNode *node = this->GetDataNode(); this->InitializePlanarFigurePropertiesFromDataNode(node); PlanarFigureDisplayMode lineDisplayMode = PF_DEFAULT; if (m_IsSelected) { lineDisplayMode = PF_SELECTED; } else if (m_IsHovering) { lineDisplayMode = PF_HOVER; } mitk::Point2D anchorPoint; anchorPoint[0] = 0; anchorPoint[1] = 1; // render the actual lines of the PlanarFigure RenderLines(lineDisplayMode, planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); // position-offset of the annotations, is set in RenderAnnotations() and // used in RenderQuantities() double annotationOffset = 0.0; // Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); if (m_DrawControlPoints) { // draw the control-points RenderControlPoints(planarFigure, lineDisplayMode, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } // draw name near the anchor point (point located on the right) const std::string name = node->GetName(); if (m_DrawName && !name.empty()) { RenderAnnotations(renderer, name, anchorPoint, globalOpacity, lineDisplayMode, annotationOffset); } // draw feature quantities (if requested) next to the anchor point, // but under the name (that is where 'annotationOffset' is used) if (m_DrawQuantities) { RenderQuantities(planarFigure, renderer, anchorPoint, annotationOffset, globalOpacity, lineDisplayMode); } this->m_Context->GetDevice()->End(); } void mitk::PlanarFigureMapper2D::PaintPolyLine(const mitk::PlanarFigure::PolyLineType vertices, bool closed, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer) { mitk::Point2D rightMostPoint; rightMostPoint.Fill(itk::NumericTraits::min()); // transform all vertices into Point2Ds in display-Coordinates and store them in vector std::vector pointlist; for (auto iter = vertices.cbegin(); iter != vertices.cend(); ++iter) { // Draw this 2D point as OpenGL vertex mitk::Point2D displayPoint; this->TransformObjectToDisplay(*iter, displayPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); pointlist.push_back(displayPoint); if (displayPoint[0] > rightMostPoint[0]) rightMostPoint = displayPoint; } // If the planarfigure is closed, we add the first control point again. // Thus we can always use 'GL_LINE_STRIP' and get rid of strange flickering // effect when using the MESA OpenGL library. if (closed) { mitk::Point2D displayPoint; this->TransformObjectToDisplay( vertices.cbegin()[0], displayPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); pointlist.push_back(displayPoint); } // now paint all the points in one run float* points = new float[pointlist.size()*2]; - for (int i = 0 ; i < pointlist.size() ; ++i) + for (unsigned int i = 0 ; i < pointlist.size() ; ++i) { points[i * 2] = pointlist[i][0]; points[i * 2 + 1] = pointlist[i][1]; } this->m_Context->DrawPoly(points,pointlist.size()); anchorPoint = rightMostPoint; } void mitk::PlanarFigureMapper2D::DrawMainLines(mitk::PlanarFigure *figure, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer) { const auto numberOfPolyLines = figure->GetPolyLinesSize(); for (auto loop = 0; loop < numberOfPolyLines; ++loop) { const auto polyline = figure->GetPolyLine(loop); this->PaintPolyLine( polyline, figure->IsClosed(), anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } } void mitk::PlanarFigureMapper2D::DrawHelperLines(mitk::PlanarFigure *figure, Point2D &anchorPoint, const PlaneGeometry *planarFigurePlaneGeometry, const PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer) { const auto numberOfHelperPolyLines = figure->GetHelperPolyLinesSize(); // Draw helper objects for (unsigned int loop = 0; loop < numberOfHelperPolyLines; ++loop) { const auto helperPolyLine = figure->GetHelperPolyLine(loop, renderer->GetScaleFactorMMPerDisplayUnit(), renderer->GetViewportSize()[1]); // Check if the current helper objects is to be painted if (!figure->IsHelperToBePainted(loop)) { continue; } // ... and once normally above the shadow. this->PaintPolyLine(helperPolyLine, false, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } } void mitk::PlanarFigureMapper2D::TransformObjectToDisplay(const mitk::Point2D &point2D, mitk::Point2D &displayPoint, const mitk::PlaneGeometry *objectGeometry, const mitk::PlaneGeometry * /*rendererGeometry*/, const mitk::BaseRenderer *renderer) { mitk::Point3D point3D; // Map circle point from local 2D geometry into 3D world space objectGeometry->Map(point2D, point3D); // Project 3D world point onto display geometry - renderer->WorldToDisplay(point3D, displayPoint); + renderer->WorldToView(point3D, displayPoint); } void mitk::PlanarFigureMapper2D::DrawMarker(const mitk::Point2D &point, float *lineColor, float lineOpacity, float *markerColor, float markerOpacity, float lineWidth, PlanarFigureControlPointStyleProperty::Shape shape, const mitk::PlaneGeometry *objectGeometry, const mitk::PlaneGeometry *rendererGeometry, const mitk::BaseRenderer *renderer) { if (this->GetDataNode() != nullptr && this->GetDataNode()->GetDataInteractor().IsNull()) return; if (markerOpacity == 0 && lineOpacity == 0) return; mitk::Point2D displayPoint; this->TransformObjectToDisplay(point, displayPoint, objectGeometry, rendererGeometry, renderer); this->m_Context->GetPen()->SetColorF((double)markerColor[0], (double)markerColor[1], (double)markerColor[2], markerOpacity); this->m_Context->GetPen()->SetWidth(lineWidth); switch (shape) { case PlanarFigureControlPointStyleProperty::Square: default: { // Paint filled square if (markerOpacity > 0) { m_Context->DrawRect(displayPoint[0] - 4, displayPoint[1] - 4, 8, 8); } // Paint outline this->m_Context->GetPen()->SetColorF((double)lineColor[0], (double)lineColor[1], (double)lineColor[2], (double)lineOpacity); - + float* outline = new float[8]; outline[0] = displayPoint[0] - 4; outline[1] = displayPoint[1] - 4; outline[2] = outline[0]; outline[3] = displayPoint[1] + 4; outline[4] = displayPoint[0] + 4; outline[5] = outline[3]; outline[6] = outline[4]; outline[7] = outline[1]; m_Context->DrawLines(outline, 4); break; } case PlanarFigureControlPointStyleProperty::Circle: { // TODO: This code can not be reached using the properties provided in the GUI /*float radius = 4.0; if (markerOpacity > 0) { // Paint filled circle glBegin(GL_POLYGON); for (int angle = 0; angle < 8; ++angle) { float angleRad = angle * (float)3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos(angleRad); float y = displayPoint[1] + radius * (float)sin(angleRad); glVertex3f(x, y, PLANAR_OFFSET); } glEnd(); } // Paint outline glColor4f(lineColor[0], lineColor[1], lineColor[2], lineOpacity); glBegin(GL_LINE_LOOP); for (int angle = 0; angle < 8; ++angle) { float angleRad = angle * (float)3.14159 / 4.0; float x = displayPoint[0] + radius * (float)cos(angleRad); float y = displayPoint[1] + radius * (float)sin(angleRad); glVertex3f(x, y, PLANAR_OFFSET); } glEnd();*/ break; } } // end switch } void mitk::PlanarFigureMapper2D::InitializeDefaultPlanarFigureProperties() { m_IsSelected = false; m_IsHovering = false; m_DrawOutline = false; m_DrawQuantities = false; m_DrawShadow = false; m_DrawControlPoints = false; m_DrawName = true; m_DrawDashed = false; m_DrawHelperDashed = false; m_AnnotationsShadow = false; m_ShadowWidthFactor = 1.2; m_LineWidth = 1.0; m_OutlineWidth = 4.0; m_HelperlineWidth = 2.0; m_DevicePixelRatio = 1.0; m_ControlPointShape = PlanarFigureControlPointStyleProperty::Square; this->SetColorProperty(m_LineColor, PF_DEFAULT, 1.0, 1.0, 1.0); this->SetFloatProperty(m_LineOpacity, PF_DEFAULT, 1.0); this->SetColorProperty(m_OutlineColor, PF_DEFAULT, 0.0, 0.0, 1.0); this->SetFloatProperty(m_OutlineOpacity, PF_DEFAULT, 1.0); this->SetColorProperty(m_HelperlineColor, PF_DEFAULT, 0.4, 0.8, 0.2); this->SetFloatProperty(m_HelperlineOpacity, PF_DEFAULT, 0.4); this->SetColorProperty(m_MarkerlineColor, PF_DEFAULT, 1.0, 1.0, 1.0); this->SetFloatProperty(m_MarkerlineOpacity, PF_DEFAULT, 1.0); this->SetColorProperty(m_MarkerColor, PF_DEFAULT, 1.0, 1.0, 1.0); this->SetFloatProperty(m_MarkerOpacity, PF_DEFAULT, 0.0); this->SetColorProperty(m_AnnotationColor, PF_DEFAULT, 1.0, 1.0, 1.0); this->SetColorProperty(m_LineColor, PF_HOVER, 1.0, 0.7, 0.0); this->SetFloatProperty(m_LineOpacity, PF_HOVER, 1.0); this->SetColorProperty(m_OutlineColor, PF_HOVER, 0.0, 0.0, 1.0); this->SetFloatProperty(m_OutlineOpacity, PF_HOVER, 1.0); this->SetColorProperty(m_HelperlineColor, PF_HOVER, 0.4, 0.8, 0.2); this->SetFloatProperty(m_HelperlineOpacity, PF_HOVER, 0.4); this->SetColorProperty(m_MarkerlineColor, PF_HOVER, 1.0, 1.0, 1.0); this->SetFloatProperty(m_MarkerlineOpacity, PF_HOVER, 1.0); this->SetColorProperty(m_MarkerColor, PF_HOVER, 1.0, 0.6, 0.0); this->SetFloatProperty(m_MarkerOpacity, PF_HOVER, 0.2); this->SetColorProperty(m_AnnotationColor, PF_HOVER, 1.0, 0.7, 0.0); this->SetColorProperty(m_LineColor, PF_SELECTED, 1.0, 0.0, 0.0); this->SetFloatProperty(m_LineOpacity, PF_SELECTED, 1.0); this->SetColorProperty(m_OutlineColor, PF_SELECTED, 0.0, 0.0, 1.0); this->SetFloatProperty(m_OutlineOpacity, PF_SELECTED, 1.0); this->SetColorProperty(m_HelperlineColor, PF_SELECTED, 0.4, 0.8, 0.2); this->SetFloatProperty(m_HelperlineOpacity, PF_SELECTED, 0.4); this->SetColorProperty(m_MarkerlineColor, PF_SELECTED, 1.0, 1.0, 1.0); this->SetFloatProperty(m_MarkerlineOpacity, PF_SELECTED, 1.0); this->SetColorProperty(m_MarkerColor, PF_SELECTED, 1.0, 0.6, 0.0); this->SetFloatProperty(m_MarkerOpacity, PF_SELECTED, 1.0); this->SetColorProperty(m_AnnotationColor, PF_SELECTED, 1.0, 0.0, 0.0); } void mitk::PlanarFigureMapper2D::InitializePlanarFigurePropertiesFromDataNode(const mitk::DataNode *node) { if (node == nullptr) { return; } // if we have not added an observer for ModifiedEvents on the DataNode, // we add one now. if (!m_NodeModifiedObserverAdded) { itk::SimpleMemberCommand::Pointer nodeModifiedCommand = itk::SimpleMemberCommand::New(); nodeModifiedCommand->SetCallbackFunction(this, &mitk::PlanarFigureMapper2D::OnNodeModified); m_NodeModifiedObserverTag = node->AddObserver(itk::ModifiedEvent(), nodeModifiedCommand); m_NodeModifiedObserverAdded = true; } // If the DataNode has not been modified since the last execution of // this method, we do not run it now. if (!m_NodeModified) return; // Mark the current properties as unmodified m_NodeModified = false; // Get Global Opacity float globalOpacity = 1.0; node->GetFloatProperty("opacity", globalOpacity); node->GetBoolProperty("selected", m_IsSelected); node->GetBoolProperty("planarfigure.ishovering", m_IsHovering); node->GetBoolProperty("planarfigure.drawoutline", m_DrawOutline); node->GetBoolProperty("planarfigure.drawshadow", m_DrawShadow); node->GetBoolProperty("planarfigure.drawquantities", m_DrawQuantities); node->GetBoolProperty("planarfigure.drawcontrolpoints", m_DrawControlPoints); node->GetBoolProperty("planarfigure.drawname", m_DrawName); node->GetBoolProperty("planarfigure.drawdashed", m_DrawDashed); node->GetBoolProperty("planarfigure.helperline.drawdashed", m_DrawHelperDashed); node->GetFloatProperty("planarfigure.line.width", m_LineWidth); node->GetFloatProperty("planarfigure.shadow.widthmodifier", m_ShadowWidthFactor); node->GetFloatProperty("planarfigure.outline.width", m_OutlineWidth); node->GetFloatProperty("planarfigure.helperline.width", m_HelperlineWidth); node->GetFloatProperty("planarfigure.devicepixelratio", m_DevicePixelRatio); node->GetStringProperty("planarfigure.annotations.font.family", m_AnnotationFontFamily); node->GetBoolProperty("planarfigure.annotations.font.bold", m_DrawAnnotationBold); node->GetBoolProperty("planarfigure.annotations.font.italic", m_DrawAnnotationItalic); node->GetIntProperty("planarfigure.annotations.font.size", m_AnnotationSize); if (!node->GetBoolProperty("planarfigure.annotations.shadow", m_AnnotationsShadow)) { node->GetBoolProperty("planarfigure.drawshadow", m_AnnotationsShadow); } PlanarFigureControlPointStyleProperty::Pointer styleProperty = dynamic_cast(node->GetProperty("planarfigure.controlpointshape")); if (styleProperty.IsNotNull()) { m_ControlPointShape = styleProperty->GetShape(); } // Set default color and opacity // If property "planarfigure.default.*.color" exists, then use that color. Otherwise global "color" property is used. if (!node->GetColor(m_LineColor[PF_DEFAULT], nullptr, "planarfigure.default.line.color")) { node->GetColor(m_LineColor[PF_DEFAULT], nullptr, "color"); } node->GetFloatProperty("planarfigure.default.line.opacity", m_LineOpacity[PF_DEFAULT]); if (!node->GetColor(m_OutlineColor[PF_DEFAULT], nullptr, "planarfigure.default.outline.color")) { node->GetColor(m_OutlineColor[PF_DEFAULT], nullptr, "color"); } node->GetFloatProperty("planarfigure.default.outline.opacity", m_OutlineOpacity[PF_DEFAULT]); if (!node->GetColor(m_HelperlineColor[PF_DEFAULT], nullptr, "planarfigure.default.helperline.color")) { node->GetColor(m_HelperlineColor[PF_DEFAULT], nullptr, "color"); } node->GetFloatProperty("planarfigure.default.helperline.opacity", m_HelperlineOpacity[PF_DEFAULT]); node->GetColor(m_MarkerlineColor[PF_DEFAULT], nullptr, "planarfigure.default.markerline.color"); node->GetFloatProperty("planarfigure.default.markerline.opacity", m_MarkerlineOpacity[PF_DEFAULT]); node->GetColor(m_MarkerColor[PF_DEFAULT], nullptr, "planarfigure.default.marker.color"); node->GetFloatProperty("planarfigure.default.marker.opacity", m_MarkerOpacity[PF_DEFAULT]); if (!node->GetColor(m_AnnotationColor[PF_DEFAULT], nullptr, "planarfigure.default.annotation.color")) { if (!node->GetColor(m_AnnotationColor[PF_DEFAULT], nullptr, "planarfigure.default.line.color")) { node->GetColor(m_AnnotationColor[PF_DEFAULT], nullptr, "color"); } } // Set hover color and opacity node->GetColor(m_LineColor[PF_HOVER], nullptr, "planarfigure.hover.line.color"); node->GetFloatProperty("planarfigure.hover.line.opacity", m_LineOpacity[PF_HOVER]); node->GetColor(m_OutlineColor[PF_HOVER], nullptr, "planarfigure.hover.outline.color"); node->GetFloatProperty("planarfigure.hover.outline.opacity", m_OutlineOpacity[PF_HOVER]); node->GetColor(m_HelperlineColor[PF_HOVER], nullptr, "planarfigure.hover.helperline.color"); node->GetFloatProperty("planarfigure.hover.helperline.opacity", m_HelperlineOpacity[PF_HOVER]); node->GetColor(m_MarkerlineColor[PF_HOVER], nullptr, "planarfigure.hover.markerline.color"); node->GetFloatProperty("planarfigure.hover.markerline.opacity", m_MarkerlineOpacity[PF_HOVER]); node->GetColor(m_MarkerColor[PF_HOVER], nullptr, "planarfigure.hover.marker.color"); node->GetFloatProperty("planarfigure.hover.marker.opacity", m_MarkerOpacity[PF_HOVER]); if (!node->GetColor(m_AnnotationColor[PF_HOVER], nullptr, "planarfigure.hover.annotation.color")) { if (!node->GetColor(m_AnnotationColor[PF_HOVER], nullptr, "planarfigure.hover.line.color")) { node->GetColor(m_AnnotationColor[PF_HOVER], nullptr, "color"); } } // Set selected color and opacity node->GetColor(m_LineColor[PF_SELECTED], nullptr, "planarfigure.selected.line.color"); node->GetFloatProperty("planarfigure.selected.line.opacity", m_LineOpacity[PF_SELECTED]); node->GetColor(m_OutlineColor[PF_SELECTED], nullptr, "planarfigure.selected.outline.color"); node->GetFloatProperty("planarfigure.selected.outline.opacity", m_OutlineOpacity[PF_SELECTED]); node->GetColor(m_HelperlineColor[PF_SELECTED], nullptr, "planarfigure.selected.helperline.color"); node->GetFloatProperty("planarfigure.selected.helperline.opacity", m_HelperlineOpacity[PF_SELECTED]); node->GetColor(m_MarkerlineColor[PF_SELECTED], nullptr, "planarfigure.selected.markerline.color"); node->GetFloatProperty("planarfigure.selected.markerline.opacity", m_MarkerlineOpacity[PF_SELECTED]); node->GetColor(m_MarkerColor[PF_SELECTED], nullptr, "planarfigure.selected.marker.color"); node->GetFloatProperty("planarfigure.selected.marker.opacity", m_MarkerOpacity[PF_SELECTED]); if (!node->GetColor(m_AnnotationColor[PF_SELECTED], nullptr, "planarfigure.selected.annotation.color")) { if (!node->GetColor(m_AnnotationColor[PF_SELECTED], nullptr, "planarfigure.selected.line.color")) { node->GetColor(m_AnnotationColor[PF_SELECTED], nullptr, "color"); } } // adapt opacity values to global "opacity" property for (unsigned int i = 0; i < PF_COUNT; ++i) { m_LineOpacity[i] *= globalOpacity; m_OutlineOpacity[i] *= globalOpacity; m_HelperlineOpacity[i] *= globalOpacity; m_MarkerlineOpacity[i] *= globalOpacity; m_MarkerOpacity[i] *= globalOpacity; } } void mitk::PlanarFigureMapper2D::OnNodeModified() { m_NodeModified = true; } void mitk::PlanarFigureMapper2D::SetDefaultProperties(mitk::DataNode *node, mitk::BaseRenderer *renderer, bool overwrite) { node->AddProperty("visible", mitk::BoolProperty::New(true), renderer, overwrite); // node->SetProperty("planarfigure.iseditable",mitk::BoolProperty::New(true)); node->AddProperty("planarfigure.isextendable", mitk::BoolProperty::New(false)); // node->AddProperty( "planarfigure.ishovering", mitk::BoolProperty::New(true) ); node->AddProperty("planarfigure.drawoutline", mitk::BoolProperty::New(false)); // node->AddProperty( "planarfigure.drawquantities", mitk::BoolProperty::New(true) ); node->AddProperty("planarfigure.drawshadow", mitk::BoolProperty::New(true)); node->AddProperty("planarfigure.drawcontrolpoints", mitk::BoolProperty::New(true)); node->AddProperty("planarfigure.drawname", mitk::BoolProperty::New(true)); node->AddProperty("planarfigure.drawdashed", mitk::BoolProperty::New(false)); node->AddProperty("planarfigure.helperline.drawdashed", mitk::BoolProperty::New(false)); node->AddProperty("planarfigure.annotations.font.family", mitk::StringProperty::New("Arial")); node->AddProperty("planarfigure.annotations.font.bold", mitk::BoolProperty::New(false)); node->AddProperty("planarfigure.annotations.font.italic", mitk::BoolProperty::New(false)); node->AddProperty("planarfigure.annotations.font.size", mitk::IntProperty::New(12)); node->AddProperty("planarfigure.line.width", mitk::FloatProperty::New(2.0)); node->AddProperty("planarfigure.shadow.widthmodifier", mitk::FloatProperty::New(2.0)); node->AddProperty("planarfigure.outline.width", mitk::FloatProperty::New(2.0)); node->AddProperty("planarfigure.helperline.width", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.default.line.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.default.outline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.default.helperline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.default.markerline.color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); node->AddProperty("planarfigure.default.markerline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.default.marker.color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); node->AddProperty("planarfigure.default.marker.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.hover.line.color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); node->AddProperty("planarfigure.hover.line.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.hover.outline.color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); node->AddProperty("planarfigure.hover.outline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.hover.helperline.color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); node->AddProperty("planarfigure.hover.helperline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.hover.markerline.color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); node->AddProperty("planarfigure.hover.markerline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.hover.marker.color", mitk::ColorProperty::New(0.0, 1.0, 0.0)); node->AddProperty("planarfigure.hover.marker.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.selected.line.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); node->AddProperty("planarfigure.selected.line.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.selected.outline.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); node->AddProperty("planarfigure.selected.outline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.selected.helperline.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); node->AddProperty("planarfigure.selected.helperline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.selected.markerline.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); node->AddProperty("planarfigure.selected.markerline.opacity", mitk::FloatProperty::New(1.0)); node->AddProperty("planarfigure.selected.marker.color", mitk::ColorProperty::New(1.0, 0.0, 0.0)); node->AddProperty("planarfigure.selected.marker.opacity", mitk::FloatProperty::New(1.0)); } void mitk::PlanarFigureMapper2D::RenderControlPoints(const mitk::PlanarFigure *planarFigure, const PlanarFigureDisplayMode lineDisplayMode, const mitk::PlaneGeometry *planarFigurePlaneGeometry, const mitk::PlaneGeometry *rendererPlaneGeometry, mitk::BaseRenderer *renderer) { bool isEditable = true; m_DataNode->GetBoolProperty("planarfigure.iseditable", isEditable); PlanarFigureDisplayMode pointDisplayMode = PF_DEFAULT; const unsigned int selectedControlPointsIdx = (unsigned int)planarFigure->GetSelectedControlPoint(); const unsigned int numberOfControlPoints = planarFigure->GetNumberOfControlPoints(); // Draw markers at control points (selected control point will be colored) for (unsigned int i = 0; i < numberOfControlPoints; ++i) { // Only if planar figure is marked as editable: display markers (control points) in a // different style if mouse is over them or they are selected if (isEditable) { if (i == selectedControlPointsIdx) { pointDisplayMode = PF_SELECTED; } else if (m_IsHovering && isEditable) { pointDisplayMode = PF_HOVER; } } if (m_MarkerOpacity[pointDisplayMode] == 0 && m_MarkerlineOpacity[pointDisplayMode] == 0) { continue; } if (m_DrawOutline) { // draw outlines for markers as well // linewidth for the contour is only half, as full width looks // much too thick! this->DrawMarker(planarFigure->GetControlPoint(i), m_OutlineColor[lineDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_OutlineColor[lineDisplayMode], m_MarkerOpacity[pointDisplayMode], m_OutlineWidth / 2, m_ControlPointShape, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } this->DrawMarker(planarFigure->GetControlPoint(i), m_MarkerlineColor[pointDisplayMode], m_MarkerlineOpacity[pointDisplayMode], m_MarkerColor[pointDisplayMode], m_MarkerOpacity[pointDisplayMode], m_LineWidth, m_ControlPointShape, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } if (planarFigure->IsPreviewControlPointVisible()) { this->DrawMarker(planarFigure->GetPreviewControlPoint(), m_MarkerlineColor[PF_HOVER], m_MarkerlineOpacity[PF_HOVER], m_MarkerColor[PF_HOVER], m_MarkerOpacity[PF_HOVER], m_LineWidth, m_ControlPointShape, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } } -void mitk::PlanarFigureMapper2D::RenderAnnotations(mitk::BaseRenderer *renderer, +void mitk::PlanarFigureMapper2D::RenderAnnotations(mitk::BaseRenderer */*renderer*/, const std::string name, const mitk::Point2D anchorPoint, float globalOpacity, const PlanarFigureDisplayMode lineDisplayMode, double &annotationOffset) { if (anchorPoint[0] < mitk::eps || anchorPoint[1] < mitk::eps) { return; } - m_AnnotationAnnotation->SetText(name); - m_AnnotationAnnotation->SetColor(m_AnnotationColor[lineDisplayMode][0], - m_AnnotationColor[lineDisplayMode][1], - m_AnnotationColor[lineDisplayMode][2]); - m_AnnotationAnnotation->SetOpacity(globalOpacity); - m_AnnotationAnnotation->SetFontSize(m_AnnotationSize * m_DevicePixelRatio); - m_AnnotationAnnotation->SetBoolProperty("drawShadow", m_AnnotationsShadow); - m_AnnotationAnnotation->SetVisibility(true); - m_AnnotationAnnotation->SetStringProperty("font.family", m_AnnotationFontFamily); - m_AnnotationAnnotation->SetBoolProperty("font.bold", m_DrawAnnotationBold); - m_AnnotationAnnotation->SetBoolProperty("font.italic", m_DrawAnnotationItalic); + vtkTextProperty* textProp = vtkTextProperty::New(); + textProp->SetFontSize(m_AnnotationSize); + textProp->SetFontFamilyAsString(m_AnnotationFontFamily.c_str()); + textProp->SetJustificationToLeft(); + textProp->SetOpacity(globalOpacity); + textProp->SetShadow(0); + textProp->SetBold(m_DrawAnnotationBold); + textProp->SetItalic(m_DrawAnnotationItalic); mitk::Point2D offset; offset.Fill(5); mitk::Point2D scaledAnchorPoint; scaledAnchorPoint[0] = anchorPoint[0] * m_DevicePixelRatio; scaledAnchorPoint[1] = anchorPoint[1] * m_DevicePixelRatio; offset[0] = offset[0] * m_DevicePixelRatio; offset[1] = offset[1] * m_DevicePixelRatio; - m_AnnotationAnnotation->SetPosition2D(scaledAnchorPoint); - m_AnnotationAnnotation->SetOffsetVector(offset); - m_AnnotationAnnotation->Update(renderer); - m_AnnotationAnnotation->Paint(renderer); + if(m_DrawShadow) + { + textProp->SetColor(0.0,0.0,0.0); + this->m_Context->ApplyTextProp(textProp); + this->m_Context->DrawString(scaledAnchorPoint[0]+offset[0]+1, scaledAnchorPoint[1]+offset[1]-1, name.c_str()); + } + textProp->SetColor(m_AnnotationColor[lineDisplayMode][0], + m_AnnotationColor[lineDisplayMode][1], + m_AnnotationColor[lineDisplayMode][2]); + this->m_Context->ApplyTextProp(textProp); + this->m_Context->DrawString(scaledAnchorPoint[0]+offset[0], scaledAnchorPoint[1]+offset[1], name.c_str()); + annotationOffset -= 15.0; // annotationOffset -= m_AnnotationAnnotation->GetBoundsOnDisplay( renderer ).Size[1]; + textProp->Delete(); } void mitk::PlanarFigureMapper2D::RenderQuantities(const mitk::PlanarFigure *planarFigure, - mitk::BaseRenderer *renderer, + mitk::BaseRenderer */*renderer*/, const mitk::Point2D anchorPoint, double &annotationOffset, float globalOpacity, const PlanarFigureDisplayMode lineDisplayMode) { if (anchorPoint[0] < mitk::eps || anchorPoint[1] < mitk::eps) { return; } std::stringstream quantityString; quantityString.setf(ios::fixed, ios::floatfield); quantityString.precision(1); bool firstActiveFeature = true; for (unsigned int i = 0; i < planarFigure->GetNumberOfFeatures(); ++i) { if (planarFigure->IsFeatureActive(i) && planarFigure->IsFeatureVisible(i)) { if (!firstActiveFeature) { quantityString << " x "; } quantityString << planarFigure->GetQuantity(i) << " "; quantityString << planarFigure->GetFeatureUnit(i); firstActiveFeature = false; } } - m_QuantityAnnotation->SetColor(m_AnnotationColor[lineDisplayMode][0], - m_AnnotationColor[lineDisplayMode][1], - m_AnnotationColor[lineDisplayMode][2]); + vtkTextProperty* textProp = vtkTextProperty::New(); + textProp->SetFontSize(m_AnnotationSize); + textProp->SetFontFamilyAsString(m_AnnotationFontFamily.c_str()); + textProp->SetJustificationToLeft(); + textProp->SetOpacity(globalOpacity); + textProp->SetShadow(0); + textProp->SetBold(m_DrawAnnotationBold); + textProp->SetItalic(m_DrawAnnotationItalic); - m_QuantityAnnotation->SetOpacity(globalOpacity); - m_QuantityAnnotation->SetFontSize(m_AnnotationSize * m_DevicePixelRatio); - m_QuantityAnnotation->SetBoolProperty("drawShadow", m_DrawShadow); - m_QuantityAnnotation->SetVisibility(true); - - m_AnnotationAnnotation->SetStringProperty("font.family", m_AnnotationFontFamily); - m_AnnotationAnnotation->SetBoolProperty("font.bold", m_DrawAnnotationBold); - m_AnnotationAnnotation->SetBoolProperty("font.italic", m_DrawAnnotationItalic); - - m_QuantityAnnotation->SetText(quantityString.str().c_str()); mitk::Point2D offset; offset.Fill(5); - offset[1] += annotationOffset; mitk::Point2D scaledAnchorPoint; scaledAnchorPoint[0] = anchorPoint[0] * m_DevicePixelRatio; scaledAnchorPoint[1] = anchorPoint[1] * m_DevicePixelRatio; offset[0] = offset[0] * m_DevicePixelRatio; offset[1] = offset[1] * m_DevicePixelRatio; - m_QuantityAnnotation->SetPosition2D(scaledAnchorPoint); - m_QuantityAnnotation->SetOffsetVector(offset); - m_QuantityAnnotation->Update(renderer); - m_QuantityAnnotation->Paint(renderer); - // annotationOffset -= m_QuantityAnnotation->GetBoundsOnDisplay( renderer ).Size[1]; + if(m_DrawShadow) + { + textProp->SetColor(0,0,0); + this->m_Context->ApplyTextProp(textProp); + this->m_Context->DrawString(scaledAnchorPoint[0]+offset[0]+1, scaledAnchorPoint[1]+offset[1]-1, quantityString.str().c_str()); + } + textProp->SetColor(m_AnnotationColor[lineDisplayMode][0], + m_AnnotationColor[lineDisplayMode][1], + m_AnnotationColor[lineDisplayMode][2]); + this->m_Context->ApplyTextProp(textProp); + this->m_Context->DrawString(scaledAnchorPoint[0]+offset[0], scaledAnchorPoint[1]+offset[1], quantityString.str().c_str()); + annotationOffset -= 15.0; + // annotationOffset -= m_AnnotationAnnotation->GetBoundsOnDisplay( renderer ).Size[1]; + textProp->Delete(); } void mitk::PlanarFigureMapper2D::RenderLines(const PlanarFigureDisplayMode lineDisplayMode, mitk::PlanarFigure *planarFigure, mitk::Point2D &anchorPoint, const mitk::PlaneGeometry *planarFigurePlaneGeometry, const mitk::PlaneGeometry *rendererPlaneGeometry, const mitk::BaseRenderer *renderer) { // If we want to draw an outline, we do it here if (m_DrawOutline) { const float *color = m_OutlineColor[lineDisplayMode]; const float opacity = m_OutlineOpacity[lineDisplayMode]; // convert to a float array that also contains opacity, faster GL float *colorVector = new float[4]; colorVector[0] = color[0]; colorVector[1] = color[1]; colorVector[2] = color[2]; colorVector[3] = opacity; // set the color and opacity here as it is common for all outlines this->m_Context->GetPen()->SetColorF((double)color[0], (double)color[1], (double)color[2], opacity); this->m_Context->GetPen()->SetWidth(m_OutlineWidth); if (m_DrawDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw the outline for all polylines if requested this->DrawMainLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); this->m_Context->GetPen()->SetWidth(m_HelperlineWidth); if (m_DrawHelperDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw the outline for all helper objects if requested this->DrawHelperLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); // cleanup delete[] colorVector; } // If we want to draw a shadow, we do it here if (m_DrawShadow) { // determine the shadow opacity const float opacity = m_OutlineOpacity[lineDisplayMode]; float shadowOpacity = 0.0f; if (opacity > 0.2f) shadowOpacity = opacity - 0.2f; // convert to a float array that also contains opacity, faster GL float *shadow = new float[4]; shadow[0] = 0; shadow[1] = 0; shadow[2] = 0; shadow[3] = shadowOpacity; // set the color and opacity here as it is common for all shadows this->m_Context->GetPen()->SetColorF(0, 0, 0, shadowOpacity); this->m_Context->GetPen()->SetWidth(m_OutlineWidth * m_ShadowWidthFactor); if (m_DrawDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw the outline for all polylines if requested this->DrawMainLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); this->m_Context->GetPen()->SetWidth(m_HelperlineWidth); if (m_DrawHelperDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw the outline for all helper objects if requested this->DrawHelperLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); // cleanup delete[] shadow; } // set this in brackets to avoid duplicate variables in the same scope { const float *color = m_LineColor[lineDisplayMode]; const float opacity = m_LineOpacity[lineDisplayMode]; // set the color and opacity here as it is common for all mainlines this->m_Context->GetPen()->SetColorF((double)color[0], (double)color[1], (double)color[2], (double)opacity); this->m_Context->GetPen()->SetWidth(m_LineWidth); if (m_DrawDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw the main line for all polylines this->DrawMainLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); const float *helperColor = m_HelperlineColor[lineDisplayMode]; const float helperOpacity = m_HelperlineOpacity[lineDisplayMode]; // we only set the color for the helperlines as the linewidth is unchanged this->m_Context->GetPen()->SetColorF((double)helperColor[0], (double)helperColor[1], (double)helperColor[2], (double)helperOpacity); this->m_Context->GetPen()->SetWidth(m_HelperlineWidth); if (m_DrawHelperDashed) this->m_Context->GetPen()->SetLineType(vtkPen::DASH_LINE); else this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); // Draw helper objects this->DrawHelperLines(planarFigure, anchorPoint, planarFigurePlaneGeometry, rendererPlaneGeometry, renderer); } if (m_DrawDashed || m_DrawHelperDashed) this->m_Context->GetPen()->SetLineType(vtkPen::SOLID_LINE); } diff --git a/Modules/Segmentation/Rendering/mitkContourMapper2D.cpp b/Modules/Segmentation/Rendering/mitkContourMapper2D.cpp index 23355f59bd..dad9e3f02b 100644 --- a/Modules/Segmentation/Rendering/mitkContourMapper2D.cpp +++ b/Modules/Segmentation/Rendering/mitkContourMapper2D.cpp @@ -1,133 +1,133 @@ /*=================================================================== 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 "mitkContourMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "mitkContour.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include "vtk_glew.h" mitk::ContourMapper2D::ContourMapper2D() { } mitk::ContourMapper2D::~ContourMapper2D() { } void mitk::ContourMapper2D::ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor * /*actor*/) { float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // check for color prop and use it for rendering if it exists GetDataNode()->GetColor(rgba, renderer, "color"); // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(rgba[3], renderer, "opacity"); glColor4fv(rgba); } -void mitk::ContourMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) +void mitk::ContourMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType /*type*/) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) return; //// @FIXME: Logik fuer update bool updateNeccesary = true; if (updateNeccesary) { mitk::Contour::Pointer input = const_cast(this->GetInput()); // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); vtkLinearTransform *transform = GetDataNode()->GetVtkTransform(); // Contour::OutputType point; Contour::BoundingBoxType::PointType point; mitk::Point3D p, projected_p; float vtkp[3]; float lineWidth = 3.0; if (dynamic_cast(this->GetDataNode()->GetProperty("Width")) != nullptr) lineWidth = dynamic_cast(this->GetDataNode()->GetProperty("Width"))->GetValue(); glLineWidth(lineWidth); if (input->GetClosed()) { glBegin(GL_LINE_LOOP); } else { glBegin(GL_LINE_STRIP); } // Contour::InputType end = input->GetContourPath()->EndOfInput(); // if (end > 50000) end = 0; mitk::Contour::PointsContainerPointer points = input->GetPoints(); mitk::Contour::PointsContainerIterator pointsIt = points->Begin(); while (pointsIt != points->End()) { // while ( idx != end ) //{ // point = input->GetContourPath()->Evaluate(idx); point = pointsIt.Value(); itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); bool projectmode = false; GetDataNode()->GetVisibility(projectmode, renderer, "project"); bool drawit = false; if (projectmode) drawit = true; else { Vector3D diff = p - projected_p; if (diff.GetSquaredNorm() < 1.0) drawit = true; } if (drawit) { Point2D pt2d, tmp; renderer->WorldToDisplay(p, pt2d); glVertex2f(pt2d[0], pt2d[1]); } pointsIt++; // idx += 1; } glEnd(); glLineWidth(1.0); } } const mitk::Contour *mitk::ContourMapper2D::GetInput(void) { return static_cast(GetDataNode()->GetData()); } diff --git a/Modules/Segmentation/Rendering/mitkContourSetMapper2D.cpp b/Modules/Segmentation/Rendering/mitkContourSetMapper2D.cpp index 0d860995fe..cc5beacbfa 100644 --- a/Modules/Segmentation/Rendering/mitkContourSetMapper2D.cpp +++ b/Modules/Segmentation/Rendering/mitkContourSetMapper2D.cpp @@ -1,133 +1,133 @@ /*=================================================================== 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 "mitkContourSetMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkColorProperty.h" #include "mitkContourSet.h" #include "mitkPlaneGeometry.h" #include "mitkProperties.h" #include #include "mitkGL.h" mitk::ContourSetMapper2D::ContourSetMapper2D() { } mitk::ContourSetMapper2D::~ContourSetMapper2D() { } void mitk::ContourSetMapper2D::ApplyColorAndOpacityProperties(mitk::BaseRenderer *renderer, vtkActor * /*actor*/) { float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // check for color prop and use it for rendering if it exists GetDataNode()->GetColor(rgba, renderer, "color"); // check for opacity prop and use it for rendering if it exists GetDataNode()->GetOpacity(rgba[3], renderer, "opacity"); glColor4fv(rgba); } -void mitk::ContourSetMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType type) +void mitk::ContourSetMapper2D::MitkRender(mitk::BaseRenderer *renderer, mitk::VtkPropRenderer::RenderType /*type*/) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if (!visible) return; //// @FIXME: Logik fuer update bool updateNeccesary = true; if (updateNeccesary) { // apply color and opacity read from the PropertyList ApplyColorAndOpacityProperties(renderer); mitk::ContourSet::Pointer input = const_cast(this->GetInput()); mitk::ContourSet::ContourVectorType contourVec = input->GetContours(); mitk::ContourSet::ContourIterator contourIt = contourVec.begin(); while (contourIt != contourVec.end()) { mitk::Contour::Pointer nextContour = (mitk::Contour::Pointer)(*contourIt).second; vtkLinearTransform *transform = GetDataNode()->GetVtkTransform(); // Contour::OutputType point; Contour::BoundingBoxType::PointType point; mitk::Point3D p, projected_p; float vtkp[3]; glLineWidth(nextContour->GetWidth()); if (nextContour->GetClosed()) { glBegin(GL_LINE_LOOP); } else { glBegin(GL_LINE_STRIP); } // float rgba[4]={1.0f,1.0f,1.0f,1.0f}; // if ( nextContour->GetSelected() ) //{ // rgba[0] = 1.0; // rgba[1] = 0.0; // rgba[2] = 0.0; //} // glColor4fv(rgba); mitk::Contour::PointsContainerPointer points = nextContour->GetPoints(); mitk::Contour::PointsContainerIterator pointsIt = points->Begin(); while (pointsIt != points->End()) { point = pointsIt.Value(); itk2vtk(point, vtkp); transform->TransformPoint(vtkp, vtkp); vtk2itk(vtkp, p); renderer->GetCurrentWorldPlaneGeometry()->Project(p, projected_p); Vector3D diff = p - projected_p; if (diff.GetSquaredNorm() < 1.0) { Point2D pt2d, tmp; renderer->WorldToDisplay(p, pt2d); glVertex2f(pt2d[0], pt2d[1]); } pointsIt++; // idx += 1; } glEnd(); glLineWidth(1.0); contourIt++; } } } const mitk::ContourSet *mitk::ContourSetMapper2D::GetInput(void) { return static_cast(GetDataNode()->GetData()); } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp index 7264029b09..93272eced5 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkImageStatisticsView.cpp @@ -1,1333 +1,1333 @@ /*=================================================================== 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 "QmitkImageStatisticsView.h" // Qt includes #include #include #include // berry includes #include // mitk includes #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateOr.h" #include "mitkPlanarFigureInteractor.h" #include "mitkImageTimeSelector.h" #include #include // itk includes #include "itksys/SystemTools.hxx" #include #include "itkImageRegionConstIteratorWithIndex.h" #include //blueberry includes #include #include const std::string QmitkImageStatisticsView::VIEW_ID = "org.mitk.views.imagestatistics"; const int QmitkImageStatisticsView::STAT_TABLE_BASE_HEIGHT = 180; QmitkImageStatisticsView::QmitkImageStatisticsView(QObject* /*parent*/, const char* /*name*/) : m_Controls( nullptr ), m_TimeStepperAdapter( nullptr ), m_SelectedImage( nullptr ), m_SelectedImageMask( nullptr ), m_SelectedPlanarFigure( nullptr ), m_ImageObserverTag( -1 ), m_ImageMaskObserverTag( -1 ), m_PlanarFigureObserverTag( -1 ), m_TimeObserverTag( -1 ), m_CurrentStatisticsValid( false ), m_StatisticsUpdatePending( false ), m_DataNodeSelectionChanged ( false ), m_Visible(false) { this->m_CalculationThread = new QmitkImageStatisticsCalculationThread; } QmitkImageStatisticsView::~QmitkImageStatisticsView() { if ( m_SelectedImage != nullptr ) m_SelectedImage->RemoveObserver( m_ImageObserverTag ); if ( m_SelectedImageMask != nullptr ) m_SelectedImageMask->RemoveObserver( m_ImageMaskObserverTag ); if ( m_SelectedPlanarFigure != nullptr ) m_SelectedPlanarFigure->RemoveObserver( m_PlanarFigureObserverTag ); while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } delete this->m_CalculationThread; } void QmitkImageStatisticsView::CreateQtPartControl(QWidget *parent) { if (m_Controls == nullptr) { m_Controls = new Ui::QmitkImageStatisticsViewControls; m_Controls->setupUi(parent); CreateConnections(); m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_Controls->m_BinSizeFrame->setEnabled(false); } } void QmitkImageStatisticsView::OnPageSuccessfullyLoaded() { berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, ""); if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss") { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::darkstyle); } else { this->m_Controls->m_JSHistogram->SetTheme(QmitkChartWidget::ChartStyle::defaultstyle); } } void QmitkImageStatisticsView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(this->m_Controls->m_ButtonCopyHistogramToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardHistogramButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_ButtonCopyStatisticsToClipboard), SIGNAL(clicked()),(QObject*) this, SLOT(OnClipboardStatisticsButtonClicked()) ); connect( (QObject*)(this->m_Controls->m_IgnoreZerosCheckbox), SIGNAL(clicked()),(QObject*) this, SLOT(OnIgnoreZerosCheckboxClicked()) ); connect( (QObject*) this->m_CalculationThread, SIGNAL(finished()),this, SLOT( OnThreadedStatisticsCalculationEnds()),Qt::QueuedConnection); connect( (QObject*) this, SIGNAL(StatisticsUpdate()),this, SLOT( RequestStatisticsUpdate()), Qt::QueuedConnection); connect( (QObject*) this->m_Controls->m_StatisticsTable, SIGNAL(cellDoubleClicked(int,int)),this, SLOT( JumpToCoordinates(int,int)) ); connect((QObject*)(this->m_Controls->m_barRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnBarRadioButtonSelected())); connect((QObject*)(this->m_Controls->m_lineRadioButton), SIGNAL(clicked()), (QObject*)(this), SLOT(OnLineRadioButtonSelected())); connect( (QObject*) (this->m_Controls->m_HistogramBinSizeSpinbox), SIGNAL(editingFinished()), this, SLOT(OnHistogramBinSizeBoxValueChanged())); connect((QObject*)(this->m_Controls->m_UseDefaultBinSizeBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnDefaultBinSizeBoxChanged())); connect((QObject*)(this->m_Controls->m_ShowSubchartCheckBox), SIGNAL(clicked()), (QObject*) this, SLOT(OnShowSubchartBoxChanged())); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); } } void QmitkImageStatisticsView::OnDefaultBinSizeBoxChanged() { m_Controls->m_BinSizeFrame->setEnabled(!m_Controls->m_UseDefaultBinSizeBox->isChecked()); if (m_CalculationThread != nullptr){ m_Controls->m_HistogramBinSizeSpinbox->setValue(m_CalculationThread->GetHistogramBinSize()); m_CalculationThread->SetUseDefaultNBins(m_Controls->m_UseDefaultBinSizeBox->isChecked()); } this->UpdateStatistics(); } void QmitkImageStatisticsView::OnShowSubchartBoxChanged() { bool showSubchart = this->m_Controls->m_ShowSubchartCheckBox->isChecked(); this->m_Controls->m_JSHistogram->Reload(showSubchart); } void QmitkImageStatisticsView::OnBarRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeAndReload(QmitkChartWidget::ChartType::bar); } void QmitkImageStatisticsView::OnLineRadioButtonSelected() { this->m_Controls->m_JSHistogram->SetChartTypeAndReload(QmitkChartWidget::ChartType::line); } void QmitkImageStatisticsView::PartClosed(const berry::IWorkbenchPartReference::Pointer& ) { } void QmitkImageStatisticsView::OnTimeChanged(const itk::EventObject& e) { if (this->m_SelectedDataNodes.isEmpty() || this->m_SelectedImage == nullptr) return; const mitk::SliceNavigationController::GeometryTimeEvent* timeEvent = dynamic_cast(&e); assert(timeEvent != nullptr); int timestep = timeEvent->GetPos(); if (this->m_SelectedImage->GetTimeSteps() > 1) { for (int x = 0; x < this->m_Controls->m_StatisticsTable->columnCount(); x++) { for (int y = 0; y < this->m_Controls->m_StatisticsTable->rowCount(); y++) { QTableWidgetItem* item = this->m_Controls->m_StatisticsTable->item(y, x); if (item == nullptr) break; if (x == timestep) { item->setBackgroundColor(Qt::yellow); } else { if (y % 2 == 0) item->setBackground(this->m_Controls->m_StatisticsTable->palette().base()); else item->setBackground(this->m_Controls->m_StatisticsTable->palette().alternateBase()); } } } this->m_Controls->m_StatisticsTable->viewport()->update(); } if ((this->m_SelectedImage->GetTimeSteps() == 1 && timestep == 0) || this->m_SelectedImage->GetTimeSteps() > 1) { // display histogram for selected timestep this->m_Controls->m_JSHistogram->Clear(); QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer histogram = (QmitkImageStatisticsCalculationThread::HistogramType::ConstPointer)this->m_CalculationThread->GetTimeStepHistogram(timestep); if (histogram.IsNotNull()) { bool closedFigure = this->m_CalculationThread->GetStatisticsUpdateSuccessFlag(); if ( closedFigure ) { this->m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram) ); if (this->m_Controls->m_lineRadioButton->isChecked()) { this->m_Controls->m_JSHistogram->SetChartType(QmitkChartWidget::ChartType::line); } else { this->m_Controls->m_JSHistogram->SetChartType(QmitkChartWidget::ChartType::bar); } this->m_Controls->m_JSHistogram->SetDataLabels({ m_Controls->m_SelectedFeatureImageLabel->text().toStdString() }); this->m_Controls->m_JSHistogram->SetXAxisLabel("Grey value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); this->m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); } } } } void QmitkImageStatisticsView::JumpToCoordinates(int row ,int col) { if(m_SelectedDataNodes.isEmpty()) { MITK_WARN("QmitkImageStatisticsView") << "No data node selected for statistics calculation." ; return; } mitk::Point3D world; if (row==5 && !m_WorldMinList.empty()) world = m_WorldMinList[col]; else if (row==4 && !m_WorldMaxList.empty()) world = m_WorldMaxList[col]; else return; mitk::IRenderWindowPart* part = this->GetRenderWindowPart(); if (part) { part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()->SelectSliceByPoint(world); part->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()->SelectSliceByPoint(world); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), col); part->GetQmitkRenderWindow("axial")->GetSliceNavigationController()->SetGeometryTime(timeEvent); } } void QmitkImageStatisticsView::OnIgnoreZerosCheckboxClicked() { emit StatisticsUpdate(); } void QmitkImageStatisticsView::OnClipboardHistogramButtonClicked() { if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != nullptr)) { const unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); typedef mitk::ImageStatisticsCalculator::HistogramType HistogramType; const HistogramType *histogram = this->m_CalculationThread->GetTimeStepHistogram(t).GetPointer(); QString clipboard( "Measurement \t Frequency\n" ); for ( HistogramType::ConstIterator it = histogram->Begin(); it != histogram->End(); ++it ) { if( m_Controls->m_HistogramBinSizeSpinbox->value() == 1.0) { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 0 ) .arg( it.GetFrequency() ); } else { clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( it.GetMeasurementVector()[0], 0, 'f', 2 ) .arg( it.GetFrequency() ); } } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); } // If a (non-closed) PlanarFigure is selected, display a line profile widget else if ( m_CurrentStatisticsValid && (m_SelectedPlanarFigure != nullptr )) { /*auto intensity = m_Controls->m_JSHistogram->GetFrequency(); auto pixel = m_Controls->m_JSHistogram->GetMeasurement(); QString clipboard( "Pixel \t Intensity\n" ); auto j = pixel.begin(); for (auto i = intensity.begin(); i < intensity.end(); i++) { assert(j != pixel.end()); clipboard = clipboard.append( "%L1 \t %L2\n" ) .arg( (*j).toString()) .arg( (*i).toString()); j++; } QApplication::clipboard()->setText( clipboard, QClipboard::Clipboard ); */ } else { QApplication::clipboard()->clear(); } } void QmitkImageStatisticsView::OnClipboardStatisticsButtonClicked() { QLocale tempLocal; QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates)); if ( m_CurrentStatisticsValid && !( m_SelectedPlanarFigure != nullptr)) { const std::vector &statistics = this->m_CalculationThread->GetStatisticsData(); // Set time borders for for loop ;) unsigned int startT, endT; if(this->m_Controls->m_CheckBox4dCompleteTable->checkState()==Qt::CheckState::Unchecked) { startT = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); endT = startT+1; } else { startT = 0; endT = statistics.size(); } QVector< QVector > statisticsTable; QStringList headline; // Create Headline headline << " " << "Mean" << "Median" << "StdDev" << "RMS" << "Max" << "Min" << "NumberOfVoxels" << "Skewness" << "Kurtosis" << "Uniformity" << "Entropy" << "MPP" << "UPP" << "V [mm³]"; for(int i=0;i row; row.append(headline.at(i)); statisticsTable.append(row); } // Fill Table for(unsigned int t=startT;tGetMean()) << QString::number(statistics[t]->GetMedian()) << QString::number(statistics[t]->GetStd()) << QString::number(statistics[t]->GetRMS()) << QString::number(statistics[t]->GetMax()) << QString::number(statistics[t]->GetMin()) << QString::number(statistics[t]->GetN()) << QString::number(statistics[t]->GetSkewness()) << QString::number(statistics[t]->GetKurtosis()) << QString::number(statistics[t]->GetUniformity()) << QString::number(statistics[t]->GetEntropy()) << QString::number(statistics[t]->GetMPP()) << QString::number(statistics[t]->GetUPP()) << QString::number(m_Controls->m_StatisticsTable->item(7, 0)->data(Qt::DisplayRole).toDouble()); for(int z=0;zsetText(clipboard, QClipboard::Clipboard); } else { QApplication::clipboard()->clear(); } QLocale::setDefault(tempLocal); } void QmitkImageStatisticsView::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes ) { if (this->m_Visible) { this->SelectionChanged( nodes ); } else { this->m_DataNodeSelectionChanged = true; } } void QmitkImageStatisticsView::SelectionChanged(const QList &selectedNodes) { //Clear Histogram if data node is deselected m_Controls->m_JSHistogram->Clear(); if( this->m_StatisticsUpdatePending ) { this->m_DataNodeSelectionChanged = true; return; // not ready for new data now! } if (selectedNodes.size() == this->m_SelectedDataNodes.size()) { int i = 0; for (; i < selectedNodes.size(); ++i) { if (selectedNodes.at(i) != this->m_SelectedDataNodes.at(i)) { break; } } // node selection did not change if (i == selectedNodes.size()) return; } //reset the feature image and image mask field m_Controls->m_SelectedFeatureImageLabel->setText("None"); m_Controls->m_SelectedMaskLabel->setText("None"); this->ReinitData(); if (selectedNodes.isEmpty()) { m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); m_Controls->groupBox->setEnabled(false); m_Controls->groupBox_3->setEnabled(false); } else { m_Controls->groupBox->setEnabled(true); m_Controls->groupBox_3->setEnabled(true); m_Controls->m_barRadioButton->setChecked(true); } if(selectedNodes.size() == 1 || selectedNodes.size() == 2) { bool isBinary = false; selectedNodes.value(0)->GetBoolProperty("binary",isBinary); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); isBinary |= isLabelSet->CheckNode(selectedNodes.value(0)); if(isBinary) { m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); } for (int i= 0; i< selectedNodes.size(); ++i) { this->m_SelectedDataNodes.push_back(selectedNodes.at(i)); } this->m_DataNodeSelectionChanged = false; this->m_Controls->m_ErrorMessageLabel->setText( "" ); this->m_Controls->m_ErrorMessageLabel->hide(); emit StatisticsUpdate(); } else { this->m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::ReinitData() { while( this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if(this->m_SelectedImage != nullptr) { this->m_SelectedImage->RemoveObserver( this->m_ImageObserverTag); this->m_SelectedImage = nullptr; } if(this->m_SelectedImageMask != nullptr) { this->m_SelectedImageMask->RemoveObserver( this->m_ImageMaskObserverTag); this->m_SelectedImageMask = nullptr; } if(this->m_SelectedPlanarFigure != nullptr) { this->m_SelectedPlanarFigure->RemoveObserver( this->m_PlanarFigureObserverTag); this->m_SelectedPlanarFigure = nullptr; } this->m_SelectedDataNodes.clear(); this->m_StatisticsUpdatePending = false; m_Controls->m_ErrorMessageLabel->setText( "" ); m_Controls->m_ErrorMessageLabel->hide(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); } void QmitkImageStatisticsView::OnThreadedStatisticsCalculationEnds() { std::stringstream message; message << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->hide(); this->WriteStatisticsToGUI(); } void QmitkImageStatisticsView::UpdateStatistics() { mitk::IRenderWindowPart* renderPart = this->GetRenderWindowPart(); if ( renderPart == nullptr ) { this->m_StatisticsUpdatePending = false; return; } m_WorldMinList.clear(); m_WorldMaxList.clear(); // classify selected nodes mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); mitk::NodePredicateDataType::Pointer isLabelSet = mitk::NodePredicateDataType::New("LabelSetImage"); mitk::NodePredicateOr::Pointer imagePredicate = mitk::NodePredicateOr::New(isImage, isLabelSet); std::string maskName; std::string maskType; std::string featureImageName; unsigned int maskDimension = 0; // reset data from last run ITKCommandType::Pointer changeListener = ITKCommandType::New(); changeListener->SetCallbackFunction( this, &QmitkImageStatisticsView::SelectedDataModified ); mitk::DataNode::Pointer planarFigureNode; for( int i= 0 ; i < this->m_SelectedDataNodes.size(); ++i) { mitk::PlanarFigure::Pointer planarFig = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); if( imagePredicate->CheckNode(this->m_SelectedDataNodes.at(i)) ) { bool isMask = false; this->m_SelectedDataNodes.at(i)->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(this->m_SelectedDataNodes.at(i)); if( this->m_SelectedImageMask == nullptr && isMask) { this->m_SelectedImageMask = dynamic_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageMaskObserverTag = this->m_SelectedImageMask->AddObserver(itk::ModifiedEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = m_SelectedImageMask->GetNameOfClass(); maskDimension = 3; } else if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(this->m_SelectedDataNodes.at(i)->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } featureImageName = this->m_SelectedDataNodes.at(i)->GetName(); } } else if (planarFig.IsNotNull()) { if(this->m_SelectedPlanarFigure == nullptr) { this->m_SelectedPlanarFigure = planarFig; this->m_PlanarFigureObserverTag = this->m_SelectedPlanarFigure->AddObserver(mitk::EndInteractionPlanarFigureEvent(), changeListener); maskName = this->m_SelectedDataNodes.at(i)->GetName(); maskType = this->m_SelectedPlanarFigure->GetNameOfClass(); maskDimension = 2; planarFigureNode = m_SelectedDataNodes.at(i); } } else { std::stringstream message; message << "" << "Invalid data node type!" << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); } } if(maskName == "") { maskName = "None"; maskType = ""; maskDimension = 0; } if(featureImageName == "") { featureImageName = "None"; } if (m_SelectedPlanarFigure != nullptr && m_SelectedImage == nullptr) { mitk::DataStorage::SetOfObjects::ConstPointer parentSet = this->GetDataStorage()->GetSources(planarFigureNode); for (unsigned int i=0; iSize(); i++) { mitk::DataNode::Pointer node = parentSet->ElementAt(i); if( imagePredicate->CheckNode(node) ) { bool isMask = false; node->GetPropertyValue("binary", isMask); isMask |= isLabelSet->CheckNode(node); if( !isMask ) { if(this->m_SelectedImage == nullptr) { this->m_SelectedImage = static_cast(node->GetData()); this->m_ImageObserverTag = this->m_SelectedImage->AddObserver(itk::ModifiedEvent(), changeListener); } } } } } unsigned int timeStep = renderPart->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_SelectedImage != nullptr && m_SelectedImage->IsInitialized()) { // Check if a the selected image is a multi-channel image. If yes, statistics // cannot be calculated currently. if ( m_SelectedImage->GetPixelType().GetNumberOfComponents() > 1 ) { std::stringstream message; message << "Multi-component images not supported."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_CurrentStatisticsValid = false; this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_UseDefaultBinSizeBox->setEnabled(true); m_Controls->m_InfoLabel->setText(""); return; } std::stringstream maskLabel; maskLabel << maskName; if ( maskDimension > 0 ) { maskLabel << " [" << maskDimension << "D " << maskType << "]"; } m_Controls->m_SelectedMaskLabel->setText( maskLabel.str().c_str() ); m_Controls->m_SelectedFeatureImageLabel->setText(featureImageName.c_str()); // check time step validity if(m_SelectedImage->GetDimension() <= 3 && timeStep > m_SelectedImage->GetDimension(3)-1) { timeStep = m_SelectedImage->GetDimension(3)-1; } // Add the used mask time step to the mask label so the user knows which mask time step was used // if the image time step is bigger than the total number of mask time steps (see // ImageStatisticsCalculator::ExtractImageAndMask) if (m_SelectedImageMask != nullptr) { unsigned int maskTimeStep = timeStep; if (maskTimeStep >= m_SelectedImageMask->GetTimeSteps()) { maskTimeStep = m_SelectedImageMask->GetTimeSteps() - 1; } m_Controls->m_SelectedMaskLabel->setText(m_Controls->m_SelectedMaskLabel->text() + QString(" (t=") + QString::number(maskTimeStep) + QString(")")); } // check if the segmentation mask is empty if (m_SelectedImageMask != NULL) { typedef itk::Image ItkImageType; typedef itk::ImageRegionConstIteratorWithIndex< ItkImageType > IteratorType; ItkImageType::Pointer itkImage; mitk::CastToItkImage( m_SelectedImageMask, itkImage ); bool empty = true; IteratorType it( itkImage, itkImage->GetLargestPossibleRegion() ); while ( !it.IsAtEnd() ) { ItkImageType::ValueType val = it.Get(); if ( val != 0 ) { empty = false; break; } ++it; } if ( empty ) { std::stringstream message; message << "Empty segmentation mask selected..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); return; } } //// initialize thread and trigger it this->m_CalculationThread->SetIgnoreZeroValueVoxel( m_Controls->m_IgnoreZerosCheckbox->isChecked() ); this->m_CalculationThread->Initialize( m_SelectedImage, m_SelectedImageMask, m_SelectedPlanarFigure ); this->m_CalculationThread->SetTimeStep( timeStep ); std::stringstream message; message << "Calculating statistics..."; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); try { // Compute statistics // this->m_CalculationThread->SetUseDefaultBinSize(m_Controls->m_UseDefaultBinSizeBox->isChecked()); this->m_CalculationThread->start(); } catch ( const mitk::Exception& e) { std::stringstream message; message << "" << e.GetDescription() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::runtime_error &e ) { // In case of exception, print error message on GUI std::stringstream message; message << "" << e.what() << ""; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } catch ( const std::exception &e ) { MITK_ERROR << "Caught exception: " << e.what(); // In case of exception, print error message on GUI std::stringstream message; message << "Error! Unequal Dimensions of Image and Segmentation. No recompute possible "; m_Controls->m_ErrorMessageLabel->setText( message.str().c_str() ); m_Controls->m_ErrorMessageLabel->show(); this->m_StatisticsUpdatePending = false; } } else { this->m_StatisticsUpdatePending = false; } } void QmitkImageStatisticsView::SelectedDataModified() { if( !m_StatisticsUpdatePending ) { emit StatisticsUpdate(); } } void QmitkImageStatisticsView::NodeRemoved(const mitk::DataNode *node) { while(this->m_CalculationThread->isRunning()) // wait until thread has finished { itksys::SystemTools::Delay(100); } if (node->GetData() == m_SelectedImage) { m_SelectedImage = nullptr; } } void QmitkImageStatisticsView::RequestStatisticsUpdate() { if ( !m_StatisticsUpdatePending ) { if(this->m_DataNodeSelectionChanged) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->m_StatisticsUpdatePending = true; this->UpdateStatistics(); } } if (this->GetRenderWindowPart()) this->GetRenderWindowPart()->RequestUpdate(); } void QmitkImageStatisticsView::OnHistogramBinSizeBoxValueChanged() { if (m_Controls->m_HistogramBinSizeSpinbox->value() != m_HistogramBinSize) { m_HistogramBinSize = m_Controls->m_HistogramBinSizeSpinbox->value(); this->m_CalculationThread->SetHistogramBinSize(m_Controls->m_HistogramBinSizeSpinbox->value()); this->UpdateStatistics(); } } void QmitkImageStatisticsView::WriteStatisticsToGUI() { m_Controls->m_JSHistogram->Clear(); //Disconnect OnLineRadioButtonSelected() to prevent reloading chart when radiobutton is checked programmatically disconnect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), 0, 0); connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnPageSuccessfullyLoaded())); m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); m_Controls->m_InfoLabel->setText(""); if(m_DataNodeSelectionChanged) { this->m_StatisticsUpdatePending = false; this->RequestStatisticsUpdate(); return; // stop visualization of results and calculate statistics of new selection } if ( this->m_CalculationThread->GetStatisticsUpdateSuccessFlag()) { if ( this->m_CalculationThread->GetStatisticsChangedFlag() ) { // Do not show any error messages m_Controls->m_ErrorMessageLabel->hide(); m_CurrentStatisticsValid = true; } if (m_SelectedImage != nullptr) { //all statistics are now computed also on planar figures (lines, paths...)! // If a (non-closed) PlanarFigure is selected, display a line profile widget if (m_SelectedPlanarFigure != nullptr) { // Check if the (closed) planar figure is out of bounds and so no image mask could be calculated--> Intensity Profile can not be calculated bool outOfBounds = false; if ( m_SelectedPlanarFigure->IsClosed() && m_SelectedImageMask == nullptr) { outOfBounds = true; const QString message("Planar figure is on a rotated image plane or outside the image bounds."); m_Controls->m_InfoLabel->setText(message); } // check whether PlanarFigure is initialized const mitk::PlaneGeometry *planarFigurePlaneGeometry = m_SelectedPlanarFigure->GetPlaneGeometry(); if ( !(planarFigurePlaneGeometry == nullptr || outOfBounds)) { unsigned int timeStep = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()->GetPos(); mitk::Image::Pointer image; if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(this->m_CalculationThread->GetStatisticsImage()); timeSelector->SetTimeNr(timeStep); timeSelector->Update(); image = timeSelector->GetOutput(); } else { image = this->m_CalculationThread->GetStatisticsImage(); } mitk::IntensityProfile::ConstPointer intensityProfile = (mitk::IntensityProfile::ConstPointer)mitk::ComputeIntensityProfile(image, m_SelectedPlanarFigure); auto intensityProfileList = ConvertIntensityProfileToVector(intensityProfile); m_Controls->m_JSHistogram->SetChartType(QmitkChartWidget::ChartType::line); m_Controls->m_JSHistogram->AddData1D(intensityProfileList); m_Controls->m_JSHistogram->SetDataLabels({ "Intensity profile " + m_Controls->m_SelectedMaskLabel->text().toStdString() }); m_Controls->m_JSHistogram->SetXAxisLabel("Distance"); m_Controls->m_JSHistogram->SetYAxisLabel("Intensity"); m_Controls->m_JSHistogram->Show(m_Controls->m_ShowSubchartCheckBox->isChecked()); m_Controls->m_lineRadioButton->setChecked(true); m_Controls->m_lineRadioButton->setEnabled(false); m_Controls->m_barRadioButton->setEnabled(false); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(false); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(false); m_Controls->m_UseDefaultBinSizeBox->setEnabled(false); //Reconnect OnLineRadioButtonSelected() connect((QObject*)(this->m_Controls->m_JSHistogram), SIGNAL(PageSuccessfullyLoaded()), (QObject*) this, SLOT(OnLineRadioButtonSelected())); auto statisticsVector = this->m_CalculationThread->GetStatisticsData(); //only one entry (current timestep) this->FillLinearProfileStatisticsTableView(statisticsVector.front().GetPointer(), this->m_CalculationThread->GetStatisticsImage()); QString message("Only linegraph available for an intensity profile!"); if (this->m_CalculationThread->GetStatisticsImage()->GetDimension() == 4) { message += "Only current timestep displayed!"; } message += ""; m_Controls->m_InfoLabel->setText(message); m_CurrentStatisticsValid = true; } else { // Clear statistics, histogram, and GUI this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex( 0 ); m_CurrentStatisticsValid = false; m_Controls->m_ErrorMessageLabel->hide(); m_Controls->m_SelectedMaskLabel->setText( "None" ); this->m_StatisticsUpdatePending = false; m_Controls->m_lineRadioButton->setEnabled(true); m_Controls->m_barRadioButton->setEnabled(true); m_Controls->m_HistogramBinSizeSpinbox->setEnabled(true); m_Controls->m_HistogramBinSizeCaptionLabel->setEnabled(true); if (!outOfBounds) m_Controls->m_InfoLabel->setText(""); - return; + return; } } else { m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_Controls->m_HistogramBinSizeSpinbox->setValue(this->m_CalculationThread->GetHistogramBinSize()); auto histogram = this->m_CalculationThread->GetTimeStepHistogram(this->m_CalculationThread->GetTimeStep()).GetPointer(); m_Controls->m_JSHistogram->AddData2D(ConvertHistogramToMap(histogram)); m_Controls->m_JSHistogram->SetChartType(QmitkChartWidget::ChartType::bar); this->m_Controls->m_JSHistogram->SetDataLabels({ m_Controls->m_SelectedFeatureImageLabel->text().toStdString() }); this->m_Controls->m_JSHistogram->SetXAxisLabel("Gray value"); this->m_Controls->m_JSHistogram->SetYAxisLabel("Frequency"); m_Controls->m_JSHistogram->Show(this->m_Controls->m_ShowSubchartCheckBox->isChecked()); this->FillStatisticsTableView(this->m_CalculationThread->GetStatisticsData(), this->m_CalculationThread->GetStatisticsImage()); } m_CurrentStatisticsValid = true; } } else { m_Controls->m_SelectedMaskLabel->setText("None"); m_Controls->m_ErrorMessageLabel->setText(m_CalculationThread->GetLastErrorMessage().c_str()); m_Controls->m_ErrorMessageLabel->show(); // Clear statistics and histogram this->InvalidateStatisticsTableView(); m_Controls->m_StatisticsWidgetStack->setCurrentIndex(0); m_CurrentStatisticsValid = false; } berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); this->m_StatisticsUpdatePending = false; } void QmitkImageStatisticsView::FillStatisticsTableView( const std::vector &statistics, const mitk::Image *image ) { this->m_Controls->m_StatisticsTable->setColumnCount(image->GetTimeSteps()); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(image->GetTimeSteps() > 1); // Set Checkbox for complete copy of statistic table if(image->GetTimeSteps()>1) { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(true); } else { this->m_Controls->m_CheckBox4dCompleteTable->setEnabled(false); this->m_Controls->m_CheckBox4dCompleteTable->setChecked(false); } for (unsigned int t = 0; t < image->GetTimeSteps(); t++) { this->m_Controls->m_StatisticsTable->setHorizontalHeaderItem(t, new QTableWidgetItem(QString::number(t))); if (statistics.at(t)->GetMaxIndex().size()==3) { mitk::Point3D index, max, min; index[0] = statistics.at(t)->GetMaxIndex()[0]; index[1] = statistics.at(t)->GetMaxIndex()[1]; index[2] = statistics.at(t)->GetMaxIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, max); this->m_WorldMaxList.push_back(max); index[0] = statistics.at(t)->GetMinIndex()[0]; index[1] = statistics.at(t)->GetMinIndex()[1]; index[2] = statistics.at(t)->GetMinIndex()[2]; m_SelectedImage->GetGeometry()->IndexToWorld(index, min); this->m_WorldMinList.push_back(min); } auto statisticsVector = AssembleStatisticsIntoVector(statistics.at(t).GetPointer(), image); unsigned int count = 0; for (const auto& entry : statisticsVector) { auto item = new QTableWidgetItem(entry); this->m_Controls->m_StatisticsTable->setItem(count, t, item); count++; } } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); // make sure the current timestep's column is highlighted (and the correct histogram is displayed) unsigned int t = this->GetRenderWindowPart()->GetTimeNavigationController()->GetTime()-> GetPos(); mitk::SliceNavigationController::GeometryTimeEvent timeEvent(this->m_SelectedImage->GetTimeGeometry(), t); this->OnTimeChanged(timeEvent); t = std::min(image->GetTimeSteps() - 1, t); // See bug 18340 /*QString hotspotMean; hotspotMean.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMean(), 0, 'f', decimals)); hotspotMean += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 7, t, new QTableWidgetItem( hotspotMean ) ); QString hotspotMax; hotspotMax.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMax(), 0, 'f', decimals)); hotspotMax += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 8, t, new QTableWidgetItem( hotspotMax ) ); QString hotspotMin; hotspotMin.append(QString("%1").arg(s[t].GetHotspotStatistics().GetMin(), 0, 'f', decimals)); hotspotMin += " ("; for (int i=0; im_Controls->m_StatisticsTable->setItem( 9, t, new QTableWidgetItem( hotspotMin ) );*/ } std::vector QmitkImageStatisticsView::AssembleStatisticsIntoVector(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, mitk::Image::ConstPointer image, bool noVolumeDefined) const { std::vector result; unsigned int decimals = 2; //statistics of higher order should have 5 decimal places because they used to be very small unsigned int decimalsHigherOrderStatistics = 5; if (image->GetPixelType().GetComponentType() == itk::ImageIOBase::DOUBLE || image->GetPixelType().GetComponentType() == itk::ImageIOBase::FLOAT) { decimals = 5; } result.push_back(GetFormattedString(statistics->GetMean(), decimals)); result.push_back(GetFormattedString(statistics->GetMedian(), decimals)); result.push_back(GetFormattedString(statistics->GetStd(), decimals)); result.push_back(GetFormattedString(statistics->GetRMS(), decimals)); result.push_back(GetFormattedString(statistics->GetMax(), decimals) + " " + GetFormattedIndex(statistics->GetMaxIndex())); result.push_back(GetFormattedString(statistics->GetMin(), decimals) + " " + GetFormattedIndex(statistics->GetMinIndex())); //to prevent large negative values of empty image statistics if (statistics->GetN() != std::numeric_limits::max() + 1) { result.push_back(GetFormattedString(statistics->GetN(), 0)); const mitk::BaseGeometry *geometry = image->GetGeometry(); if (geometry != NULL && !noVolumeDefined) { const mitk::Vector3D &spacing = image->GetGeometry()->GetSpacing(); double volume = spacing[0] * spacing[1] * spacing[2] * static_cast(statistics->GetN()); result.push_back(GetFormattedString(volume, decimals)); } else { result.push_back("NA"); } } else { result.push_back("NA"); result.push_back("NA"); } result.push_back(GetFormattedString(statistics->GetSkewness(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetKurtosis(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetUniformity(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetEntropy(), decimalsHigherOrderStatistics)); result.push_back(GetFormattedString(statistics->GetMPP(), decimals)); result.push_back(GetFormattedString(statistics->GetUPP(), decimalsHigherOrderStatistics)); return result; } void QmitkImageStatisticsView::FillLinearProfileStatisticsTableView(mitk::ImageStatisticsCalculator::StatisticsContainer::ConstPointer statistics, const mitk::Image *image) { this->m_Controls->m_StatisticsTable->setColumnCount(1); this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); m_PlanarFigureStatistics = this->AssembleStatisticsIntoVector(statistics, image, true); for (unsigned int i = 0; i< m_PlanarFigureStatistics.size(); i++) { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem(m_PlanarFigureStatistics[i] )); } this->m_Controls->m_StatisticsTable->resizeColumnsToContents(); int height = STAT_TABLE_BASE_HEIGHT; if (this->m_Controls->m_StatisticsTable->horizontalHeader()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalHeader()->height(); if (this->m_Controls->m_StatisticsTable->horizontalScrollBar()->isVisible()) height += this->m_Controls->m_StatisticsTable->horizontalScrollBar()->height(); this->m_Controls->m_StatisticsTable->setMinimumHeight(height); } void QmitkImageStatisticsView::InvalidateStatisticsTableView() { this->m_Controls->m_StatisticsTable->horizontalHeader()->setVisible(false); this->m_Controls->m_StatisticsTable->setColumnCount(1); for ( int i = 0; i < this->m_Controls->m_StatisticsTable->rowCount(); ++i ) { { this->m_Controls->m_StatisticsTable->setItem( i, 0, new QTableWidgetItem( "NA" ) ); } } this->m_Controls->m_StatisticsTable->setMinimumHeight(STAT_TABLE_BASE_HEIGHT); } void QmitkImageStatisticsView::Activated() { } void QmitkImageStatisticsView::Deactivated() { } void QmitkImageStatisticsView::Visible() { m_Visible = true; mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { itk::ReceptorMemberCommand::Pointer cmdTimeEvent = itk::ReceptorMemberCommand::New(); cmdTimeEvent->SetCallbackFunction(this, &QmitkImageStatisticsView::OnTimeChanged); // It is sufficient to add the observer to the axial render window since the GeometryTimeEvent // is always triggered by all views. m_TimeObserverTag = renderWindow->GetQmitkRenderWindow("axial")-> GetSliceNavigationController()-> AddObserver(mitk::SliceNavigationController::GeometryTimeEvent(nullptr, 0), cmdTimeEvent); } if (m_DataNodeSelectionChanged) { if (this->IsCurrentSelectionValid()) { this->SelectionChanged(this->GetCurrentSelection()); } else { this->SelectionChanged(this->GetDataManagerSelection()); } m_DataNodeSelectionChanged = false; } } void QmitkImageStatisticsView::Hidden() { m_Visible = false; // The slice navigation controller observer is removed here instead of in the destructor. // If it was called in the destructor, the application would freeze because the view's // destructor gets called after the render windows have been destructed. if ( m_TimeObserverTag != 0 ) { mitk::IRenderWindowPart* renderWindow = GetRenderWindowPart(); if (renderWindow) { renderWindow->GetQmitkRenderWindow("axial")->GetSliceNavigationController()-> RemoveObserver( m_TimeObserverTag ); } m_TimeObserverTag = 0; } } void QmitkImageStatisticsView::SetFocus() { } std::map QmitkImageStatisticsView::ConvertHistogramToMap(itk::Statistics::Histogram::ConstPointer histogram) const { std::map histogramMap; auto endIt = histogram->End(); auto it = histogram->Begin(); // generating Lists of measurement and frequencies for (; it != endIt; ++it) { double frequency = it.GetFrequency(); double measurement = it.GetMeasurementVector()[0]; histogramMap.emplace(measurement, frequency); } return histogramMap; } std::vector QmitkImageStatisticsView::ConvertIntensityProfileToVector(mitk::IntensityProfile::ConstPointer intensityProfile) const { std::vector intensityProfileList; auto end = intensityProfile->End(); for (auto it = intensityProfile->Begin(); it != end; ++it) { intensityProfileList.push_back(it.GetMeasurementVector()[0]); } return intensityProfileList; } QString QmitkImageStatisticsView::GetFormattedString(double value, unsigned int decimals) const { typedef mitk::ImageStatisticsCalculator::StatisticsContainer::RealType RealType; RealType maxVal = std::numeric_limits::max(); if (value == maxVal) { return QString("NA"); } else { return QString("%1").arg(value, 0, 'f', decimals); } } QString QmitkImageStatisticsView::GetFormattedIndex(const vnl_vector& vector) const { if (vector.empty()) { return QString(); } QString formattedIndex("("); for (const auto& entry : vector) { formattedIndex += QString::number(entry); formattedIndex += ","; } formattedIndex.chop(1); formattedIndex += ")"; return formattedIndex; }