Slice sync logic refactor, add manual slice sync logic(camera focal point distance incremental sync).
This commit is contained in:
@@ -211,6 +211,7 @@ void infinitiViewer::SetRenderer(vtkRenderer *arg) {
|
||||
}
|
||||
|
||||
void infinitiViewer::SetInputData(vtkImageData *in) {
|
||||
if (!in) return;
|
||||
#ifdef _DEBUG
|
||||
printf("fusion imageDataOrigin:%f,%f,%f", in->GetOrigin()[0], in->GetOrigin()[1], in->GetOrigin()[2]);
|
||||
printf("fusion spacing:%f,%f,%f", in->GetSpacing()[0], in->GetSpacing()[1], in->GetSpacing()[2]);
|
||||
@@ -219,7 +220,8 @@ void infinitiViewer::SetInputData(vtkImageData *in) {
|
||||
this->ImageActor->GetMapper()->SetInputData(in);
|
||||
this->RemoveFusionData();
|
||||
this->ActiveRuler();
|
||||
// this->UpdateDisplayExtent();
|
||||
double zVec = in->GetSpacing()[2];
|
||||
defaultProjection[2][2] = zVec>0.0?1.0:-1.0;
|
||||
}
|
||||
|
||||
void infinitiViewer::SetInputConnection(vtkAlgorithmOutput *input) {
|
||||
@@ -452,15 +454,22 @@ void infinitiViewer::SetSlice(int slice) {
|
||||
double *origin = outInfo->Get(vtkDataObject::ORIGIN());
|
||||
double *pos = camera->GetPosition();
|
||||
|
||||
double npv = origin[this->SliceOrientation] + this->Slice * spacing[this->SliceOrientation];
|
||||
camera->SetDistance(fabs(npv - pos[this->SliceOrientation]));
|
||||
double newFocalPoint = origin[SliceOrientation] + Slice * spacing[SliceOrientation];
|
||||
double newDistance = fabs(newFocalPoint - pos[SliceOrientation]);
|
||||
double offset = fabs(newDistance - camera->GetDistance());
|
||||
camera->SetDistance(newDistance);
|
||||
if (Fusion && FusionMapper) {
|
||||
FusionMapper->SetClippingPlanes(ImageMapper->GetClippingPlanes());
|
||||
}
|
||||
|
||||
this->Render();
|
||||
if (InteractorStyle)
|
||||
InteractorStyle->InvokeEvent(ActorDraggableInteractorStyle::SlicedEvent, &this->Slice);
|
||||
if (InteractorStyle){
|
||||
double direction = (double)(slice - lastSliceNumber);
|
||||
double focusPoint[5] = {.0, .0, .0 };
|
||||
GetSlicePoint(focusPoint);
|
||||
double sliceData[5] ={focusPoint[0], focusPoint[1], focusPoint[2], offset, direction};
|
||||
InteractorStyle->InvokeEvent(ActorDraggableInteractorStyle::SlicedEvent, sliceData);
|
||||
}
|
||||
}
|
||||
|
||||
void infinitiViewer::ChangeSlice(vtkObject *, unsigned long eventid, void *calldata) {
|
||||
@@ -483,6 +492,19 @@ void infinitiViewer::GetSlicePoint(double *point) {
|
||||
point[2] = focusPoint[2];
|
||||
}
|
||||
|
||||
void infinitiViewer::applySliceOffset(double offset, double direction){
|
||||
double projV = Renderer->GetActiveCamera()->GetDirectionOfProjection()[SliceOrientation];
|
||||
double defaultProjV = defaultProjection[SliceOrientation][SliceOrientation];
|
||||
// 根据投影向量判断当前镜头方向, innerDirection>0 与默认同向, innerDirection<0 与默认反向
|
||||
// 与默认相同时距离额的正增长为slice+
|
||||
double innerDirection = projV * defaultProjV;
|
||||
// 否则距离的负增长会导致Slice++(即使distance + offset为slice++)
|
||||
if (innerDirection < 0 ) offset = offset * -1.0;;
|
||||
// 假设原数据为slice--则需要唯一
|
||||
if (direction < 0) offset = offset * -1.0;
|
||||
Renderer->GetActiveCamera()->SetDistance(Renderer->GetActiveCamera()->GetDistance() + offset);
|
||||
}
|
||||
|
||||
vtkSmartPointer<vtkPoints> infinitiViewer::GetSliceBoundPoints() {
|
||||
double bounds[6] = {.0, .0, .0, .0, .0, .0};
|
||||
ImageMapper->GetBounds(bounds);
|
||||
@@ -1207,19 +1229,20 @@ void infinitiViewer::UpdateOrientation() {
|
||||
|
||||
vtkCamera *cam = this->Renderer ? this->Renderer->GetActiveCamera() : nullptr;
|
||||
if (cam) {
|
||||
|
||||
switch (this->SliceOrientation) {
|
||||
switch (SliceOrientation) {
|
||||
case infinitiViewer::SLICE_ORIENTATION_XY: {
|
||||
cam->SetFocalPoint(0, 0, 0);
|
||||
cam->SetPosition(0, 0, -1); // -1 if medical ?
|
||||
cam->SetPosition(0, 0, -1);
|
||||
cam->SetViewUp(0, -1, 0);
|
||||
break;
|
||||
}
|
||||
//Z轴负数间隔,则Z轴的slice为反方向堆叠
|
||||
//初始的朝向和ViewUp都需要调整
|
||||
case infinitiViewer::SLICE_ORIENTATION_XZ: {
|
||||
double zVec = GetInput()->GetSpacing()[2];
|
||||
double upVal = (zVec > 0.0 ? 1.0 : -1.0);
|
||||
cam->SetFocalPoint(0, 0, 0);
|
||||
cam->SetPosition(0, 1 * upVal, 0); // 1 if medical ?
|
||||
cam->SetPosition(0, 1 * upVal, 0);
|
||||
cam->SetViewUp(0, 0, -1.0 * upVal);
|
||||
break;
|
||||
}
|
||||
@@ -1227,7 +1250,7 @@ void infinitiViewer::UpdateOrientation() {
|
||||
double zVec = GetInput()->GetSpacing()[2];
|
||||
double upVal = (zVec > 0.0 ? 1.0 : -1.0);
|
||||
cam->SetFocalPoint(0, 0, 0);
|
||||
cam->SetPosition(-1 * upVal, 0, 0); // -1 if medical ?
|
||||
cam->SetPosition(-1 * upVal, 0, 0);
|
||||
cam->SetViewUp(0, 0, -1.0 * upVal);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -378,6 +378,8 @@ vtkTypeMacro(infinitiViewer, vtkObject);
|
||||
|
||||
void GetSlicePoint(double *point);
|
||||
|
||||
void applySliceOffset(double offset, double direction);
|
||||
|
||||
virtual void UpdateOrientation();
|
||||
|
||||
protected:
|
||||
@@ -458,6 +460,11 @@ private:
|
||||
bool rulerActive = false;
|
||||
char SOP_UID[20] = {0};
|
||||
double imageDataOrigin[3] = {.0, .0, .0};
|
||||
double defaultProjection[3][3] = {
|
||||
{1.,0.,0.},
|
||||
{0.,1.,0.},
|
||||
{0.,0.,1.}
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -116,7 +116,7 @@ void ImageViewManager::smartDo(SmartDoCallback cb, DicomImageView *sourceView, v
|
||||
});
|
||||
break;
|
||||
}
|
||||
case DoScope::EStudyEBoundsSeries: {
|
||||
case DoScope::SameStudySeries: {
|
||||
std::for_each(vList.begin(), vList.end(), [=](auto v) {
|
||||
if (v == sourceView) return;
|
||||
if (!v->hasSeries()) return;
|
||||
@@ -140,6 +140,17 @@ void ImageViewManager::smartDo(SmartDoCallback cb, DicomImageView *sourceView, v
|
||||
});
|
||||
break;
|
||||
}
|
||||
case DoScope::SameOrientationSeries: {
|
||||
std::for_each(vList.begin(), vList.end(), [=](auto v) {
|
||||
if (v == sourceView) return;
|
||||
if (!v->hasSeries()) return;
|
||||
//same series
|
||||
if (v->CompareWorldSliceOrientation(sourceView)) {
|
||||
cb(v, callData);
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case DoScope::AllExceptSelf: {
|
||||
std::for_each(vList.begin(), vList.end(), [=](auto v) {
|
||||
if (v == sourceView) return;
|
||||
@@ -177,33 +188,30 @@ void ImageViewManager::viewDoubleClicked(DicomImageView *view) {
|
||||
}
|
||||
}
|
||||
|
||||
void ImageViewManager::viewSynced(DicomImageView *src, int interactionMode, void *data) {
|
||||
|
||||
switch (interactionMode) {
|
||||
case VTKIS_IMAGE_SLICING:
|
||||
if (SyncHelper::getSyncItem(SLICE_POS)) {
|
||||
if (SyncHelper::getSyncState() == AUTO_SYNC) {
|
||||
this->smartDo([](auto v, auto callData) {
|
||||
if (v->hasSeries()) {
|
||||
double *r = (double *) callData;
|
||||
v->syncSlicePoint(r);
|
||||
v->SyncScrollBar();
|
||||
}
|
||||
}, src, data, ImageViewManager::EStudyEBoundsSeries);
|
||||
void ImageViewManager::viewSliced(DicomImageView *src, void *sliceData) {
|
||||
//Sync slice
|
||||
if (SyncHelper::getSyncItem(SLICE_POS)) {
|
||||
if (SyncHelper::getSyncState() == AUTO_SYNC) {
|
||||
this->smartDo([](auto v, auto callData) {
|
||||
if (v->hasSeries()) {
|
||||
double *r = (double *) callData;
|
||||
v->syncSlicePoint(r);
|
||||
v->SyncScrollBar();
|
||||
}
|
||||
if (SyncHelper::getSyncState() == MANUAL_SYNC) {
|
||||
this->smartDo([](auto v, auto callData) {
|
||||
if (v->hasSeries()) {
|
||||
//disable global trigger slot
|
||||
int *r = (int *) callData;
|
||||
v->addSlice(r[1]);
|
||||
}
|
||||
}, src, data, ImageViewManager::EStudyEBoundsSeries);
|
||||
}, src, sliceData, ImageViewManager::SameStudySeries);
|
||||
}
|
||||
else if (SyncHelper::getSyncState() == MANUAL_SYNC) {
|
||||
this->smartDo([](auto v, auto callData) {
|
||||
if (v->hasSeries()) {
|
||||
//disable global trigger slot
|
||||
double * r = (double *) callData;
|
||||
v->applySliceOffset(r[3], r[4]);
|
||||
v->SyncScrollBar();
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}, src, sliceData, ImageViewManager::SameOrientationSeries);
|
||||
}
|
||||
}
|
||||
//TODO: reference line
|
||||
}
|
||||
|
||||
void ImageViewManager::viewPaned(DicomImageView *src, void* offsetVector) {
|
||||
@@ -215,7 +223,7 @@ void ImageViewManager::viewPaned(DicomImageView *src, void* offsetVector) {
|
||||
double vector[3] = {d[3] - d[0], d[4] - d[1], d[5] - d[2]};
|
||||
v->applyPanOffset(vector);
|
||||
}
|
||||
}, src, offsetVector, ImageViewManager::EStudyEBoundsSeries);
|
||||
}, src, offsetVector, ImageViewManager::SameStudySeries);
|
||||
} else if (SyncHelper::getSyncState() == AUTO_SYNC) {
|
||||
this->smartDo([](auto v, auto callData) {
|
||||
if (v->hasSeries()) {
|
||||
@@ -223,7 +231,7 @@ void ImageViewManager::viewPaned(DicomImageView *src, void* offsetVector) {
|
||||
double vector[3] = {d[3], d[4] , d[5]};
|
||||
v->shiftCamera(vector);
|
||||
}
|
||||
}, src, offsetVector, ImageViewManager::EStudyEBoundsSeries);
|
||||
}, src, offsetVector, ImageViewManager::SameStudySeries);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -235,7 +243,7 @@ void ImageViewManager::viewZoomed(DicomImageView *src, double scaleFactor) {
|
||||
double d = *(double *) callData;
|
||||
v->setZoomScale(d);
|
||||
}
|
||||
}, src, &scaleFactor, ImageViewManager::EStudyEBoundsSeries);
|
||||
}, src, &scaleFactor, ImageViewManager::SameStudySeries);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +255,7 @@ void ImageViewManager::viewEndWindowLevel(DicomImageView *src, double level, dou
|
||||
double *d = (double *) callData;
|
||||
v->setWindowLevel(d[0], d[1]);
|
||||
}
|
||||
}, src, data, ImageViewManager::EStudyEBoundsSeries);
|
||||
}, src, data, ImageViewManager::SameStudySeries);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,8 +98,8 @@ public:
|
||||
Current,
|
||||
SameSeries,
|
||||
//Equal Study, Equal World Bounds series
|
||||
EStudyEBoundsSeries,
|
||||
EqualBoundsSeriesExceptSelf,
|
||||
SameStudySeries,
|
||||
SameOrientationSeries,
|
||||
AllExceptSelf,
|
||||
All
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "dicomimageview.h"
|
||||
#include "dicomimageview.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDebug>
|
||||
@@ -420,11 +420,9 @@ void DicomImageView::dispatchEvent(vtkObject *, unsigned long eid, void *callDat
|
||||
break;
|
||||
}
|
||||
case (ActorDraggableInteractorStyle::DraggableStyleEvents::SlicedEvent): {
|
||||
mScrollBar->SetValueSilently(r[0]);
|
||||
mScrollBar->SetValueSilently(mImageViewer->GetSlice());
|
||||
//invoke event
|
||||
double focusPoint[3] = {.0, .0, .0};
|
||||
mImageViewer->GetSlicePoint(focusPoint);
|
||||
emit onSlice(this, focusPoint);
|
||||
emit onSlice(this, callData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -165,6 +165,11 @@ public:
|
||||
mImageViewer->Render();
|
||||
}
|
||||
|
||||
void applySliceOffset(double offset, double direction){
|
||||
mImageViewer->applySliceOffset(offset, direction);
|
||||
mImageViewer->Render();
|
||||
}
|
||||
|
||||
void loadSeries(SeriesImageSet *series);
|
||||
|
||||
signals:
|
||||
|
||||
Reference in New Issue
Block a user