Add ResliceImageViewer, ResliceImageInteractorStyle, ResliceCursorLegendActor, MPRResliceWindow.

This commit is contained in:
Krad
2022-12-13 09:46:02 +08:00
parent c12818b49c
commit 46d22eacd7
8 changed files with 989 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
//
// Created by Krad on 2022/12/6.
//
#include "ResliceImageInteractorStyle.h"
#include <vtkObjectFactory.h>
#include <vtkCommand.h>
#include <vtkCallbackCommand.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkPropCollection.h>
vtkStandardNewMacro(ResliceImageInteractorStyle)
ResliceImageInteractorStyle::ResliceImageInteractorStyle():vtkInteractorStyleImage() {
}
ResliceImageInteractorStyle::~ResliceImageInteractorStyle() {
}
void ResliceImageInteractorStyle::OnMouseMove() {
if (triggerEvent)
{
this->InvokeEvent(vtkCommand::UserEvent+20,Interactor->GetEventPosition());
this->Interactor->Render();
}
else{
vtkInteractorStyleImage::OnMouseMove();
}
}
void ResliceImageInteractorStyle::OnLeftButtonDown() {
triggerEvent = false;
vtkInteractorStyleImage::OnLeftButtonDown();
}
void ResliceImageInteractorStyle::OnLeftButtonUp() {
vtkInteractorStyleImage::OnLeftButtonUp();
triggerEvent = true;
}

View File

@@ -0,0 +1,39 @@
//
// Created by Krad on 2022/12/6.
//
#ifndef RENDERLAB_RESLICEIMAGEINTERACTORSTYLE_H
#define RENDERLAB_RESLICEIMAGEINTERACTORSTYLE_H
#include <vtkInteractorStyleImage.h>
#include <vector>
#include <vtkRenderer.h>
class ResliceImageInteractorStyle:public vtkInteractorStyleImage {
public:
static ResliceImageInteractorStyle *New();
vtkTypeMacro(ResliceImageInteractorStyle, vtkInteractorStyleImage);
void OnLeftButtonDown() override;
void OnLeftButtonUp() override;
void OnMouseMove() override;
protected:
ResliceImageInteractorStyle();
~ResliceImageInteractorStyle() override;
private:
ResliceImageInteractorStyle(const ResliceImageInteractorStyle &) = delete;
void operator=(const ResliceImageInteractorStyle &) = delete;
bool triggerEvent = true;
};
#endif //RENDERLAB_RESLICEIMAGEINTERACTORSTYLE_H

View File

