feat: rebuild window sync logic

This commit is contained in:
kradchen
2025-06-16 14:46:03 +08:00
parent 6f835c9597
commit 641f63a6ee
11 changed files with 101 additions and 144 deletions

View File

@@ -17,9 +17,9 @@ int MeasureHelper::measureType = 0;
bool FlipExportHelper::flip = false;
SyncState SyncHelper::_syc_state = SyncState::DIS_SYNC;
bool SyncHelper::_syc_item[SYNC_STATE_NUM][SYNC_ITEM_NUM] = {true,true,true,true,true,true,false,false,false};
bool SyncHelper::_sync_flag =false; //for just zoom and pan
const QString SyncHelper::SyncStateName[SYNC_STATE_NUM] = { "AUTO_SYNC","MANUAL_SYNC","DIS_SYNC" };
unsigned int SyncHelper::_syc_item = 0x0000;
bool SyncHelper::_syc_state = false;
const QString SyncHelper::SyncStateName[SYNC_STATE_NUM] = { "AUTO_SYNC","DIS_SYNC" };
const QString SyncHelper::SyncItemName[SYNC_ITEM_NUM] = { "SLICE_LOC","ZOOM_PAN","WIDTH_LEVEL" };
LanguageOption LanguageHelper::lang = English;

View File

