MPR menu button.

This commit is contained in:
Krad
2022-08-24 10:51:00 +08:00
parent 12bc958c4a
commit 203ab67002
11 changed files with 191 additions and 146 deletions

View File

@@ -27,6 +27,31 @@
#include "IO/General/ColorMapReader.h" #include "IO/General/ColorMapReader.h"
#include "Interaction/ActorDraggableInteractorStyle.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); vtkStandardNewMacro(DICOMImageViewer);
@@ -37,7 +62,7 @@ DICOMImageViewer::DICOMImageViewer()
ImageActor(vtkImageSlice::New()), ImageMapper(vtkImageSliceMapper::New()), FusionActor(nullptr), ImageActor(vtkImageSlice::New()), ImageMapper(vtkImageSliceMapper::New()), FusionActor(nullptr),
FusionMapper(nullptr), Interactor(nullptr), InteractorStyle(nullptr), OpacityActor(nullptr), FusionMapper(nullptr), Interactor(nullptr), InteractorStyle(nullptr), OpacityActor(nullptr),
cornerAnnotation(vtkCornerAnnotation::New()), bar(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), currentPresetIndex(1), Fusion(false), firstFusion(true), FusionOpacity(0.5), list(nullptr),
measureStore(MeasureStore::Instance()), measureStore(MeasureStore::Instance()),
rulerActive(false){ rulerActive(false){
@@ -125,8 +150,6 @@ DICOMImageViewer::~DICOMImageViewer() {
void DICOMImageViewer::SetupImageViewer() { void DICOMImageViewer::SetupImageViewer() {
this->SetColorLevel(m_cornerInfo.win_level); this->SetColorLevel(m_cornerInfo.win_level);
this->SetColorWindow(m_cornerInfo.win_width); this->SetColorWindow(m_cornerInfo.win_width);
//this->GetRenderer()->ResetCamera();
this->SetSliceOrientationToXY();
this->Render(); //first render will call resetcamera this->Render(); //first render will call resetcamera
this->SetSlice(0); this->SetSlice(0);
UpdateCornerInfoAll(); UpdateCornerInfoAll();
@@ -208,7 +231,6 @@ void DICOMImageViewer::SetRenderer(vtkRenderer *arg) {
} }
this->InstallPipeline(); this->InstallPipeline();
this->UpdateOrientation();
} }
void DICOMImageViewer::SetInputData(vtkImageData *in) { void DICOMImageViewer::SetInputData(vtkImageData *in) {
@@ -315,33 +337,6 @@ void DICOMImageViewer::Render() {
vtkAlgorithm *input = this->GetInputAlgorithm(); vtkAlgorithm *input = this->GetInputAlgorithm();
if (input) { if (input) {
input->UpdateInformation(); 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) { if (this->Renderer) {
this->Renderer->ResetCamera(); this->Renderer->ResetCamera();
auto camera = this->Renderer->GetActiveCamera(); auto camera = this->Renderer->GetActiveCamera();
@@ -354,12 +349,6 @@ void DICOMImageViewer::Render() {
int currentIndex = ImageMapper->GetSliceNumber(); int currentIndex = ImageMapper->GetSliceNumber();
if (currentIndex != lastIndex) this->SetSlice(lastIndex); if (currentIndex != lastIndex) this->SetSlice(lastIndex);
ResetZoomScaleToFitWindowSize(); 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; this->FirstRender = 0;
} }
@@ -387,8 +376,8 @@ void DICOMImageViewer::GetSliceRange(int &min, int &max) {
input->UpdateInformation(); input->UpdateInformation();
int *w_ext = int *w_ext =
input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT());
min = w_ext[this->SliceOrientation * 2]; min = w_ext[this->SliceIJK * 2];
max = w_ext[this->SliceOrientation * 2 + 1]; max = w_ext[this->SliceIJK * 2 + 1];
} }
} }
@@ -397,7 +386,7 @@ int *DICOMImageViewer::GetSliceRange() {
if (input) { if (input) {
input->UpdateInformation(); input->UpdateInformation();
return input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) + return input->GetOutputInformation(0)->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()) +
this->SliceOrientation * 2; this->SliceIJK * 2;
} }
return nullptr; return nullptr;
} }
@@ -452,8 +441,8 @@ void DICOMImageViewer::SetSlice(int slice) {
double *origin = outInfo->Get(vtkDataObject::ORIGIN()); double *origin = outInfo->Get(vtkDataObject::ORIGIN());
double *pos = camera->GetPosition(); double *pos = camera->GetPosition();
double newFocalPoint = origin[SliceOrientation] + Slice * spacing[SliceOrientation]; double newFocalPoint = origin[SliceIJK] + Slice * spacing[SliceIJK];
double newDistance = fabs(newFocalPoint - pos[SliceOrientation]); double newDistance = fabs(newFocalPoint - pos[SliceIJK]);
double offset = fabs(newDistance - camera->GetDistance()); double offset = fabs(newDistance - camera->GetDistance());
camera->SetDistance(newDistance); camera->SetDistance(newDistance);
if (Fusion && FusionMapper) { if (Fusion && FusionMapper) {
@@ -488,8 +477,8 @@ void DICOMImageViewer::GetSlicePoint(double *point) {
} }
void DICOMImageViewer::applySliceOffset(double offset, double direction){ void DICOMImageViewer::applySliceOffset(double offset, double direction){
double projV = Renderer->GetActiveCamera()->GetDirectionOfProjection()[SliceOrientation]; double projV = Renderer->GetActiveCamera()->GetDirectionOfProjection()[SliceIJK];
double defaultProjV = defaultProjection[SliceOrientation][SliceOrientation]; double defaultProjV = defaultProjection[SliceIJK][SliceIJK];
// 根据投影向量判断当前镜头方向, innerDirection>0 与默认同向, innerDirection<0 与默认反向 // 根据投影向量判断当前镜头方向, innerDirection>0 与默认同向, innerDirection<0 与默认反向
// 与默认相同时距离额的正增长为slice+ // 与默认相同时距离额的正增长为slice+
double innerDirection = projV * defaultProjV; double innerDirection = projV * defaultProjV;
@@ -508,20 +497,20 @@ vtkPoints* DICOMImageViewer::GetSliceBoundPoints() {
vtkCamera *camera = this->Renderer->GetActiveCamera(); vtkCamera *camera = this->Renderer->GetActiveCamera();
double fpt[3] = {.0, .0, .0}; double fpt[3] = {.0, .0, .0};
camera->GetFocalPoint(fpt); camera->GetFocalPoint(fpt);
bounds[SliceOrientation * 2] = fpt[SliceOrientation]; bounds[SliceIJK * 2] = fpt[SliceIJK];
bounds[SliceOrientation * 2+1] = fpt[SliceOrientation]; bounds[SliceIJK * 2 + 1] = fpt[SliceIJK];
vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New(); vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New();
//只取4个点 //只取4个点
pts->InsertNextPoint(bounds[0], bounds[2], bounds[4]); pts->InsertNextPoint(bounds[0], bounds[2], bounds[4]);
if (SliceOrientation != 1) { if (SliceIJK != 1) {
pts->InsertNextPoint(bounds[0], bounds[3], bounds[4]); 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[3], bounds[5]);
pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]); pts->InsertNextPoint(bounds[0], bounds[2], bounds[5]);
} }
} }
if (SliceOrientation != 0) { if (SliceIJK != 0) {
if (SliceOrientation != 1) { if (SliceIJK != 1) {
pts->InsertNextPoint(bounds[1], bounds[3], bounds[4]); pts->InsertNextPoint(bounds[1], bounds[3], bounds[4]);
pts->InsertNextPoint(bounds[1], bounds[2], bounds[4]); pts->InsertNextPoint(bounds[1], bounds[2], bounds[4]);
} else { } else {
@@ -565,7 +554,7 @@ void DICOMImageViewer::SyncSlicePoint(double *point) {
Renderer->GetActiveCamera()->GetFocalPoint(f); Renderer->GetActiveCamera()->GetFocalPoint(f);
double bounds[6] = {.0, .0, .0, .0, .0, .0}; double bounds[6] = {.0, .0, .0, .0, .0, .0};
ImageMapper->GetBounds(bounds); ImageMapper->GetBounds(bounds);
f[SliceOrientation] = focusPoint[SliceOrientation]; f[SliceIJK] = focusPoint[SliceIJK];
Renderer->GetActiveCamera()->SetFocalPoint(f); Renderer->GetActiveCamera()->SetFocalPoint(f);
this->Render(); this->Render();
UpdateTopLeftCornerInfo(); UpdateTopLeftCornerInfo();
@@ -635,10 +624,10 @@ void DICOMImageViewer::shiftCamera(const double *point) {
double fp[3] = {0.0, 0.0, 0.0}; double fp[3] = {0.0, 0.0, 0.0};
double newP[3] = {point[0], point[1], point[2]}; double newP[3] = {point[0], point[1], point[2]};
Renderer->GetActiveCamera()->GetPosition(fp); Renderer->GetActiveCamera()->GetPosition(fp);
newP[SliceOrientation] = fp[2]; newP[SliceIJK] = fp[2];
Renderer->GetActiveCamera()->SetPosition(newP); Renderer->GetActiveCamera()->SetPosition(newP);
Renderer->GetActiveCamera()->GetFocalPoint(fp); Renderer->GetActiveCamera()->GetFocalPoint(fp);
newP[SliceOrientation] = fp[2]; newP[SliceIJK] = fp[2];
Renderer->GetActiveCamera()->SetFocalPoint(newP); Renderer->GetActiveCamera()->SetFocalPoint(newP);
} }
@@ -994,7 +983,7 @@ void DICOMImageViewer::LoadMeasures(bool forceReload) {
} }
void DICOMImageViewer::ReloadCurrentSliceMeasure() { void DICOMImageViewer::ReloadCurrentSliceMeasure() {
list = measureStore->GetMeasures(SOP_UID, this->SliceOrientation, ImageMapper->GetSliceNumber()); list = measureStore->GetMeasures(SOP_UID, this->SliceIJK, ImageMapper->GetSliceNumber());
if (list) { if (list) {
for (int i = 0; i < list->length(); i++) { 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) { void DICOMImageViewer::AddMeasures(vtkObject *, unsigned long eventid, void *calldata) {
auto m = static_cast<Measure *>(calldata); auto m = static_cast<Measure *>(calldata);
if (m->Valid()) { 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); LoadMeasures(true);
this->Render(); this->Render();
@@ -1044,7 +1033,7 @@ void DICOMImageViewer::DeleteSelectedMeasure() {
void DICOMImageViewer::DeleteCurrentSliceMeasure() { void DICOMImageViewer::DeleteCurrentSliceMeasure() {
this->InteractorStyle->ClearSelectedProp(); this->InteractorStyle->ClearSelectedProp();
ClearCurrentSliceMeasure(); ClearCurrentSliceMeasure();
measureStore->RemoveAllInSlice(SOP_UID, this->SliceOrientation, this->ImageMapper->GetSliceNumber()); measureStore->RemoveAllInSlice(SOP_UID, this->SliceIJK, this->ImageMapper->GetSliceNumber());
ReloadCurrentSliceMeasure(); ReloadCurrentSliceMeasure();
this->Render(); this->Render();
} }
@@ -1116,10 +1105,13 @@ void DICOMImageViewer::InitCornerInfo(ExtendMedicalImageProperties *pSeries) {
m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n"); m_cornerInfo.ConstAnno[TOP_RIGHT_PRIVACY].append("\n");
} }
void DICOMImageViewer::SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) const { void DICOMImageViewer::SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) {
OrientationMatrix->DeepCopy(pSeries->GetOrientationMatrix()); OrientationMatrix->DeepCopy(pSeries->GetOrientationMatrix());
WorldToModelMatrix->DeepCopy(pSeries->GetWorldToModelMatrix()); WorldToModelMatrix->DeepCopy(pSeries->GetWorldToModelMatrix());
ModelToWorldMatrix->DeepCopy(pSeries->GetModelToWorldMatrix()); ModelToWorldMatrix->DeepCopy(pSeries->GetModelToWorldMatrix());
SliceIJK = 2;
SlicePlane = -1;
SetReconPlane(GetReconPlane());
} }
void DICOMImageViewer::InitTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &ser_num) { void DICOMImageViewer::InitTopLeftCornerInfo(const std::string &lbl_ser_num, const std::string &ser_num) {
@@ -1196,18 +1188,18 @@ void DICOMImageViewer::UpdateTopLeftCornerInfo() {
} }
// SliceOrientation------------------------------------------------------------ // SliceOrientation------------------------------------------------------------
void DICOMImageViewer::SetSliceOrientation(int orientation) { void DICOMImageViewer::SetReconPlane(int plane) {
if (orientation < DICOMImageViewer::SLICE_ORIENTATION_YZ || if (plane < DICOMImageViewer::CORONAL ||
orientation > DICOMImageViewer::SLICE_ORIENTATION_XY) { plane > DICOMImageViewer::AXIAL) {
vtkErrorMacro("Error - invalid slice orientation " << orientation); vtkErrorMacro("Error - invalid slice plane " << plane);
return; return;
} }
if (this->SliceOrientation == orientation) { if (this->SlicePlane == plane) {
return; return;
} }
this->SliceOrientation = orientation; this->SlicePlane = plane;
// Update the viewer // Update the viewer
@@ -1216,7 +1208,7 @@ void DICOMImageViewer::SetSliceOrientation(int orientation) {
this->Slice = static_cast<int>((range[0] + range[1]) * 0.5); this->Slice = static_cast<int>((range[0] + range[1]) * 0.5);
} }
this->UpdateOrientation(); this->UpdateReconPlane();
UpdateOrientationInfo(); UpdateOrientationInfo();
// this->UpdateDisplayExtent(); // this->UpdateDisplayExtent();
@@ -1230,48 +1222,77 @@ void DICOMImageViewer::SetSliceOrientation(int orientation) {
SetSlice(0); SetSlice(0);
} }
//TODO暂时只有正交数据否则强制转型会有一些问题 int DICOMImageViewer::GetReconPlane() {
int DICOMImageViewer::GetWorldSliceOrientation() { if (SlicePlane>=0) return SlicePlane;
double orientations[4] = {.0, .0, .0, 1.0}; double projVector[4] = {.0, .0, .0, 1.0};
orientations[SliceOrientation] = 1.0; projVector[SliceIJK] = 1.0;
OrientationMatrix->MultiplyPoint(orientations, orientations); OrientationMatrix->MultiplyPoint(projVector, projVector);
return (int) abs(round(1.0 * orientations[1]) + round(2.0 * orientations[2])); 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; vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr;
if (cam) { if (cam) {
switch (SliceOrientation) { OrientationMatrix->Invert();
case DICOMImageViewer::SLICE_ORIENTATION_XY: { switch (SlicePlane) {
case CORONAL: {
cam->SetFocalPoint(0, 0, 0); cam->SetFocalPoint(0, 0, 0);
cam->SetPosition(0, 0, -1); double position[4]={.0, -1.0, .0, 1.0};
cam->SetViewUp(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; break;
} }
//Z轴负数间隔则Z轴的slice为反方向堆叠 case AXIAL: {
//初始的朝向和ViewUp都需要调整
case DICOMImageViewer::SLICE_ORIENTATION_XZ: {
double zVec = GetInput()->GetSpacing()[2];
double upVal = (zVec > 0.0 ? 1.0 : -1.0);
cam->SetFocalPoint(0, 0, 0); cam->SetFocalPoint(0, 0, 0);
cam->SetPosition(0, 1 * upVal, 0); double position[4] = {.0, .0, -1.0, 1.0};
cam->SetViewUp(0, 0, -1.0 * upVal); 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; break;
} }
case DICOMImageViewer::SLICE_ORIENTATION_YZ: { case SAGITTAL: {
double zVec = GetInput()->GetSpacing()[2];
double upVal = (zVec > 0.0 ? 1.0 : -1.0);
cam->SetFocalPoint(0, 0, 0); cam->SetFocalPoint(0, 0, 0);
cam->SetPosition(-1 * upVal, 0, 0); double position[4] = {1.0, .0, .0, 1.0};
cam->SetViewUp(0, 0, -1.0 * upVal); 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; 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) { int getOrientationIndex(double *v) {
@@ -1364,7 +1385,7 @@ void DICOMImageViewer::PrintSelf(ostream &os, vtkIndent indent) {
os << indent << "ImageMapper:\n" << endl; os << indent << "ImageMapper:\n" << endl;
this->ImageMapper->PrintSelf(os, indent.GetNextIndent()); this->ImageMapper->PrintSelf(os, indent.GetNextIndent());
os << indent << "Slice: " << this->Slice << endl; os << indent << "Slice: " << this->Slice << endl;
os << indent << "SliceOrientation: " << this->SliceOrientation << endl; os << indent << "SliceIJK: " << this->SliceIJK << endl;
os << indent << "InteractorStyle: " << endl; os << indent << "InteractorStyle: " << endl;
if (this->InteractorStyle) { if (this->InteractorStyle) {
os << "\n"; os << "\n";

View File

@@ -109,29 +109,17 @@ public:
* Set/get the slice orientation * Set/get the slice orientation
*/ */
enum { enum SlicePlane{
SLICE_ORIENTATION_YZ = 0, CORONAL = 0, //冠状面
SLICE_ORIENTATION_XZ = 1, SAGITTAL = 1, //矢状面
SLICE_ORIENTATION_XY = 2 AXIAL = 2, //横断面
}; };
vtkGetMacro(SliceOrientation, int); vtkGetMacro(SliceIJK, int);
virtual void SetSliceOrientation(int orientation); virtual void SetReconPlane(int plane);
virtual void SetSliceOrientationToXY() { int GetReconPlane();
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();
//@{ //@{
/** /**
* Set/Get the current slice to display (depending on the orientation * Set/Get the current slice to display (depending on the orientation
@@ -391,9 +379,9 @@ public:
void applySliceOffset(double offset, double direction); void applySliceOffset(double offset, double direction);
virtual void UpdateOrientation(); virtual void UpdateReconPlane();
void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries) const; void SetCoordsTransformMatrix(ExtendMedicalImageProperties *pSeries);
protected: protected:
DICOMImageViewer(); DICOMImageViewer();
@@ -465,7 +453,8 @@ private:
vtkNew<vtkMatrix4x4> ModelToWorldMatrix; vtkNew<vtkMatrix4x4> ModelToWorldMatrix;
DicomCornerInfo m_cornerInfo; DicomCornerInfo m_cornerInfo;
int SliceOrientation; int SliceIJK;
int SlicePlane;
int FirstRender; int FirstRender;
int Slice; int Slice;
int loadedMeasureSlice; int loadedMeasureSlice;

View File

@@ -139,7 +139,7 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
if (!v->hasSeries()) return; if (!v->hasSeries()) return;
//check series //check series
auto series = sourceView->getSeriesInstance(); auto series = sourceView->getSeriesInstance();
if (v->getSeriesInstance() == series && v->getSliceOrientation() == sourceView->getSliceOrientation()) { if (v->getSeriesInstance() == series && v->getReconPlane() == sourceView->getReconPlane()) {
cb(v, callData); cb(v, callData);
} }
else{ else{
@@ -159,14 +159,14 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
//same series //same series
if (series == currentSeries if (series == currentSeries
//equal slice orientation //equal slice orientation
&& v->getSliceOrientation() == sourceView->getSliceOrientation()) { && v->getReconPlane() == sourceView->getReconPlane()) {
cb(v, callData); cb(v, callData);
return; return;
} }
//equal study //equal study
else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0 else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0
//equal world slice orientation //equal world slice orientation
&& v->CompareWorldSliceOrientation(sourceView) && v->CompareReconPlane(sourceView)
//Intersect bounds //Intersect bounds
&& currentSeries->IntersectWorldBounds(series)) { && currentSeries->IntersectWorldBounds(series)) {
cb(v, callData); cb(v, callData);
@@ -181,7 +181,7 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
if (v == sourceView) return; if (v == sourceView) return;
if (!v->hasSeries()) return; if (!v->hasSeries()) return;
//same series //same series
if (v->CompareWorldSliceOrientation(sourceView)) { if (v->CompareReconPlane(sourceView)) {
cb(v, callData); cb(v, callData);
} }
else if (otherCb) otherCb(v, callData); else if (otherCb) otherCb(v, callData);
@@ -199,14 +199,14 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
//same series //same series
if (series == currentSeries if (series == currentSeries
//equal slice orientation //equal slice orientation
&& v->getSliceOrientation() != sourceView->getSliceOrientation()) { && v->getReconPlane() != sourceView->getReconPlane()) {
cb(v, callData); cb(v, callData);
return; return;
} }
//equal study //equal study
else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0 else if (strcmp(currentSeries->getStudyUID(), series->getStudyUID()) == 0
//no equal world slice orientation //no equal world slice orientation
&& !v->CompareWorldSliceOrientation(sourceView) && !v->CompareReconPlane(sourceView)
//Intersect bounds //Intersect bounds
&& currentSeries->IntersectWorldBounds(series)) { && currentSeries->IntersectWorldBounds(series)) {
cb(v, callData); cb(v, callData);
@@ -425,8 +425,8 @@ void ImageViewManager::deleteMeasure(EventObject* deleteType){
} }
} }
void ImageViewManager::switchSliceOrientation() { void ImageViewManager::changeReconPlane(int plane) {
currentView->setSliceOrientation((currentView->getSliceOrientation() + 1) % 3); currentView->setReconPlane(plane);
reloadCurrentView(currentView); reloadCurrentView(currentView);
} }

View File

@@ -86,7 +86,7 @@ public:
void deleteMeasure(EventObject* deleteType); void deleteMeasure(EventObject* deleteType);
void switchSliceOrientation(); void changeReconPlane(int plane);
void switchReferenceLineVisibility(bool v); void switchReferenceLineVisibility(bool v);

View File

@@ -21,7 +21,7 @@ void ImageViewStateCheckWorker::checkImageViewState(DicomImageView *view) {
ViewFunctionState state; ViewFunctionState state;
if (view->hasSeries()){ if (view->hasSeries()){
state.canSync=mManager->checkSyncAbility(view); state.canSync=mManager->checkSyncAbility(view);
state.canMPR=view->checkMPRAble(); state.canMPR= view->checkMPRAble() ? view->getReconPlane() : -1;
state.canFusion=mManager->checkViewFusion(view); state.canFusion=mManager->checkViewFusion(view);
emit imageViewStateChanged(state); emit imageViewStateChanged(state);
} }

View File

@@ -12,7 +12,7 @@ class ImageViewManager;
struct ViewFunctionState{ struct ViewFunctionState{
int canSync; int canSync;
bool canMPR; int canMPR;
bool canFusion; bool canFusion;
}; };

View File

@@ -22,8 +22,8 @@
DicomImageView::DicomImageView(QWidget *parent) DicomImageView::DicomImageView(QWidget *parent)
: QFrame(parent), mGLRenWin(vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New()), mImageViewer(nullptr), : QFrame(parent), mGLRenWin(vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New()), mImageViewer(nullptr),
mSeries(nullptr), mScrollBar(new ClickableScrollBar(Qt::Orientation::Vertical, this)), mSeries(nullptr), mScrollBar(new ClickableScrollBar(Qt::Orientation::Vertical, this)),
mTitleBar(createMyTitleBar()), mGLWidget(new QVTKOpenGLNativeWidget),mVcrToolbar(nullptr), mVcrController(nullptr), mTitleBar(createMyTitleBar()), mGLWidget(new QVTKOpenGLNativeWidget), mVcrToolbar(nullptr), mVcrController(nullptr),
mOverlayView(nullptr), mBaseView(nullptr), mSliceOrientation(2), mIsCine(false), mIsNegative(false), mOverlayView(nullptr), mBaseView(nullptr), mIsCine(false), mIsNegative(false),
mIsOverlay(false), mIsSlotInited(false) mIsOverlay(false), mIsSlotInited(false)
{ {
//main container //main container
@@ -467,14 +467,15 @@ void DicomImageView::render() {
} }
int DicomImageView::getSliceOrientation() { int DicomImageView::getReconPlane() {
return mSliceOrientation; return mImageViewer->GetReconPlane();
} }
void DicomImageView::setSliceOrientation(int orientation) { void DicomImageView::setReconPlane(int plane) {
if (mImageViewer->GetReconPlane() == plane) return;
unloadFusion(); unloadFusion();
mSliceOrientation = orientation;
mImageViewer->SetSliceOrientation(orientation); mImageViewer->SetReconPlane(plane);
int max = 0; int max = 0;
int min = 0; int min = 0;
mImageViewer->GetSliceRange(min, max); mImageViewer->GetSliceRange(min, max);
@@ -627,7 +628,7 @@ void DicomImageView::ClearTransformations() {
if (hasSeries()) { if (hasSeries()) {
int slice = mImageViewer->GetSlice(); int slice = mImageViewer->GetSlice();
//reset flip and rotation //reset flip and rotation
mImageViewer->UpdateOrientation(); mImageViewer->UpdateReconPlane();
resetPanZoom(); resetPanZoom();
//avoid black out problem //avoid black out problem
mImageViewer->GetRenderer()->ResetCameraClippingRange(); mImageViewer->GetRenderer()->ResetCameraClippingRange();
@@ -765,7 +766,7 @@ bool DicomImageView::checkFusion(DicomImageView *base, DicomImageView *overlap)
// check intersect // check intersect
if(!baseSeries->IntersectWorldBounds(overlapSeries)) return false; if(!baseSeries->IntersectWorldBounds(overlapSeries)) return false;
// check current slice orientation // check current slice orientation
return base->CompareWorldSliceOrientation(overlap); return base->CompareReconPlane(overlap);
} }
bool DicomImageView::checkFusion(DicomImageView *overlap) { bool DicomImageView::checkFusion(DicomImageView *overlap) {

View File

@@ -158,12 +158,12 @@ public:
void negativeWindow(); void negativeWindow();
//MPR //MPR
void setSliceOrientation(int orientation); void setReconPlane(int plane);
int getSliceOrientation(); int getReconPlane();
bool CompareWorldSliceOrientation(DicomImageView *view) { bool CompareReconPlane(DicomImageView *view) {
return this->mImageViewer->GetWorldSliceOrientation() == view->mImageViewer->GetWorldSliceOrientation(); return this->mImageViewer->GetReconPlane() == view->mImageViewer->GetReconPlane();
} }
void syncSlicePoint(double *point) { void syncSlicePoint(double *point) {
@@ -334,8 +334,6 @@ private:
DicomImageView *mOverlayView; DicomImageView *mOverlayView;
DicomImageView *mBaseView; DicomImageView *mBaseView;
int mSliceOrientation;
bool mIsCine; bool mIsCine;
bool mIsNegative; bool mIsNegative;
bool mIsOverlay; bool mIsOverlay;

View File

@@ -6,6 +6,7 @@
#include <QToolButton> #include <QToolButton>
#include <QMenu> #include <QMenu>
#include <QButtonGroup> #include <QButtonGroup>
#include <QActionGroup>
#include "Rendering/Measure/Measure.h" #include "Rendering/Measure/Measure.h"
#include "Common/QGlobals.h" #include "Common/QGlobals.h"
@@ -407,12 +408,36 @@ void DefaultToolBar::initTransformButton() {
} }
void DefaultToolBar::initMPRButton(){ void DefaultToolBar::initMPRButton(){
connect(mBtnMPR, &QToolButton::clicked, [=](){ mBtnMPR->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
SyncHelper::setSyncState(DIS_SYNC); mBtnMPR->setToolTip(QString("MPR"));
syncStateChanged(); QMenu *m = new QMenu(this);
emit changeSliceOrientation(); 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->setEnabled(false);
mBtnMPR->setPopupMode(QToolButton::MenuButtonPopup);
mBtnMPR->setMenu(m);
connect(mBtnMPR, &QToolButton::clicked,[=](){
m->popup( mBtnMPR->mapToGlobal({0, mBtnMPR->geometry().bottom()}));
});
} }
void DefaultToolBar::resetNeedCheckFunctionButtons(){ void DefaultToolBar::resetNeedCheckFunctionButtons(){
@@ -425,7 +450,18 @@ void DefaultToolBar::resetNeedCheckFunctionButtons(){
void DefaultToolBar::updateNeedCheckFunctionButtons(ViewFunctionState state) 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); mBtnFusion->setEnabled(state.canFusion);
// SyncHelper::setSyncState((SyncState)state.canSync); // SyncHelper::setSyncState((SyncState)state.canSync);
// syncStateChanged(); // syncStateChanged();

View File

@@ -33,7 +33,7 @@ signals:
void negativeWindow(); void negativeWindow();
void fusion(bool on = false); void fusion(bool on = false);
void cine(bool on = false); void cine(bool on = false);
void changeSliceOrientation(); void changeReconPlane(int plane);
void clear(); void clear();
void parentWindowStateChange(Qt::WindowState state); void parentWindowStateChange(Qt::WindowState state);
void parentWindowClose(); void parentWindowClose();

View File

@@ -172,8 +172,8 @@ void QDicomViewer::initViewOperation() {
} }
}); });
// MPR // MPR
connect(ui->toolBar, &DefaultToolBar::changeSliceOrientation, connect(ui->toolBar, &DefaultToolBar::changeReconPlane,
ui->viewContainer->getViewManager(), &ImageViewManager::switchSliceOrientation); ui->viewContainer->getViewManager(), &ImageViewManager::changeReconPlane);
connect(ui->toolBar, &DefaultToolBar::volumeRendering,[=](){ connect(ui->toolBar, &DefaultToolBar::volumeRendering,[=](){
auto volumeWin = new VolumeRenderingWindow(this); auto volumeWin = new VolumeRenderingWindow(this);
connect(volumeWin,&QDialog::finished,[=](){ connect(volumeWin,&QDialog::finished,[=](){