@@ -0,0 +1,233 @@
//
// Created by Krad on 2022/12/1.
//
#include "ResliceCursorLegendActor.h"
#include <vtkObjectFactory.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkInteractorStyle.h>
#include <vtkCamera.h>
#include <vtkPoints.h>
#include <vtkProperty2D.h>
#include <vtkActor2D.h>
#include <vtkPolyLineSource.h>
#include <vtkProperty2D.h>
#include <vtkDiskSource.h>
#include "Rendering/Core/ControlPointRActor.h"
namespace {
class Vector2 {
public:
Vector2(double x, double y) {
X = x;
Y = y;
}
double X;
double Y;
double getValue(int index){
if (index == 0) return X;
else return Y;
}
Vector2& operator=(const Vector2& other){
this->X = other.X;
this->Y = other.Y;
return *this;
}
Vector2 operator-(const Vector2 &other) const {
return {this->X - other.X, this->Y - other.Y};
}
Vector2 operator+(const Vector2 &other) const {
return {this->X + other.X, this->Y + other.Y};
}
Vector2 operator*(double val) const {
return {this->X * val, this->Y * val};
}
Vector2 operator/(const double val) const {
return {this->X / val, this->Y / val};
}
static double cross(const Vector2 &a, const Vector2 &b) {
return a.X * b.Y - a.Y * b.X;
}
};
bool IntersectLine2D(const Vector2& p1,const Vector2& v1,
const Vector2& p2, const Vector2& v2, Vector2& intersectPoint){
double crossV = Vector2::cross(v1, v2);
if (abs(crossV) > 1e-6) {
double t = Vector2::cross(p2-p1, v2) / crossV;
intersectPoint = p1 + v1 * t;
return true;
}
return false;
};
}
vtkStandardNewMacro(ResliceCursorLegendActor)
ResliceCursorLegendActor::ResliceCursorLegendActor()
: vtkProp()
, LineActor(vtkActor2D::New())
, ControlPoint(ControlPointRActor::New())
, LineShadow(vtkActor2D::New())
, senseArea(vtkActor2D::New())
, linePolyData(vtkPolyData::New()){
vtkNew<vtkPoints> pts;
pts->SetNumberOfPoints(2);
pts->SetPoint(0,0,0,0);
pts->SetPoint(1,0,0,0);
linePolyData->SetPoints(pts);
vtkIdType ids[2] = {0, 1};
linePolyData->GetLines()->InsertNextCell(2,ids);
vtkNew<vtkPolyDataMapper2D> mapper ;
vtkNew<vtkPolyDataMapper2D> mapper1 ;
vtkNew<vtkPolyDataMapper2D> mapper2 ;
mapper->SetInputData(linePolyData);
mapper1->SetInputData(linePolyData);
mapper2->SetInputData(linePolyData);
LineActor->SetMapper(mapper);
LineShadow->SetMapper(mapper1);
senseArea->SetMapper(mapper2);
ControlPoint->SetWorldPosition(0,0,0);
}
ResliceCursorLegendActor::~ResliceCursorLegendActor() {
}
// 避免坐标系值问题导致线变粗
void AlignDoubleVector3(double* in, double *out){
for (int i = 0; i < 3; ++i) {
out[i] = ((int)in[i]) + 0.5;
}
}
void ResliceCursorLegendActor::BuildShape(vtkRenderer *renderer) {
//handle disk
if (HandleUpdated){
renderer->SetDisplayPoint(Handle2DPoint[0],Handle2DPoint[1], 0);
renderer->DisplayToWorld();
renderer->GetWorldPoint(HandlePoint);
HandleUpdated = false;
}
ControlPoint->SetWorldPosition(HandlePoint);
//cross hair
double vector[3] = {.0, .0, .0};
vtkMath::Cross(GetSliceDirectionVector(), GetProjectDirectionVector(), vector);
vtkMath::Normalize(vector);
double point1[4] = {SlicePoint[0] ,
SlicePoint[1] ,
SlicePoint[2],
1.0};
double point2[4] = {SlicePoint[0] + vector[0],
SlicePoint[1] + vector[1],
SlicePoint[2] + vector[2],
1.0};
double out1[4] = {.0, .0, .0,.0};
double out2[4] = {.0, .0, .0, .0};
linePolyData->GetPoints()->SetNumberOfPoints(2);
renderer->SetWorldPoint(point1);
renderer->WorldToDisplay();
renderer->GetDisplayPoint(out1);
renderer->SetWorldPoint(point2);
renderer->WorldToDisplay();
renderer->GetDisplayPoint(out2);
double vector2D[2] = {out2[0] - out1[0], out2[1] - out1[1]};
vtkMath::Normalize2D(vector2D);
Vector2 v1 = {vector2D[0], vector2D[1]};
Vector2 screenVectors[2] ={{0, 1}, {1, 0}};
Vector2 p0 = {out1[0],out1[1]};
int *size = renderer->GetSize();
Vector2 pts[2] = {{-0.5,-0.5} ,{size[0] + 0.5,size[1] + 0.5}};
Vector2 intersectPoint(.0, .0);
// calc the point, which line cross the screen border
int pointIdx = 0;
// line vector loop
for (int i = 0; i < 2; ++i) {
// line point loop
for (const auto & pt : pts) {
if (pointIdx >= 2)return;
if (IntersectLine2D(p0, v1, pt, screenVectors[i], intersectPoint)) {
int pcV = (int) intersectPoint.getValue(i);
if (pcV >= -1 && pcV <= size[i] + 1) {
linePolyData->GetPoints()->SetPoint(pointIdx++, (int)intersectPoint.X + 0.5, (int)intersectPoint.Y + 0.5, 0);
}
}
}
}
}
void ResliceCursorLegendActor::ReleaseGraphicsResources(vtkWindow * window) {
senseArea->ReleaseGraphicsResources(window);
LineActor->ReleaseGraphicsResources(window);
LineShadow->ReleaseGraphicsResources(window);
ControlPoint->ReleaseGraphicsResources(window);
vtkProp::ReleaseGraphicsResources(window);
}
int ResliceCursorLegendActor::RenderOverlay(vtkViewport *viewport) {
auto renderer = vtkRenderer::SafeDownCast(viewport);
if (!renderer) return 0;
if (firstRender){
ControlPoint->SetRenderer(renderer);
firstRender = false;
}
BuildShape(renderer);
if (senseArea->GetVisibility())senseArea->RenderOverlay(viewport);
if (LineShadow->GetVisibility())LineShadow->RenderOverlay(viewport);
if (LineActor->GetVisibility())LineActor->RenderOverlay(viewport);
if (ControlPoint->GetVisibility())ControlPoint->RenderOverlay(viewport);
return 1;
}
vtkProperty2D *ResliceCursorLegendActor::GetProperty() {
return LineActor->GetProperty();
}
void ResliceCursorLegendActor::UpdateMousePosition(int* pos) {
double point0[3] = {.0,.0,.0};
double point1[3] = {.0,.0,.0};
linePolyData->GetPoints()->GetPoint(0,point0);
linePolyData->GetPoints()->GetPoint(1,point1);
double vector[3] = {
point1[0] - point0[0],
point1[1] - point0[1],
0
};
vtkMath::Normalize(vector);
double zVector[3] = {.0, .0, 1.0};
double out[3] = {.0, .0, .0};
vtkMath::Cross(vector, zVector, out);
Vector2 p1 (pos[0]+0.5,pos[1]+0.5);
Vector2 p2 (point0[0],point0[1]);
Vector2 v1 (out[0],out[1]);
Vector2 v2 (vector[0],vector[1]);
Vector2 intersectPoint (.0,.0);
if(IntersectLine2D(p1,v1,p2,v2,intersectPoint))
{
Handle2DPoint[0] = (int)intersectPoint.X+0.5;
Handle2DPoint[1] = (int)intersectPoint.Y+0.5;
HandleUpdated = true;
this->Modified();
}
}
void ResliceCursorLegendActor::Pick() {
vtkProp::Pick();
}