@@ -123,23 +123,6 @@ typedef struct DicomCornerInfo
std::string ConstAnno[CORNER_NUM];
}DicomCornerInfo_t;
enum SyncState
{
AUTO_SYNC,
MANUAL_SYNC,
DIS_SYNC
};
enum SyncItem
{
SLICE_POS,
ZOOM_PAN,
WIDTH_LEVEL
};
enum AddDicomType
{
DUPLICATE_TYPE,
@@ -303,41 +286,43 @@ private:
#define SYNC_ITEM_NUM 3
#define SYNC_STATE_NUM 3
enum SyncType
{
SYNC_SLICE = 0x0001,
SYNC_PAN_ZOOM = 0x0002,
SYNC_WINDOW = 0x0004
};
class SyncHelper
{
public:
static bool getSyncItem(SyncItem index)
static bool getSyncItem(SyncType aType)
{
return _syc_item[_syc_state][index];
return _syc_item&aType;
}
static void setSyncItem(SyncItem index, bool sync)
static void setSyncItem(unsigned int aSyncSetting,bool aValue)
{
_syc_item[_syc_state][index] = sync;
_syc_item = _syc_item | (aValue? aSyncSetting:(!aSyncSetting));
}
static void setSyncItems(bool sync)
static void setSyncItems(unsigned int aSyncSetting)
{
for (int i = 0; i < SYNC_ITEM_NUM; i++)
{
_syc_item[_syc_state][i] = sync;
}
_syc_item = _syc_item&aSyncSetting;
}
static SyncState getSyncState()
static bool getSyncState()
{
return _syc_state;
}
static void setSyncState(SyncState curState)
static void setSyncState(bool aState)
{
_syc_state = curState;
_syc_state = aState;
EventsCenter::TriggerEvent(SyncStateChanged);
}
static const QString SyncStateName[SYNC_STATE_NUM];// = { "AUTO_SYNC","MANUAL_SYNC","DIS_SYNC" };
static const QString SyncItemName[SYNC_ITEM_NUM];// = { "SLICE_LOC","ZOOM_PAN","WIDTH_LEVEL" };
private:
static SyncState _syc_state;
static bool _syc_item[SYNC_STATE_NUM][SYNC_ITEM_NUM];
static bool _sync_flag; //for just zoom and pan
static unsigned int _syc_item;
static bool _syc_state;
};
enum LanguageOption

View File

@@ -366,6 +366,7 @@ void DICOMImageViewer::Render() {
int currentIndex = ImageMapper->GetSliceNumber();
if (currentIndex != lastIndex) this->SetSlice(lastIndex);
ResetZoomScaleToFitWindowSize();
this->InteractorStyle->SetCurrentImageNumber(0);
}
this->FirstRender = 0;
return;
@@ -469,6 +470,10 @@ void DICOMImageViewer::SetSlice(int slice) {
// this->Render();
UpdateTopLeftCornerInfo();
if (InteractorStyle){
if (slice == 0){
InteractorStyle->SetCurrentRenderer(this->Renderer);
InteractorStyle->SetCurrentImageNumber(0);
}
double direction = (double)(slice - lastSliceNumber);
double focusPoint[5] = {.0, .0, .0 };
GetSlicePoint(focusPoint);
@@ -574,7 +579,8 @@ void DICOMImageViewer::modifiedReferenceLine(){
Render();
}
void DICOMImageViewer::SyncSlicePoint(double *point) {
void DICOMImageViewer::SyncSliceWithFocus(double *point)
{
double focusPoint[4] = {point[0], point[1], point[2], 1.0};
WorldToModelMatrix->MultiplyPoint(focusPoint, focusPoint);
double f[3] = {.0, .0, .0};
@@ -584,6 +590,7 @@ void DICOMImageViewer::SyncSlicePoint(double *point) {
f[SliceIJK] = focusPoint[SliceIJK];
Renderer->GetActiveCamera()->SetFocalPoint(f);
this->Render();
Slice = ImageMapper->GetSliceNumber();
UpdateTopLeftCornerInfo();
}

View File

@@ -369,7 +369,8 @@ public:
return &raiser;
}
void SyncSlicePoint(double *point);
void SyncSliceWithFocus(double *point);
void GetSlicePoint(double *point);

View File

@@ -137,8 +137,9 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
if (!v->hasSeries()) return;
//check series
auto series = sourceView->getSeriesInstance();
if (v->getSeriesInstance() == series && v->getReconPlane() == sourceView->getReconPlane()) {
cb(v, callData);
if ( v->getSeriesInstance() == series) {
if(cb)cb(v, callData);
else if(otherCb) otherCb(v, callData);
}
else{
if (otherCb) otherCb(v, callData);
@@ -147,6 +148,24 @@ void ImageViewManager::smartDo(SmartDoCallback cb,SmartDoCallback otherCb, Dico
});
break;
}
case DoScope::SameSeriesSameOrientation: {
std::for_each(vList.begin(), vList.end(), [=](auto v) {
if (v == sourceView) return;
if (!v->hasSeries()) return;
//check series
auto series = sourceView->getSeriesInstance();
if ( v->getSeriesInstance() == series && v->getReconPlane() == sourceView->getReconPlane()) {
if(cb)cb(v, callData);
else if(otherCb) otherCb(v, callData);
}
else
{
if (otherCb) otherCb(v, callData);
}
});
break;
}
case DoScope::SameStudySameOrientation: {
std::for_each(vList.begin(), vList.end(), [=](auto v) {
if (v == sourceView) return;
@@ -254,25 +273,15 @@ void ImageViewManager::viewDoubleClicked(DicomImageView *view) {
void ImageViewManager::viewSliced(DicomImageView *src, void *sliceData) {
//Sync slice
if (sliceData && SyncHelper::getSyncItem(SLICE_POS)) {
if (SyncHelper::getSyncState() == AUTO_SYNC) {
if (sliceData && SyncHelper::getSyncItem(SYNC_SLICE)) {
if (SyncHelper::getSyncState() == SYNC_SLICE) {
this->smartDo([](auto v, auto callData) {
if (v->hasSeries()) {
double *r = (double *) callData;
v->syncSlicePoint(r);
v->syncSliceFocus(r);
v->SyncScrollBar();
}
}, src, sliceData, ImageViewManager::SameStudySameOrientation);
}
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();
}
}, src, sliceData, ImageViewManager::SameOrientationSeries);
}, src, sliceData, ImageViewManager::SameSeriesSameOrientation);
}
}
//reference line
@@ -300,57 +309,37 @@ void ImageViewManager::renderReferenceLine() {
}
void ImageViewManager::viewPaned(DicomImageView *src, void* offsetVector) {
if (SyncHelper::getSyncItem(ZOOM_PAN)) {
if (SyncHelper::getSyncState() == MANUAL_SYNC) {
this->smartDo([](auto v, auto callData) {
if (SyncHelper::getSyncState() && SyncHelper::getSyncItem(SYNC_PAN_ZOOM))
{
this->smartDo([](auto v, auto callData){
if (v->hasSeries()) {
double *d = (double *) callData;
double vector[3] = {d[3] - d[0], d[4] - d[1], d[5] - d[2]};
v->applyPanOffset(vector);
}
}, src, offsetVector, ImageViewManager::SameOrientationSeries);
} else if (SyncHelper::getSyncState() == AUTO_SYNC) {
this->smartDo([](auto v, auto callData) {
if (v->hasSeries()) {
double *d = (double *) callData;
double vector[3] = {d[3], d[4] , d[5]};
v->shiftCamera(vector);
}
}, src, offsetVector, ImageViewManager::SameStudySameOrientation);
}
} }, src, offsetVector, ImageViewManager::SameSeriesSameOrientation);
}
}
void ImageViewManager::viewZoomed(DicomImageView *src, double* scaleFactor) {
if (SyncHelper::getSyncItem(ZOOM_PAN)) {
if (SyncHelper::getSyncState() == MANUAL_SYNC){
if (SyncHelper::getSyncState() && SyncHelper::getSyncItem(SYNC_PAN_ZOOM)){
this->smartDo([](auto v, auto callData) {
if (v->hasSeries()) {
double* d = ((double *) callData);
v->setZoomFactor(d[1]/d[0]);
}
}, src, scaleFactor, ImageViewManager::SameOrientationSeries);
}
else if (SyncHelper::getSyncState() == AUTO_SYNC) {
this->smartDo([](auto v, auto callData) {
if (v->hasSeries()) {
double d = ((double *) callData)[1];
v->setZoomScale(d);
}
}, src, scaleFactor, ImageViewManager::SameStudySameOrientation);
}
}, src, scaleFactor, ImageViewManager::SameSeriesSameOrientation);
}
}
void ImageViewManager::viewEndWindowLevel(DicomImageView *src, double level, double window) {
double data[2] = {level, window};
if (SyncHelper::getSyncItem(WIDTH_LEVEL)) {
if (SyncHelper::getSyncState() && SyncHelper::getSyncItem(SYNC_WINDOW)) {
this->smartDo([](auto v, auto callData) {
if (v->hasSeries()) {
double *d = (double *) callData;
v->setWindowLevel(d[0], d[1]);
}
}, src, data, ImageViewManager::SameStudySameOrientation);
}, src, data, ImageViewManager::SameSeriesSameOrientation);
}
}
@@ -481,7 +470,7 @@ bool ImageViewManager::checkViewFusion(DicomImageView *view) {
return false;
}
int ImageViewManager::checkSyncAbility(DicomImageView* view) {
bool ImageViewManager::checkSyncAbility(DicomImageView* view) {
bool flag = false;
this->smartDo([](auto v, auto callData) {
bool *d = (bool *) callData;
@@ -490,7 +479,7 @@ int ImageViewManager::checkSyncAbility(DicomImageView* view) {
d[0] = true;
}
}, view, &flag, ImageViewManager::SameStudySameOrientation);
if (flag) return AUTO_SYNC;
if (flag) return true;
this->smartDo([](auto v, auto callData) {
bool *d = (bool *) callData;
if (d[0]) return;
@@ -499,8 +488,8 @@ int ImageViewManager::checkSyncAbility(DicomImageView* view) {
}
}, view, &flag, ImageViewManager::SameOrientationSeries);
if (flag) return MANUAL_SYNC;
return DIS_SYNC;
if (flag) return true;
return false;
}
void ImageViewManager::clearCurrentView() {

View File

@@ -97,11 +97,12 @@ public:
void switchFusion();
int checkSyncAbility(DicomImageView* view);
bool checkSyncAbility(DicomImageView* view);
enum DoScope {
Current,
SameSeries,
SameSeriesSameOrientation,
//Equal Study, Equal World Bounds series
SameStudySameOrientation,
SameOrientationSeries,

View File

@@ -171,8 +171,8 @@ public:
return this->mImageViewer->GetReconPlane() == view->mImageViewer->GetReconPlane();
}
void syncSlicePoint(double *point) {
mImageViewer->SyncSlicePoint(point);
void syncSliceFocus(double *point) {
mImageViewer->SyncSliceWithFocus(point);
}
void applySliceOffset(double offset, double direction){

View File

@@ -227,11 +227,6 @@ void DefaultToolBar::initSyncButton() {
// Menu
QMenu * m = new QMenu(this);
// SyncState curst = SyncHelper::getSyncState();
// mActionSyncState = m->addAction(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[curst]));
// mActionSyncState->setCheckable(false);
// addSeparator();
#define ADD_SYNC_ITEM(index,text,type)\
mSyncActions[index] = m->addAction(text, this, [&](bool value) {\
SyncHelper::setSyncItem(type, value);\
@@ -240,9 +235,9 @@ void DefaultToolBar::initSyncButton() {
mSyncActions[index]->setChecked(false);\
mSyncActions[index]->setDisabled(true);
ADD_SYNC_ITEM(0,tr("Sychronize slice"),SyncItem::SLICE_POS)
ADD_SYNC_ITEM(1,tr("Sychronize zoom & pan"),SyncItem::ZOOM_PAN)
ADD_SYNC_ITEM(2,tr("Sychronize window level & width"),SyncItem::WIDTH_LEVEL)
ADD_SYNC_ITEM(0,tr("Sychronize slice"), SYNC_SLICE)
ADD_SYNC_ITEM(1,tr("Sychronize zoom & pan"), SYNC_PAN_ZOOM)
ADD_SYNC_ITEM(2,tr("Sychronize window level & width"), SYNC_WINDOW)
//hide zoom& pan action
mSyncActions[1]->setVisible(false);
@@ -250,43 +245,22 @@ void DefaultToolBar::initSyncButton() {
mBtnSync->setPopupMode(QToolButton::MenuButtonPopup);
mBtnSync->setMenu(m);
connect(mBtnSync, &QToolButton::clicked,[](){
SyncHelper::setSyncState((SyncState)((SyncHelper::getSyncState()+1)%3));
SyncHelper::setSyncState(!SyncHelper::getSyncState());
});
connect(EventsCenter::Default(), &EventsCenter::SyncStateChanged, this, &DefaultToolBar::syncStateChanged);
}
void DefaultToolBar::syncStateChanged() const {
switch (SyncHelper::getSyncState()) {
case AUTO_SYNC:
mBtnSync->setIcon(mAutoIcon);
mActionSyncState->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[AUTO_SYNC]));
for (int i = 0; i < SYNC_ITEM_NUM; i++) {
mSyncActions[i]->setDisabled(false);
}
mSyncActions[SLICE_POS]->setChecked(SyncHelper::getSyncItem(SLICE_POS));
mSyncActions[WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(WIDTH_LEVEL));
mSyncActions[ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(ZOOM_PAN));
break;
case MANUAL_SYNC:{
mBtnSync->setIcon(mManualIcon);
mActionSyncState->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[MANUAL_SYNC]));
mSyncActions[SLICE_POS]->setChecked(SyncHelper::getSyncItem(SLICE_POS));
mSyncActions[WIDTH_LEVEL]->setChecked(SyncHelper::getSyncItem(WIDTH_LEVEL));
mSyncActions[ZOOM_PAN]->setChecked(SyncHelper::getSyncItem(ZOOM_PAN));
break;
}
case DIS_SYNC:
mBtnSync->setIcon(mDisIcon);
mActionSyncState->setText(QString(tr("CUR STATE: %1")).arg(SyncHelper::SyncStateName[DIS_SYNC]));
for (int i = 0; i < SYNC_ITEM_NUM; i++) {
mSyncActions[i]->setChecked(false);
mSyncActions[i]->setDisabled(true);
}
break;
default:
break;
mBtnSync->setIcon(SyncHelper::getSyncState()?mAutoIcon:mDisIcon);
unsigned int v = 1;
for (unsigned int i = 0; i < SYNC_ITEM_NUM; i++) {
mSyncActions[i]->setChecked(SyncHelper::getSyncState());
mSyncActions[i]->setEnabled(SyncHelper::getSyncState());
SyncHelper::setSyncItem(v <<i, SyncHelper::getSyncState());
}
}
void DefaultToolBar::initModeButtons() {
@@ -551,20 +525,20 @@ void DefaultToolBar::updateNeedCheckFunctionButtons(ViewFunctionState state)
mBtnClear->setEnabled(true);
mBtnFlip->setEnabled(true);
mBtnCine->setEnabled(true);
mBtnMPR->setEnabled(state.canMPR!=-1);
mBtnVR->setEnabled(state.canMPR!=-1);
if (state.canMPR!=-1){
for (int i = 0; i < 3; ++i) {
if (i==state.canMPR){
mMPRActions[i]->setEnabled(false);
}
else{
mMPRActions[i]->setEnabled(true);
mBtnMPR->setEnabled(state.canMPR!=-1);
mBtnVR->setEnabled(state.canMPR!=-1);
if (state.canMPR!=-1){
for (int i = 0; i < 3; ++i) {
if (i==state.canMPR){
mMPRActions[i]->setEnabled(false);
}
else{
mMPRActions[i]->setEnabled(true);
}
}
mMPRActions[state.canMPR]->setChecked(true);
}
mMPRActions[state.canMPR]->setChecked(true);
}
mBtnFusion->setEnabled(state.canFusion);
mBtnFusion->setEnabled(state.canFusion);
}
// SyncHelper::setSyncState((SyncState)state.canSync);
// syncStateChanged();

View File

@@ -95,7 +95,6 @@ private:
QAction *mActionMaximize;
QAction *mActionClose;
QAction *mActionFullScreen;
QAction *mActionSyncState;
QAction *mActionHideAnnotations;
QAction *mActionHideReferenceLine;
QAction *mActionHideMeasure;

View File

@@ -175,6 +175,7 @@ void QDicomViewer::initViewOperation() {
default:
break;
}
SyncHelper::setSyncState(false);
}
});
// MPR

View File

@@ -81,8 +81,8 @@ int main(int argc, char* argv[])
LanguageHelper::setLanguage(ChineseSimple);
}
QApplication::installTranslator(&translator);
QDicomViewer w;
w.show();
QDicomViewer w;
w.show();
exitCode = a.exec();
}