From 203ab670023fd1a47cff8d115a30b5504fcd2d41 Mon Sep 17 00:00:00 2001 From: Krad Date: Wed, 24 Aug 2022 10:51:00 +0800 Subject: [PATCH] MPR menu button. --- src/src/Rendering/Viewer/DICOMImageViewer.cxx | 201 ++++++++++-------- src/src/Rendering/Viewer/DICOMImageViewer.h | 33 +-- src/src/UI/Manager/ImageViewManager.cpp | 16 +- src/src/UI/Manager/ImageViewManager.h | 2 +- .../UI/Manager/ImageViewStateCheckWorker.cpp | 2 +- .../UI/Manager/ImageViewStateCheckWorker.h | 2 +- .../UI/Widget/ImageView/dicomimageview.cpp | 19 +- src/src/UI/Widget/ImageView/dicomimageview.h | 10 +- src/src/UI/Widget/ToolBar/DefaultToolBar.cpp | 46 +++- src/src/UI/Widget/ToolBar/DefaultToolBar.h | 2 +- src/src/UI/Window/QDicomViewer.cpp | 4 +- 11 files changed, 191 insertions(+), 146 deletions(-) diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.cxx b/src/src/Rendering/Viewer/DICOMImageViewer.cxx index bbb3875..17eb22d 100644 --- a/src/src/Rendering/Viewer/DICOMImageViewer.cxx +++ b/src/src/Rendering/Viewer/DICOMImageViewer.cxx @@ -27,6 +27,31 @@ #include "IO/General/ColorMapReader.h" #include "Interaction/ActorDraggableInteractorStyle.h" +namespace { + //扭转存在偏转的坐标轴 + void adjustVector(double* vector,int & ijkIdx){ + int maxIdx = fabs(vector[0]) > fabs(vector[1]) ? + (fabs(vector[0]) > fabs(vector[2]) ? 0 : 2) : + (fabs(vector[1]) > fabs(vector[2]) ? 1 : 2); + double temp = vector[maxIdx]; + vector[0] = 0.0; + vector[1] = 0.0; + vector[2] = 0.0; + vector[maxIdx] = 1.0*(temp>0?1.0:-1.0); + ijkIdx = maxIdx; + } + + void adjustVector(double* vector){ + int a; + adjustVector(vector, a); + } + + int projToPlane(int idx){ + if(idx == 0) return 1; + if(idx == 1) return 0; + return idx; + } +} vtkStandardNewMacro(DICOMImageViewer); @@ -37,7 +62,7 @@ DICOMImageViewer::DICOMImageViewer() ImageActor(vtkImageSlice::New()), ImageMapper(vtkImageSliceMapper::New()), FusionActor(nullptr), FusionMapper(nullptr), Interactor(nullptr), InteractorStyle(nullptr), OpacityActor(nullptr), cornerAnnotation(vtkCornerAnnotation::New()), bar(nullptr), - SliceOrientation(DICOMImageViewer::SLICE_ORIENTATION_XY), FirstRender(1), Slice(0), loadedMeasureSlice(0), + SliceIJK(-1),SlicePlane(-1), FirstRender(1), Slice(0), loadedMeasureSlice(0), currentPresetIndex(1), Fusion(false), firstFusion(true), FusionOpacity(0.5), list(nullptr), measureStore(MeasureStore::Instance()), rulerActive(false){ @@ -125,8 +150,6 @@ DICOMImageViewer::~DICOMImageViewer() { void DICOMImageViewer::SetupImageViewer() { this->SetColorLevel(m_cornerInfo.win_level); this->SetColorWindow(m_cornerInfo.win_width); - //this->GetRenderer()->ResetCamera(); - this->SetSliceOrientationToXY(); this->Render(); //first render will call resetcamera this->SetSlice(0); UpdateCornerInfoAll(); @@ -208,7 +231,6 @@ void DICOMImageViewer::SetRenderer(vtkRenderer *arg) { } this->InstallPipeline(); - this->UpdateOrientation(); } void DICOMImageViewer::SetInputData(vtkImageData *in) { @@ -315,33 +337,6 @@ void DICOMImageViewer::Render() { vtkAlgorithm *input = this->GetInputAlgorithm(); if (input) { input->UpdateInformation(); - int *w_ext = - this->GetInputInformation()->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); - int xs = 0, ys = 0; - - switch (this->SliceOrientation) { - case DICOMImageViewer::SLICE_ORIENTATION_XY: - default: - xs = w_ext[1] - w_ext[0] + 1; - ys = w_ext[3] - w_ext[2] + 1; - break; - - case DICOMImageViewer::SLICE_ORIENTATION_XZ: - xs = w_ext[1] - w_ext[0] + 1; - ys = w_ext[5] - w_ext[4] + 1; - break; - - case DICOMImageViewer::SLICE_ORIENTATION_YZ: - xs = w_ext[3] - w_ext[2] + 1; - ys = w_ext[5] - w_ext[4] + 1; - break; - } - - // if it would be smaller than 150 by 100 then limit to 150 by 100 - if (this->RenderWindow->GetSize()[0] == 0) { - this->RenderWindow->SetSize(xs < 150 ? 150 : xs, ys < 100 ? 100 : ys); - } - if (this->Renderer) { this->Renderer->ResetCamera(); auto camera = this->Renderer->GetActiveCamera(); @@ -354,12 +349,6 @@ void DICOMImageViewer::Render() { int currentIndex = ImageMapper->GetSliceNumber(); if (currentIndex != lastIndex) this->SetSlice(lastIndex); ResetZoomScaleToFitWindowSize(); -// this->Renderer->GetActiveCamera()->SetParallelScale(xs < 150 ? 75 : (xs - 1) / 2.0); - //calibration of image by VFlip - //this->Renderer->GetActiveCamera()->Elevation(-180); - //this->Renderer->GetActiveCamera()->Roll(180); - //this->Renderer->ResetCameraClippingRange(); - } this->FirstRender = 0; } @@ -387,8 +376,8 @@ void DICOMImageViewer::GetSliceRange(int &min, int &max) { input->UpdateInformation(); int *w_ext = input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); - min = w_ext[this->SliceOrientation * 2]; - max = w_ext[this->SliceOrientation * 2 + 1]; + min = w_ext[this->SliceIJK * 2]; + max = w_ext[this->SliceIJK * 2 + 1]; } } @@ -397,7 +386,7 @@ int *DICOMImageViewer::GetSliceRange() { if (input) { input->UpdateInformation(); return input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) + - this->SliceOrientation * 2; + this->SliceIJK * 2; } return nullptr; } @@ -452,8 +441,8 @@ void DICOMImageViewer::SetSlice(int slice) { double *origin = outInfo->Get(vtkDataObject::ORIGIN()); double *pos = camera->GetPosition(); - double newFocalPoint = origin[SliceOrientation] + Slice * spacing[SliceOrientation]; - double newDistance = fabs(newFocalPoint - pos[SliceOrientation]); + double newFocalPoint = origin[SliceIJK] + Slice * spacing[SliceIJK]; + double newDistance = fabs(newFocalPoint - pos[SliceIJK]); double offset = fabs(newDistance - camera->GetDistance()); camera->SetDistance(newDistance); if (Fusion && FusionMapper) { @@ -488,8 +477,8 @@ void DICOMImageViewer::GetSlicePoint(double *point) { } void DICOMImageViewer::applySliceOffset(double offset, double direction){ - double projV = Renderer->GetActiveCamera()->GetDirectionOfProjection()[SliceOrientation]; - double defaultProjV = defaultProjection[SliceOrientation][SliceOrientation]; + double projV = Renderer->GetActiveCamera()->GetDirectionOfProjection()[SliceIJK]; + double defaultProjV = defaultProjection[SliceIJK][SliceIJK]; // 根据投影向量判断当前镜头方向, innerDirection>0 与默认同向, innerDirection<0 与默认反向 // 与默认相同时距离额的正增长为slice+ double innerDirection = projV * defaultProjV; @@ -508,20 +497,20 @@ vtkPoints* DICOMImageViewer::GetSliceBoundPoints() { vtkCamera *camera = this->Renderer->GetActiveCamera(); double fpt[3] = {.0, .0, .0}; camera->GetFocalPoint(fpt); - bounds[SliceOrientation * 2] = fpt[SliceOrientation]; - bounds[SliceOrientation * 2+1] = fpt[SliceOrientation]; + bounds[SliceIJK * 2] = fpt[SliceIJK]; + bounds[SliceIJK * 2 + 1] = fpt[SliceIJK]; vtkSmartPointer pts = vtkSmartPointer::New(); //只取4个点 pts->InsertNextPoint(bounds[0], bounds[2], bounds[4]); - if (SliceOrientation != 1) { + if (SliceIJK != 1) { pts->InsertNextPoint(bounds[0], bounds[3], bounds[4]); - if (SliceOrientation != 2) { + if (SliceIJK != 2) { pts->InsertNextPoint(bounds[0], bounds[3], bounds[5]); pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]); } } - if (SliceOrientation != 0) { - if (SliceOrientation != 1) { + if (SliceIJK != 0) { + if (SliceIJK != 1) { pts->InsertNextPoint(bounds[1], bounds[3], bounds[4]); pts->InsertNextPoint(bounds[1], bounds[2], bounds[4]); } else { @@ -565,7 +554,7 @@ void DICOMImageViewer::SyncSlicePoint(double *point) { Renderer->GetActiveCamera()->GetFocalPoint(f); double bounds[6] = {.0, .0, .0, .0, .0, .0}; ImageMapper->GetBounds(bounds); - f[SliceOrientation] = focusPoint[SliceOrientation]; + f[SliceIJK] = focusPoint[SliceIJK]; Renderer->GetActiveCamera()->SetFocalPoint(f); this->Render(); UpdateTopLeftCornerInfo(); @@ -635,10 +624,10 @@ void DICOMImageViewer::shiftCamera(const double *point) { double fp[3] = {0.0, 0.0, 0.0}; double newP[3] = {point[0], point[1], point[2]}; Renderer->GetActiveCamera()->GetPosition(fp); - newP[SliceOrientation] = fp[2]; + newP[SliceIJK] = fp[2]; Renderer->GetActiveCamera()->SetPosition(newP); Renderer->GetActiveCamera()->GetFocalPoint(fp); - newP[SliceOrientation] = fp[2]; + newP[SliceIJK] = fp[2]; Renderer->GetActiveCamera()->SetFocalPoint(newP); } @@ -994,7 +983,7 @@ void DICOMImageViewer::LoadMeasures(bool forceReload) { } void DICOMImageViewer::ReloadCurrentSliceMeasure() { - list = measureStore->GetMeasures(SOP_UID, this->SliceOrientation, ImageMapper->GetSliceNumber()); + list = measureStore->GetMeasures(SOP_UID, this->SliceIJK, ImageMapper->GetSliceNumber()); if (list) { for (int i = 0; i < list->length(); i++) { @@ -1018,7 +1007,7 @@ void DICOMImageViewer::ClearCurrentSliceMeasure() const { void DICOMImageViewer::AddMeasures(vtkObject *, unsigned long eventid, void *calldata) { auto m = static_cast(calldata); if (m->Valid()) { - measureStore->Store(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber(), m); + measureStore->Store(SOP_UID, this->SliceIJK, this->ImageMapper->GetSliceNumber(), m); } LoadMeasures(true); this->Render(); @@ -1044,7 +1033,7 @@ void DICOMImageViewer::DeleteSelectedMeasure() { void DICOMImageViewer::DeleteCurrentSliceMeasure() { this->InteractorStyle->ClearSelectedProp(); ClearCurrentSliceMeasure(); - measureStore->RemoveAllInSlice(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber()); + measureStore->RemoveAllInSlice(SOP_UID, this->SliceIJK, this->ImageMapper->GetSliceNumber()); ReloadCurrentSliceMeasure(); this->Render(); } @@ -1116,10 +1105,13 @@ void DICOMImageViewer::InitCornerInfo(ExtendMedicalImageProperties *pSeries) { m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); } -void DICOMImageViewer::SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) const { +void DICOMImageViewer::SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) { OrientationMatrix->DeepCopy(pSeries->GetOrientationMatrix()); WorldToModelMatrix->DeepCopy(pSeries->GetWorldToModelMatrix()); ModelToWorldMatrix->DeepCopy(pSeries->GetModelToWorldMatrix()); + SliceIJK = 2; + SlicePlane = -1; + SetReconPlane(GetReconPlane()); } void DICOMImageViewer::InitTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &ser_num) { @@ -1196,18 +1188,18 @@ void DICOMImageViewer::UpdateTopLeftCornerInfo() { } // SliceOrientation------------------------------------------------------------ -void DICOMImageViewer::SetSliceOrientation(int orientation) { - if (orientation < DICOMImageViewer::SLICE_ORIENTATION_YZ || - orientation > DICOMImageViewer::SLICE_ORIENTATION_XY) { - vtkErrorMacro("Error - invalid slice orientation " << orientation); +void DICOMImageViewer::SetReconPlane(int plane) { + if (plane < DICOMImageViewer::CORONAL || + plane > DICOMImageViewer::AXIAL) { + vtkErrorMacro("Error - invalid slice plane " << plane); return; } - if (this->SliceOrientation == orientation) { + if (this->SlicePlane == plane) { return; } - this->SliceOrientation = orientation; + this->SlicePlane = plane; // Update the viewer @@ -1216,7 +1208,7 @@ void DICOMImageViewer::SetSliceOrientation(int orientation) { this->Slice = static_cast((range[0] + range[1]) * 0.5); } - this->UpdateOrientation(); + this->UpdateReconPlane(); UpdateOrientationInfo(); // this->UpdateDisplayExtent(); @@ -1230,48 +1222,77 @@ void DICOMImageViewer::SetSliceOrientation(int orientation) { SetSlice(0); } -//TODO:暂时只有正交数据!!!否则强制转型会有一些问题 -int DICOMImageViewer::GetWorldSliceOrientation() { - double orientations[4] = {.0, .0, .0, 1.0}; - orientations[SliceOrientation] = 1.0; - OrientationMatrix->MultiplyPoint(orientations, orientations); - return (int) abs(round(1.0 * orientations[1]) + round(2.0 * orientations[2])); +int DICOMImageViewer::GetReconPlane() { + if (SlicePlane>=0) return SlicePlane; + double projVector[4] = {.0, .0, .0, 1.0}; + projVector[SliceIJK] = 1.0; + OrientationMatrix->MultiplyPoint(projVector, projVector); + int ret = 0; + ::adjustVector(projVector, ret); + return ::projToPlane(ret); } -// Orientation (with corner text)---------------------------------------------- -void DICOMImageViewer::UpdateOrientation() { - // Set the camera position +void DICOMImageViewer::UpdateReconPlane() { + // Set the camera position vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr; + if (cam) { - switch (SliceOrientation) { - case DICOMImageViewer::SLICE_ORIENTATION_XY: { + OrientationMatrix->Invert(); + switch (SlicePlane) { + case CORONAL: { cam->SetFocalPoint(0, 0, 0); - cam->SetPosition(0, 0, -1); - cam->SetViewUp(0, -1, 0); + double position[4]={.0, -1.0, .0, 1.0}; + OrientationMatrix->MultiplyPoint(position,position); + ::adjustVector(position, SliceIJK); + //原图非切片直接使用原方向 + if (SliceIJK == 2)break; + cam->SetPosition(position); + double viewUp[4]={.0, .0, 1.0, 1.0}; + OrientationMatrix->MultiplyPoint(viewUp,viewUp); + adjustVector(viewUp); + cam->SetViewUp(viewUp); break; } - //Z轴负数间隔,则Z轴的slice为反方向堆叠 - //初始的朝向和ViewUp都需要调整 - case DICOMImageViewer::SLICE_ORIENTATION_XZ: { - double zVec = GetInput()->GetSpacing()[2]; - double upVal = (zVec > 0.0 ? 1.0 : -1.0); + case AXIAL: { cam->SetFocalPoint(0, 0, 0); - cam->SetPosition(0, 1 * upVal, 0); - cam->SetViewUp(0, 0, -1.0 * upVal); + double position[4] = {.0, .0, -1.0, 1.0}; + OrientationMatrix->MultiplyPoint(position, position); + ::adjustVector(position, SliceIJK); + //原图非切片直接使用原方向 + if (SliceIJK == 2)break; + cam->SetPosition(position); + double viewUp[4] = {.0, -1.0, 0.0, 1.0}; + OrientationMatrix->MultiplyPoint(viewUp, viewUp); + adjustVector(viewUp); + cam->SetViewUp(viewUp); break; } - case DICOMImageViewer::SLICE_ORIENTATION_YZ: { - double zVec = GetInput()->GetSpacing()[2]; - double upVal = (zVec > 0.0 ? 1.0 : -1.0); + case SAGITTAL: { cam->SetFocalPoint(0, 0, 0); - cam->SetPosition(-1 * upVal, 0, 0); - cam->SetViewUp(0, 0, -1.0 * upVal); + double position[4] = {1.0, .0, .0, 1.0}; + OrientationMatrix->MultiplyPoint(position, position); + ::adjustVector(position, SliceIJK); + //原图非切片直接使用原方向 + if (SliceIJK == 2)break; + cam->SetPosition(position); + double viewUp[4] = {.0, .0, 1.0, 1.0}; + OrientationMatrix->MultiplyPoint(viewUp, viewUp); + adjustVector(viewUp); + cam->SetViewUp(viewUp); break; } } + OrientationMatrix->Invert(); + if (SliceIJK == 2){ + double position[3]={.0, 0, -1.0}; + cam->SetPosition(position); + double viewUp[4] = {.0, -1.0, .0, 1.0}; + cam->SetViewUp(viewUp); + } } + } int getOrientationIndex(double *v) { @@ -1364,7 +1385,7 @@ void DICOMImageViewer::PrintSelf(ostream &os, vtkIndent indent) { os << indent << "ImageMapper:\n" << endl; this->ImageMapper->PrintSelf(os, indent.GetNextIndent()); os << indent << "Slice: " << this->Slice << endl; - os << indent << "SliceOrientation: " << this->SliceOrientation << endl; + os << indent << "SliceIJK: " << this->SliceIJK << endl; os << indent << "InteractorStyle: " << endl; if (this->InteractorStyle) { os << "\n"; diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.h b/src/src/Rendering/Viewer/DICOMImageViewer.h index 8d44462..6aaa061 100644 --- a/src/src/Rendering/Viewer/DICOMImageViewer.h +++ b/src/src/Rendering/Viewer/DICOMImageViewer.h @@ -109,29 +109,17 @@ public: * Set/get the slice orientation */ - enum { - SLICE_ORIENTATION_YZ = 0, - SLICE_ORIENTATION_XZ = 1, - SLICE_ORIENTATION_XY = 2 + enum SlicePlane{ + CORONAL = 0, //冠状面 + SAGITTAL = 1, //矢状面 + AXIAL = 2, //横断面 }; - vtkGetMacro(SliceOrientation, int); + vtkGetMacro(SliceIJK, int); - virtual void SetSliceOrientation(int orientation); + virtual void SetReconPlane(int plane); - virtual void SetSliceOrientationToXY() { - this->SetSliceOrientation(DICOMImageViewer::SLICE_ORIENTATION_XY); - } - - virtual void SetSliceOrientationToYZ() { - this->SetSliceOrientation(DICOMImageViewer::SLICE_ORIENTATION_YZ); - } - - virtual void SetSliceOrientationToXZ() { - this->SetSliceOrientation(DICOMImageViewer::SLICE_ORIENTATION_XZ); - } - - int GetWorldSliceOrientation(); + int GetReconPlane(); //@{ /** * Set/Get the current slice to display (depending on the orientation @@ -391,9 +379,9 @@ public: void applySliceOffset(double offset, double direction); - virtual void UpdateOrientation(); + virtual void UpdateReconPlane(); - void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) const; + void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries); protected: DICOMImageViewer(); @@ -465,7 +453,8 @@ private: vtkNew ModelToWorldMatrix; DicomCornerInfo m_cornerInfo; - int SliceOrientation; + int SliceIJK; + int SlicePlane; int FirstRender; int Slice; int loadedMeasureSlice; diff --git a/src/src/UI/Manager/ImageViewManager.cpp b/src/src/UI/Manager/ImageViewManager.cpp index 3276021..e8eec2a 100644 --- a/src/src/UI/Manager/ImageViewManager.cpp +++ b/src/src/UI/Manager/ImageViewManager.cpp @@ -139,7 +139,7 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico if (!v->hasSeries()) return; //check series auto series = sourceView->getSeriesInstance(); - if (v->getSeriesInstance() == series && v->getSliceOrientation() == sourceView->getSliceOrientation()) { + if (v->getSeriesInstance() == series && v->getReconPlane() == sourceView->getReconPlane()) { cb(v, callData); } else{ @@ -159,14 +159,14 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico //same series if (series == currentSeries //equal slice orientation - && v->getSliceOrientation() == sourceView->getSliceOrientation()) { + && v->getReconPlane() == sourceView->getReconPlane()) { cb(v, callData); return; } //equal study else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0 //equal world slice orientation - && v->CompareWorldSliceOrientation(sourceView) + && v->CompareReconPlane(sourceView) //Intersect bounds && currentSeries->IntersectWorldBounds(series)) { cb(v, callData); @@ -181,7 +181,7 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico if (v == sourceView) return; if (!v->hasSeries()) return; //same series - if (v->CompareWorldSliceOrientation(sourceView)) { + if (v->CompareReconPlane(sourceView)) { cb(v, callData); } else if (otherCb) otherCb(v, callData); @@ -199,14 +199,14 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico //same series if (series == currentSeries //equal slice orientation - && v->getSliceOrientation() != sourceView->getSliceOrientation()) { + && v->getReconPlane() != sourceView->getReconPlane()) { cb(v, callData); return; } //equal study else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0 //no equal world slice orientation - && !v->CompareWorldSliceOrientation(sourceView) + && !v->CompareReconPlane(sourceView) //Intersect bounds && currentSeries->IntersectWorldBounds(series)) { cb(v, callData); @@ -425,8 +425,8 @@ void ImageViewManager::deleteMeasure(EventObject* deleteType){ } } -void ImageViewManager::switchSliceOrientation() { - currentView->setSliceOrientation((currentView->getSliceOrientation() + 1) % 3); +void ImageViewManager::changeReconPlane(int plane) { + currentView->setReconPlane(plane); reloadCurrentView(currentView); } diff --git a/src/src/UI/Manager/ImageViewManager.h b/src/src/UI/Manager/ImageViewManager.h index 447be4b..c5f1be3 100644 --- a/src/src/UI/Manager/ImageViewManager.h +++ b/src/src/UI/Manager/ImageViewManager.h @@ -86,7 +86,7 @@ public: void deleteMeasure(EventObject* deleteType); - void switchSliceOrientation(); + void changeReconPlane(int plane); void switchReferenceLineVisibility(bool v); diff --git a/src/src/UI/Manager/ImageViewStateCheckWorker.cpp b/src/src/UI/Manager/ImageViewStateCheckWorker.cpp index d7b9419..1e397b1 100644 --- a/src/src/UI/Manager/ImageViewStateCheckWorker.cpp +++ b/src/src/UI/Manager/ImageViewStateCheckWorker.cpp @@ -21,7 +21,7 @@ void ImageViewStateCheckWorker::checkImageViewState(DicomImageView *view) { ViewFunctionState state; if (view->hasSeries()){ state.canSync=mManager->checkSyncAbility(view); - state.canMPR=view->checkMPRAble(); + state.canMPR= view->checkMPRAble() ? view->getReconPlane() : -1; state.canFusion=mManager->checkViewFusion(view); emit imageViewStateChanged(state); } diff --git a/src/src/UI/Manager/ImageViewStateCheckWorker.h b/src/src/UI/Manager/ImageViewStateCheckWorker.h index b12253d..3874d51 100644 --- a/src/src/UI/Manager/ImageViewStateCheckWorker.h +++ b/src/src/UI/Manager/ImageViewStateCheckWorker.h @@ -12,7 +12,7 @@ class ImageViewManager; struct ViewFunctionState{ int canSync; - bool canMPR; + int canMPR; bool canFusion; }; diff --git a/src/src/UI/Widget/ImageView/dicomimageview.cpp b/src/src/UI/Widget/ImageView/dicomimageview.cpp index c77c9e6..9c85b9f 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.cpp +++ b/src/src/UI/Widget/ImageView/dicomimageview.cpp @@ -22,8 +22,8 @@ DicomImageView::DicomImageView(QWidget *parent) : QFrame(parent), mGLRenWin(vtkSmartPointer::New()), mImageViewer(nullptr), mSeries(nullptr), mScrollBar(new ClickableScrollBar(Qt::Orientation::Vertical, this)), - mTitleBar(createMyTitleBar()), mGLWidget(new QVTKOpenGLNativeWidget),mVcrToolbar(nullptr), mVcrController(nullptr), - mOverlayView(nullptr), mBaseView(nullptr), mSliceOrientation(2), mIsCine(false), mIsNegative(false), + mTitleBar(createMyTitleBar()), mGLWidget(new QVTKOpenGLNativeWidget), mVcrToolbar(nullptr), mVcrController(nullptr), + mOverlayView(nullptr), mBaseView(nullptr), mIsCine(false), mIsNegative(false), mIsOverlay(false), mIsSlotInited(false) { //main container @@ -467,14 +467,15 @@ void DicomImageView::render() { } -int DicomImageView::getSliceOrientation() { - return mSliceOrientation; +int DicomImageView::getReconPlane() { + return mImageViewer->GetReconPlane(); } -void DicomImageView::setSliceOrientation(int orientation) { +void DicomImageView::setReconPlane(int plane) { + if (mImageViewer->GetReconPlane() == plane) return; unloadFusion(); - mSliceOrientation = orientation; - mImageViewer->SetSliceOrientation(orientation); + + mImageViewer->SetReconPlane(plane); int max = 0; int min = 0; mImageViewer->GetSliceRange(min, max); @@ -627,7 +628,7 @@ void DicomImageView::ClearTransformations() { if (hasSeries()) { int slice = mImageViewer->GetSlice(); //reset flip and rotation - mImageViewer->UpdateOrientation(); + mImageViewer->UpdateReconPlane(); resetPanZoom(); //avoid black out problem mImageViewer->GetRenderer()->ResetCameraClippingRange(); @@ -765,7 +766,7 @@ bool DicomImageView::checkFusion(DicomImageView *base, DicomImageView *overlap) // check intersect if(!baseSeries->IntersectWorldBounds(overlapSeries)) return false; // check current slice orientation - return base->CompareWorldSliceOrientation(overlap); + return base->CompareReconPlane(overlap); } bool DicomImageView::checkFusion(DicomImageView *overlap) { diff --git a/src/src/UI/Widget/ImageView/dicomimageview.h b/src/src/UI/Widget/ImageView/dicomimageview.h index 699f07d..a2cb3d0 100644 --- a/src/src/UI/Widget/ImageView/dicomimageview.h +++ b/src/src/UI/Widget/ImageView/dicomimageview.h @@ -158,12 +158,12 @@ public: void negativeWindow(); //MPR - void setSliceOrientation(int orientation); + void setReconPlane(int plane); - int getSliceOrientation(); + int getReconPlane(); - bool CompareWorldSliceOrientation(DicomImageView *view) { - return this->mImageViewer->GetWorldSliceOrientation() == view->mImageViewer->GetWorldSliceOrientation(); + bool CompareReconPlane(DicomImageView *view) { + return this->mImageViewer->GetReconPlane() == view->mImageViewer->GetReconPlane(); } void syncSlicePoint(double *point) { @@ -334,8 +334,6 @@ private: DicomImageView *mOverlayView; DicomImageView *mBaseView; - int mSliceOrientation; - bool mIsCine; bool mIsNegative; bool mIsOverlay; diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp index dcfcb97..3963e3e 100644 --- a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp +++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Rendering/Measure/Measure.h" #include "Common/QGlobals.h" @@ -407,12 +408,36 @@ void DefaultToolBar::initTransformButton() { } void DefaultToolBar::initMPRButton(){ - connect(mBtnMPR, &QToolButton::clicked, [=](){ - SyncHelper::setSyncState(DIS_SYNC); - syncStateChanged(); - emit changeSliceOrientation(); + mBtnMPR->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + mBtnMPR->setToolTip(QString("MPR")); + QMenu *m = new QMenu(this); + auto group = new QActionGroup(this); + auto actionCoronal = m->addAction(tr("Coronal")); + auto actionSagittal =m->addAction(tr("Sagittal")); + auto actionAxial = m->addAction(tr("Axial")); + actionCoronal->setCheckable(true); + actionSagittal->setCheckable(true); + actionAxial->setCheckable(true); + + connect(group, &QActionGroup::triggered, this, [=](QAction* action) { + for (int i = 0; i < 3; ++i) { + if (m->actions()[i]==action){ + emit changeReconPlane(i); + return; + } + } }); + + group->addAction(actionCoronal); + group->addAction(actionSagittal); + group->addAction(actionAxial); + group->setExclusive(true); mBtnMPR->setEnabled(false); + mBtnMPR->setPopupMode(QToolButton::MenuButtonPopup); + mBtnMPR->setMenu(m); + connect(mBtnMPR, &QToolButton::clicked,[=](){ + m->popup( mBtnMPR->mapToGlobal({0, mBtnMPR->geometry().bottom()})); + }); } void DefaultToolBar::resetNeedCheckFunctionButtons(){ @@ -425,7 +450,18 @@ void DefaultToolBar::resetNeedCheckFunctionButtons(){ void DefaultToolBar::updateNeedCheckFunctionButtons(ViewFunctionState state) { - mBtnMPR->setEnabled(state.canMPR); + mBtnMPR->setEnabled(state.canMPR!=-1); + if (state.canMPR!=-1){ + for (int i = 0; i < 3; ++i) { + if (i==state.canMPR){ + mBtnMPR->menu()->actions()[i]->setEnabled(false); + } + else{ + mBtnMPR->menu()->actions()[i]->setEnabled(true); + } + } + mBtnMPR->menu()->actions()[state.canMPR]->setChecked(true); + } mBtnFusion->setEnabled(state.canFusion); // SyncHelper::setSyncState((SyncState)state.canSync); // syncStateChanged(); diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.h b/src/src/UI/Widget/ToolBar/DefaultToolBar.h index 2009c1c..9af0093 100644 --- a/src/src/UI/Widget/ToolBar/DefaultToolBar.h +++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.h @@ -33,7 +33,7 @@ signals: void negativeWindow(); void fusion(bool on = false); void cine(bool on = false); - void changeSliceOrientation(); + void changeReconPlane(int plane); void clear(); void parentWindowStateChange(Qt::WindowState state); void parentWindowClose(); diff --git a/src/src/UI/Window/QDicomViewer.cpp b/src/src/UI/Window/QDicomViewer.cpp index 7f08022..ce3f154 100644 --- a/src/src/UI/Window/QDicomViewer.cpp +++ b/src/src/UI/Window/QDicomViewer.cpp @@ -172,8 +172,8 @@ void QDicomViewer::initViewOperation() { } }); // MPR - connect(ui->toolBar, &DefaultToolBar::changeSliceOrientation, - ui->viewContainer->getViewManager(), &ImageViewManager::switchSliceOrientation); + connect(ui->toolBar, &DefaultToolBar::changeReconPlane, + ui->viewContainer->getViewManager(), &ImageViewManager::changeReconPlane); connect(ui->toolBar, &DefaultToolBar::volumeRendering,[=](){ auto volumeWin = new VolumeRenderingWindow(this); connect(volumeWin,&QDialog::finished,[=](){