View File

@@ -0,0 +1,98 @@
//
// Created by Krad on 2022/12/1.
//
#ifndef RENDERLAB_RESLICECURSORLEGENDACTOR_H
#define RENDERLAB_RESLICECURSORLEGENDACTOR_H
#include <vtkProp.h>
class vtkRenderer;
class vtkPolyData;
class vtkActor2D;
class vtkDiskSource;
class vtkProperty2D;
class ControlPointRActor;
class ResliceCursorLegendActor:public vtkProp {
public:
//@{
/**
* Standard methods for instances of this class.
*/
static ResliceCursorLegendActor *New();
vtkTypeMacro(ResliceCursorLegendActor, vtkProp);
virtual void BuildShape(vtkRenderer *renderer);
vtkSetVector3Macro(SlicePoint,double);
vtkGetVector3Macro(SlicePoint,double);
vtkSetVector3Macro(SliceDirectionVector,double);
vtkGetVector3Macro(SliceDirectionVector,double);
vtkSetVector3Macro(ProjectDirectionVector,double);
vtkGetVector3Macro(ProjectDirectionVector,double);
vtkProperty2D* GetProperty();
//@{
/**
* Methods to make this class behave as a vtkProp.
*/
double *GetBounds() VTK_SIZEHINT(6) override { return nullptr; }
void GetActors(vtkPropCollection *) override {}
void GetVolumes(vtkPropCollection *) override {}
void ShallowCopy(vtkProp *prop) override {};
void ReleaseGraphicsResources(vtkWindow *) override;
/**
* Method use to make this actor render in 2D scene;
* @param viewport
* @return render is success
*/
int RenderOverlay(vtkViewport *viewport) override;
int RenderOpaqueGeometry(vtkViewport *vtkNotUsed(viewport)) override { return 0; }
int RenderTranslucentPolygonalGeometry(vtkViewport *vtkNotUsed(viewport)) override { return 0; }
int RenderVolumetricGeometry(vtkViewport *vtkNotUsed(viewport)) override { return 0; }
vtkTypeBool HasTranslucentPolygonalGeometry() override { return 0; }
void UpdateMousePosition(int* pos);
void Pick() override;
protected:
ResliceCursorLegendActor();
~ResliceCursorLegendActor() override;
private:
ResliceCursorLegendActor(const ResliceCursorLegendActor &) = delete;
void operator=(const ResliceCursorLegendActor &) = delete;
vtkActor2D *LineActor;
ControlPointRActor *ControlPoint;
vtkActor2D *LineShadow;
vtkActor2D *senseArea;
vtkPolyData* linePolyData;
double LineHalfLength = 500.0;
double SlicePoint[3] = {.0, .0, .0};
double HandlePoint[4] = {.0, .0, .0, .0};
bool HandleUpdated = false;
bool firstRender = true;
double Handle2DPoint[2] = {.0, .0, };
double SliceDirectionVector[3] = {.0, .0, .0};
double ProjectDirectionVector[3] = {.0, .0, .0};
};
#endif //RENDERLAB_RESLICECURSORLEGENDACTOR_H

