MPR menu button.
This commit is contained in:
@@ -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<vtkPoints> pts = vtkSmartPointer<vtkPoints>::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<Measure *>(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<int>((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";
|
||||
|
||||
@@ -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<vtkMatrix4x4> ModelToWorldMatrix;
|
||||
|
||||
DicomCornerInfo m_cornerInfo;
|
||||
int SliceOrientation;
|
||||
int SliceIJK;
|
||||
int SlicePlane;
|
||||
int FirstRender;
|
||||
int Slice;
|
||||
int loadedMeasureSlice;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
|
||||
void deleteMeasure(EventObject* deleteType);
|
||||
|
||||
void switchSliceOrientation();
|
||||
void changeReconPlane(int plane);
|
||||
|
||||
void switchReferenceLineVisibility(bool v);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class ImageViewManager;
|
||||
|
||||
struct ViewFunctionState{
|
||||
int canSync;
|
||||
bool canMPR;
|
||||
int canMPR;
|
||||
bool canFusion;
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
DicomImageView::DicomImageView(QWidget *parent)
|
||||
: QFrame(parent), mGLRenWin(vtkSmartPointer<vtkGenericOpenGLRenderWindow>::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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QToolButton>
|
||||
#include <QMenu>
|
||||
#include <QButtonGroup>
|
||||
#include <QActionGroup>
|
||||
#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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,[=](){
|
||||
|
||||
Reference in New Issue
Block a user