View File

@@ -0,0 +1,233 @@
//
// Created by Krad on 2022/12/8.
//
#include "ResliceImageViewer.h"
#include <vtkObjectFactory.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkImageData.h>
#include <vtkInteractorStyleImage.h>
#include <vtkImageResliceMapper.h>
#include <vtkImageSlice.h>
#include <vtkMatrix4x4.h>
#include <vtkProperty2D.h>
#include "Rendering/Legend/ResliceCursorLegendActor.h"
#include "Interaction/ResliceImageInteractorStyle.h"
vtkStandardNewMacro(ResliceImageViewer);
ResliceImageViewer::ResliceImageViewer()
: vtkObject()
, RenderWindow(nullptr)
, Renderer(vtkRenderer::New())
, InteractorStyle(ResliceImageInteractorStyle::New())
, Interactor(nullptr)
, Mapper(vtkImageResliceMapper::New())
, cursor1(ResliceCursorLegendActor::New())
, cursor2(ResliceCursorLegendActor::New())
, Actor(vtkImageSlice::New())
, OrientationMatrix(vtkMatrix4x4::New())
, DefaultOrientation(0)
, FirstRender(true)
{
Mapper->SetSliceAtFocalPoint(true);
Mapper->SetSliceFacesCamera(true);
Mapper->SetResampleToScreenPixels(0);
Mapper->SetSeparateWindowLevelOperation(0);
Actor->SetMapper(Mapper);
OrientationMatrix->Identity();
}
ResliceImageViewer::~ResliceImageViewer() {
if (this->OrientationMatrix) {
this->OrientationMatrix->Delete();
this->OrientationMatrix = nullptr;
}
if (this->Mapper) {
vtkImageData* imageData_nullptr = nullptr;
this->Mapper->SetInputData(imageData_nullptr);
this->Mapper->Delete();
this->Mapper = nullptr;
}
if (this->Actor) {
this->Actor->Delete();
this->Actor = nullptr;
}
if (this->Renderer) {
this->Renderer->Delete();
this->Renderer = nullptr;
}
if (this->RenderWindow) {
this->RenderWindow->Delete();
this->RenderWindow = nullptr;
}
if (this->Interactor) {
this->Interactor->Delete();
this->Interactor = nullptr;
}
if (this->InteractorStyle) {
this->InteractorStyle->Delete();
this->InteractorStyle = nullptr;
}
}
void ResliceImageViewer::InstallPipeline() {
if (this->RenderWindow && this->Renderer) {
this->Renderer->GetActiveCamera()->ParallelProjectionOn();
this->Renderer->SetUseFXAA(1);
this->RenderWindow->AddRenderer(this->Renderer);
this->Interactor = this->RenderWindow->GetInteractor();
InteractorStyle->HandleObserversOn();
this->Interactor->SetInteractorStyle(InteractorStyle);
}
if (this->Renderer && this->Actor) {
this->Renderer->AddViewProp(Actor);
this->Renderer->SetBackground(0., 0., 0.);
}
}
void ResliceImageViewer::UnInstallPipeline() {
if (this->Renderer && this->Actor) {
this->Renderer->RemoveViewProp(this->Actor);
}
if (this->RenderWindow && this->Renderer) {
this->RenderWindow->RemoveRenderer(this->Renderer);
}
if (this->Renderer && Actor) {
if (this->Renderer->HasViewProp(Actor))
{
this->Renderer->RemoveViewProp(Actor);
}
Renderer->RemoveAllObservers();
}
if (this->Interactor) {
this->Interactor->SetInteractorStyle(nullptr);
this->Interactor->SetRenderWindow(nullptr);
}
}
void ResliceImageViewer::SetRenderWindow(vtkRenderWindow *renderWindow) {
if(renderWindow == RenderWindow)return;
if(RenderWindow) {
UnInstallPipeline();
RenderWindow->Delete();
}
RenderWindow = renderWindow;
InstallPipeline();
}
void ResliceImageViewer::SetInputData(vtkImageData *in) {
if (in && in != this->Mapper->GetInput()){
in->Modified();
this->Mapper->SetInputData(in);
}
}
void ResliceImageViewer::Render() {
if (RenderWindow && Interactor){
if (FirstRender){
FirstRender = false;
Renderer->AddActor2D(cursor1);
Renderer->AddActor2D(cursor2);
cursor1->SetSlicePoint(Renderer->GetActiveCamera()->GetFocalPoint());
cursor2->SetSlicePoint(Renderer->GetActiveCamera()->GetFocalPoint());
double project[3] = {0,0.0,1.0};
project[DefaultOrientation] = 1.;
OrientationMatrix->MultiplyPoint(project,project);
cursor1->SetProjectDirectionVector(project);
cursor2->SetProjectDirectionVector(project);
double sliceDirection1[4]{.0, .0, .0, 1.};
double sliceDirection2[4]{.0, .0, .0, 1.};
switch (DefaultOrientation) {
case 0:{
sliceDirection1[2] = 1.0;
cursor1->GetProperty()->SetColor(0,0,1);
sliceDirection2[1] = 1.0;
cursor2->GetProperty()->SetColor(0,1,0);
break;
}
case 1:{
sliceDirection1[0] = 1.0;
cursor1->GetProperty()->SetColor(1,0,0);
sliceDirection2[2] = 1.0;
cursor2->GetProperty()->SetColor(0,0,1);
break;
}
case 2:{
sliceDirection1[0] = 1.0;
cursor1->GetProperty()->SetColor(1,0,0);
sliceDirection2[01] = 1.0;
cursor2->GetProperty()->SetColor(0,1,0);
break;
}
}
OrientationMatrix->MultiplyPoint(sliceDirection1,sliceDirection1);
OrientationMatrix->MultiplyPoint(sliceDirection2,sliceDirection2);
cursor1->SetSliceDirectionVector(sliceDirection1);
cursor2->SetSliceDirectionVector(sliceDirection2);
this->InteractorStyle->AddObserver(vtkCommand::UserEvent+20,this,&ResliceImageViewer::updateHandle);
//some first render logic
Render();
return;
}
Interactor->Render();
}
}
void ResliceImageViewer::SetDefaultSliceOrientation(int orientation) {
double position[4] = {.0, .0, .0, 1.};
double ViewUp[4] = {.0, .0, .0, 1.};
switch (orientation){
case 1:{
position[1] = -1.0;
ViewUp[2] = 1.0;
break;
}
case 0:{
position[0] = 1.0;
ViewUp[2] = 1.0;
break;
}
case 2: {
position[2] = -1.0;
ViewUp[1] = -1.0;
break;
}
default:
break;
}
DefaultOrientation = orientation;
OrientationMatrix->MultiplyPoint(position,position);
OrientationMatrix->MultiplyPoint(ViewUp,ViewUp);
vtkCamera* camera = Renderer->GetActiveCamera();
camera->SetFocalPoint(.0, .0, .0);
camera->SetPosition(position);
camera->SetViewUp(ViewUp);
Renderer->ResetCamera();
}
void ResliceImageViewer::SetCoordsTransformMatrix(vtkMatrix4x4 *matrix4X4) {
OrientationMatrix->DeepCopy(matrix4X4);
OrientationMatrix->Invert();
}
void ResliceImageViewer::updateHandle(vtkObject* sender, unsigned long eventID, void* callData) {
int* pos = (int*)callData;
cursor1->UpdateMousePosition(pos);
cursor2->UpdateMousePosition(pos);
}

View File

@@ -0,0 +1,73 @@
//
// Created by Krad on 2022/12/8.
//
#ifndef OMEGAV_RESLICEIMAGEVIEWER_H
#define OMEGAV_RESLICEIMAGEVIEWER_H
#include "vtkObject.h"
class vtkImageData;
class vtkRenderWindow;
class vtkRenderer;
class vtkRenderWindowInteractor;
class ResliceImageInteractorStyle;
class vtkImageResliceMapper;
class vtkImageSlice;
class vtkMatrix4x4;
class ResliceCursorLegendActor;
class ResliceImageViewer :public vtkObject {
public:
static ResliceImageViewer *New();
vtkTypeMacro(ResliceImageViewer, vtkObject);
virtual void Render();
void SetRenderWindow(vtkRenderWindow* renderWindow);
vtkGetMacro(RenderWindow, vtkRenderWindow*)
void SetInputData(vtkImageData *in);
void SetDefaultSliceOrientation(int orientation);
void SetCoordsTransformMatrix(vtkMatrix4x4* matrix4X4);
protected:
ResliceImageViewer();
~ResliceImageViewer() override;
virtual void InstallPipeline();
virtual void UnInstallPipeline();
void updateHandle(vtkObject* sender, unsigned long eventID, void* callData);
private:
ResliceImageViewer(const ResliceImageViewer &) = delete;
void operator=(const ResliceImageViewer &) = delete;
vtkRenderWindow *RenderWindow;
vtkRenderer *Renderer;
vtkRenderer *MeasureRenderer;
ResliceImageInteractorStyle *InteractorStyle;
vtkRenderWindowInteractor *Interactor;
vtkImageResliceMapper* Mapper;
ResliceCursorLegendActor* cursor1;
ResliceCursorLegendActor* cursor2;
vtkImageSlice* Actor;
vtkMatrix4x4* OrientationMatrix;
int DefaultOrientation;
bool FirstRender;
};
#endif //OMEGAV_RESLICEIMAGEVIEWER_H

View File

@@ -0,0 +1,219 @@
//
// Created by Krad on 2022/12/8.
//
#include "MPRResliceWindow.h"
#include <vtkGenericOpenGLRenderWindow.h>
#include <QVBoxLayout>
#include <QGuiApplication.h>
#include <QVTKOpenGLNativeWidget.h>
#include <QGridLayout>
#include <QMenuBar>
#include <QSplitter>
#include "Common/SeriesImageSet.h"
#include "UI/Widget/ToolBar/ResliceMPRToolBar.h"
#include "Rendering/Viewer/ResliceImageViewer.h"
MPRResliceWindow::MPRResliceWindow(QWidget *parent, Qt::WindowFlags f) : QDialog(parent, f) {
setObjectName("MPRWin");
this->setMinimumSize(800,600);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->setMargin(1);
layout->setSpacing(0);
auto toolBar = new ResliceMPRToolBar(this);
layout->addWidget(toolBar);
mWidgetAxial = new QVTKOpenGLNativeWidget(this);
mWidgetAxial->setEnableHiDPI(true);
mWidgetAxial->setBaseSize(400,300);
mWidgetAxial->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Expanding);
mWidgetSagittal = new QVTKOpenGLNativeWidget(this);
mWidgetSagittal->setEnableHiDPI(true);
mWidgetSagittal->setBaseSize(400,300);
mWidgetSagittal->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Expanding);
mWidgetCoronal = new QVTKOpenGLNativeWidget(this);
mWidgetCoronal->setEnableHiDPI(true);
mWidgetCoronal->setBaseSize(400,300);
mWidgetCoronal->setSizePolicy(QSizePolicy::Policy::Expanding,QSizePolicy::Policy::Expanding);
setRenderWindowLayout(Columns_1_2);
auto window1 = vtkGenericOpenGLRenderWindow::New();
window1->SetLineSmoothing(1);
window1->SetPointSmoothing(1);
window1->SetPolygonSmoothing(1);
mViewerC = ResliceImageViewer::New();
mWidgetCoronal->setRenderWindow(window1);
auto window2 = vtkGenericOpenGLRenderWindow::New();
window2->SetLineSmoothing(1);
window2->SetPointSmoothing(1);
window2->SetPolygonSmoothing(1);
mViewerA = ResliceImageViewer::New();
mWidgetAxial->setRenderWindow(window2);
auto window3 = vtkGenericOpenGLRenderWindow::New();
window3->SetLineSmoothing(1);
window3->SetPointSmoothing(1);
window3->SetPolygonSmoothing(1);
mViewerS = ResliceImageViewer::New();
mWidgetSagittal->setRenderWindow(window3);
}
MPRResliceWindow::~MPRResliceWindow() {
}
void MPRResliceWindow::setRenderWindowLayout(LayoutType type) {
for (int i = 0 ; mMainSplitter && i < mMainSplitter->count(); ++i) {
mMainSplitter->replaceWidget(i,new QWidget);
}
for (int i = 0 ; mAppendSplitter && i < mAppendSplitter->count(); ++i) {
mAppendSplitter->replaceWidget(i,new QWidget);
}
if (mMainSplitter)mMainSplitter->deleteLater();
mMainSplitter = new QSplitter(this);
mMainSplitter->setHandleWidth(2);
layout()->addWidget(mMainSplitter);
mAppendSplitter = new QSplitter(this);
mAppendSplitter->setHandleWidth(2);
mMainSplitter->addWidget(mAppendSplitter);
switch (type) {
case Columns_1_1_1:
{
QWidget* widgets[3] = {mWidgetCoronal, mWidgetAxial, mWidgetSagittal};
mAppendSplitter->setVisible(false);
mMainSplitter->setOrientation(Qt::Horizontal);
int width = this->width()/3;
for (auto & widget : widgets) {
mMainSplitter->addWidget(widget);
}
QList<int> sizes{0,width,width,width};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,0);
mMainSplitter->setStretchFactor(1,1);
mMainSplitter->setStretchFactor(2,1);
mMainSplitter->setStretchFactor(3,1);
break;
}
case Columns_1_2:{
mMainSplitter->setOrientation(Qt::Horizontal);
mAppendSplitter->setVisible(true);
QWidget* widgets[2] = {mWidgetAxial,mWidgetSagittal };
for (auto & widget : widgets) {
mAppendSplitter->addWidget(widget);
}
mMainSplitter->insertWidget(0,mWidgetCoronal);
mAppendSplitter->setOrientation(Qt::Vertical);
mAppendSplitter->setVisible(true);
QList<int> sizes{width()/2, width()/2};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,1);
mMainSplitter->setStretchFactor(1,1);
QList<int> sizes1{height()/2, height()/2};
mAppendSplitter->setSizes(sizes1);
mAppendSplitter->setStretchFactor(0,1);
mAppendSplitter->setStretchFactor(1,1);
break;
}
case Columns_2_1:{
QWidget* widgets[2] = {mWidgetSagittal, mWidgetAxial};
mMainSplitter->setOrientation(Qt::Horizontal);
mMainSplitter->addWidget(mWidgetCoronal);
mAppendSplitter->setOrientation(Qt::Vertical);
mAppendSplitter->setVisible(true);
for (auto & widget : widgets) {
mAppendSplitter->addWidget(widget);
}
QList<int> sizes{width()/2, width()/2};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,1);
mMainSplitter->setStretchFactor(1,1);
QList<int> sizes1{height()/2, height()/2};
mAppendSplitter->setSizes(sizes1);
mAppendSplitter->setStretchFactor(0,1);
mAppendSplitter->setStretchFactor(1,1);
break;
}
case Rows_1_2:{
QWidget* widgets[2] = {mWidgetAxial, mWidgetSagittal};
mMainSplitter->setOrientation(Qt::Vertical);
mMainSplitter->insertWidget(0,mWidgetCoronal);
mAppendSplitter->setOrientation(Qt::Horizontal);
mAppendSplitter->setVisible(true);
for (auto & widget : widgets) {
mAppendSplitter->addWidget(widget);
}
QList<int> sizes{height()/2, height()/2};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,1);
mMainSplitter->setStretchFactor(1,1);
QList<int> sizes1{width()/2, width()/2};
mAppendSplitter->setSizes(sizes1);
mAppendSplitter->setStretchFactor(0,1);
mAppendSplitter->setStretchFactor(1,1);
break;
}
case Rows_2_1:{
QWidget* widgets[2] = {mWidgetAxial, mWidgetSagittal};
mMainSplitter->setOrientation(Qt::Vertical);
mMainSplitter->addWidget(mWidgetCoronal);
mAppendSplitter->setOrientation(Qt::Horizontal);
mAppendSplitter->setVisible(true);
for (auto & widget : widgets) {
mAppendSplitter->addWidget(widget);
}
QList<int> sizes{height()/2, height()/2};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,1);
mMainSplitter->setStretchFactor(1,1);
QList<int> sizes1{width()/2, width()/2};
mAppendSplitter->setSizes(sizes1);
mAppendSplitter->setStretchFactor(0,1);
mAppendSplitter->setStretchFactor(1,1);
break;
}
case Rows_1_1_1:{
QWidget* widgets[3] = { mWidgetAxial, mWidgetSagittal,mWidgetCoronal};
mAppendSplitter->setVisible(false);
mMainSplitter->setOrientation(Qt::Vertical);
for (auto & widget : widgets) {
mMainSplitter->addWidget(widget);
}
QList<int> sizes{0,height()/3, height()/3, height()/3};
mMainSplitter->setSizes(sizes);
mMainSplitter->setStretchFactor(0,0);
mMainSplitter->setStretchFactor(1,1);
mMainSplitter->setStretchFactor(2,1);
mMainSplitter->setStretchFactor(3,1);
break;
}
}
}
void MPRResliceWindow::loadData(SeriesImageSet *series) {
mViewerC->SetRenderWindow(mWidgetCoronal->renderWindow());
mViewerC->SetCoordsTransformMatrix(series->GetProperty()->GetOrientationMatrix());
mViewerC->SetInputData(series->GetData());
mViewerC->SetDefaultSliceOrientation(2);
mViewerC->Render();
mViewerS->SetRenderWindow(mWidgetSagittal->renderWindow());
mViewerS->SetCoordsTransformMatrix(series->GetProperty()->GetOrientationMatrix());
mViewerS->SetInputData(series->GetData());
mViewerS->SetDefaultSliceOrientation(1);
mViewerS->Render();
mViewerA->SetRenderWindow(mWidgetAxial->renderWindow());
mViewerA->SetCoordsTransformMatrix(series->GetProperty()->GetOrientationMatrix());
mViewerA->SetInputData(series->GetData());
mViewerA->SetDefaultSliceOrientation(0);
mViewerA->Render();
}

View File

@@ -0,0 +1,49 @@
//
// Created by Krad on 2022/12/8.
//
#ifndef OMEGAV_MPRRESLICEWINDOW_H
#define OMEGAV_MPRRESLICEWINDOW_H
#include <QDialog>
#include <vtkSmartPointer.h>
#include <vtkImageData.h>
class QVTKOpenGLNativeWidget;
class ResliceImageViewer;
class QSplitter;
class SeriesImageSet;
class MPRResliceWindow :public QDialog {
Q_OBJECT
public:
explicit MPRResliceWindow(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
~MPRResliceWindow();
enum LayoutType{
Columns_1_2,
Columns_2_1,
Columns_1_1_1,
Rows_1_2,
Rows_2_1,
Rows_1_1_1,
};
void loadData(SeriesImageSet* series);
void setRenderWindowLayout(LayoutType type);
private:
QVTKOpenGLNativeWidget *mWidgetAxial;
QVTKOpenGLNativeWidget *mWidgetSagittal;
QVTKOpenGLNativeWidget *mWidgetCoronal;
vtkSmartPointer<vtkImageData> mImageData = nullptr;
ResliceImageViewer *mViewerA = nullptr;
ResliceImageViewer *mViewerS = nullptr;
ResliceImageViewer *mViewerC = nullptr;
QSplitter* mMainSplitter= nullptr;
QSplitter* mAppendSplitter= nullptr;
int layoutType = 0;
};
#endif //OMEGAV_MPRRESLICEWINDOW_H