Files
DCMV/src/src/UI/Widget/ImageView/dicomimageview.cpp
2025-07-23 13:42:37 +08:00

873 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dicomimageview.h"
#include <QMessageBox>
#include <QDebug>
#include <QCursor>
#include <vtkRenderer.h>
#include <vtkCamera.h>
#include <vtkInteractorStyleImage.h>
#include <QVTKOpenGLNativeWidget.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkDiscretizableColorTransferFunction.h>
#include <vtkImageProperty.h>
#include "Interaction/ActorDraggableInteractorStyle.h"
#include "UI/Window/metaDataWindow.h"
#include "UI/Widget/Component/mytitlebar.h"
#include "UI/Widget/cine/pqVCRController.h"
#include "UI/Widget/cine/pqVCRToolbar.h"
#include "UI/Widget/Thumbnail/thumbnailImage.h"
#include "dcmtk/dcmdata/dcfilefo.h"
//-----------------------------------------------------------------------------
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), mTableName("gray"),mIsCine(false), mIsNegative(false),
mIsOverlay(false), mIsSlotInited(false),mCurrentRAngle(0)
{
//main container
QFrame *wrapper = new QFrame(this);
wrapper->setObjectName("wrapper");
QGridLayout *view_layout = new QGridLayout(this);
//add container and title bar
view_layout->addWidget(mTitleBar, 0, 0);
view_layout->addWidget(wrapper, 1, 0);
view_layout->setContentsMargins(0, 0, 0, 0);
view_layout->setSpacing(0);
this->setLayout(view_layout);
// create layout for main container
QGridLayout *controlLayout = new QGridLayout(wrapper);
mGLWidget->setParent(wrapper);
mGLWidget->setRenderWindow(mGLRenWin.Get());
controlLayout->addWidget(mGLWidget, 0, 0);
//add scrollbar to container
mScrollBar->setSingleStep(1);
mScrollBar->setFocusPolicy(Qt::StrongFocus);
mScrollBar->setVisible(false);
mScrollBar->setObjectName("scrollbar");
controlLayout->addWidget(mScrollBar, 0, 1);
connect(mScrollBar, &ClickableScrollBar::clicked, this, &DicomImageView::clicked);
//config container UI
controlLayout->setContentsMargins(0, 0, 0, 0);
controlLayout->setSpacing(0);
wrapper->setLayout(controlLayout);
setAutoFillBackground(true);
//config self
QWidget::setAcceptDrops(true);
this->setObjectName("dicomview");
}
DicomImageView::~DicomImageView() {
if (mImageViewer) {
mImageViewer->Delete();
mImageViewer = nullptr;
}
mVcrControlThread.quit();//event loop
mVcrControlThread.wait(); //wait until return,block mode
if (mVcrToolbar) {
mVcrToolbar->deleteLater();
}
}
// layout about---------------------------------------------------------------
MyTitleBar *DicomImageView::createMyTitleBar() {
MyTitleBar *titleBar = new MyTitleBar(this);
connect(titleBar, &MyTitleBar::signalButtonMaxClicked, this, &DicomImageView::doubleClicked);
connect(titleBar, &MyTitleBar::signalButtonCloseClicked, this, &DicomImageView::viewCleared);
return titleBar;
}
void DicomImageView::initScrollbar() {
//_MinSlice = mImageViewer->GetSliceMin();
//_MaxSlice = mImageViewer->GetSliceMax();
mScrollBar->setValue(mImageViewer->GetSliceMin());
mScrollBar->setMaximum(mImageViewer->GetSliceMax());
// mScrollBar->setSingleStep(1);
mScrollBar->setPageStep(1);
mScrollBar->setVisible(true);
if (!mIsSlotInited) {
connect(mScrollBar, &QScrollBar::valueChanged, this, &DicomImageView::scrollBarValueChanged);
connect(this, &DicomImageView::onTransform, this, &DicomImageView::imageTransformed);
}
}
void DicomImageView::initImageViewer() {
if (!mImageViewer) {
mImageViewer = DICOMImageViewer::New();
mImageViewer->SetViewID(this->mViewID);
mImageViewer->SetRenderWindow(mGLRenWin);
mImageViewer->SetupInteractor(mGLRenWin->GetInteractor());
}
}
void DicomImageView::initImageViewerFirstTime()
{
if (!mImageViewer) {
mImageViewer = DICOMImageViewer::New();
mImageViewer->SetViewID(this->mViewID);
mImageViewer->SetRenderWindow(mGLRenWin);
mImageViewer->SetupInteractor(mGLRenWin->GetInteractor());
mGLRenWin->GetInteractor()->RemoveAllObservers();
mImageViewer->Delete();
mImageViewer = nullptr;
mIsSlotInited = false;
}
}
void DicomImageView::setHighlight(bool yes) {
mTitleBar->SetHighlight(yes);
}
// action----------------------------------------------------------------------
void DicomImageView::SyncScrollBar() {
mScrollBar->SetValueSilently(mImageViewer->GetSlice());
}
void DicomImageView::setViewID(uint aID)
{
mViewID = aID;
}
void DicomImageView::resetView()
{
if (hasSeries()) {
unloadFusion();
removeViewWithMeasure();
mImageViewer->GetRenderer()->RemoveAllViewProps();
this->render();
mImageViewer->Delete();
mImageViewer = nullptr;
mIsSlotInited = false;
//don't delete series It's belong to data cache
mSeries = nullptr;
}
mScrollBar->setVisible(false);
if (mIsCine)
mVcrToolbar->setVisible(false);
}
bool DicomImageView::hasSeries() {
return mSeries;
}
void DicomImageView::RenderReloadMeasure()
{
if (!hasSeries()) return;
mImageViewer->RenderReloadMeasure();
}
void DicomImageView::loadSeries(SeriesImageSet *series) {
if (!series) return;
initImageViewer();
mSeries = series;
QString age = series->GetProperty()->GetPatientAge();
age = age.isEmpty()?"":QString("%1%2").arg(age.left(age.length()-1).toInt()).arg(age.back());
QString date = series->GetProperty()->GetAcquisitionDate();
date = date.length()<8?"":
QString("%1/%2/%3").arg(date.left(4), date.mid(4,2), date.right(2));
QString time = series->GetProperty()->GetAcquisitionTime();
time = time.length()<6?"": QString("%1:%2:%3").arg(time.left(2), time.mid(2,2), time.mid(4,2));
mTitleBar->setTitleContent(QString("%1 (%2) - %3 %4 - %5")
.arg(series->GetProperty()->GetPatientName())
.arg(age)
.arg(date)
.arg(time)
.arg(series->GetProperty()->GetSeriesDescription()));
mImageViewer->SetInputData(mSeries->GetData());
setColorTable("gray");
mIsFirstRenderAfterLoad = true;
if(mSeries->GetOverlayData())
{
mImageViewer->SetOverlayInputData(mSeries->GetOverlayData());
}
mImageViewer->SetCoordsTransformMatrix(series->GetProperty());
mImageViewer->InitCornerInfo(series->GetProperty());
mImageViewer->SetupImageViewer();
mImageViewer->UpdateOrientationInfo();
//以下是一些转接函数
//使用connect 替代 AddObserver,避免出现多种事件机制架构
if (!mIsSlotInited) {
connect(mImageViewer->GetSignalRaiser(), &vtkSignalRaiser::raiseEvent, this, &DicomImageView::dispatchEvent);
//目前 替换了一部分包括SlicedEventEndDollyEventEndWindowLevelEventEndPanEvent主要关联到sync
ActorDraggableInteractorStyle *style = mImageViewer->GetInteractorStyle();
style->AddObserver(AfterViewerClicked, this, &DicomImageView::clicked);
style->AddObserver(vtkCommand::WindowLevelEvent, this, &DicomImageView::windowLevelHandle);
style->AddObserver(DoubleClickEvent, this, &DicomImageView::doubleClickHandle);
style->AddObserver(ScalarOpacityEvent, this, &DicomImageView::scalarEventHandle);
style->AddObserver(ScalarShiftEvent, this, &DicomImageView::scalarEventHandle);
}
initScrollbar();
mIsSlotInited = true;
}
int DicomImageView::getSeriesNumber() {
if (hasSeries()) {
return mSeries->GetSeriesNumber();
}
return -1;
}
void DicomImageView::showMetaData() {
QString fileName = QString::fromLatin1(this->mSeries->getCurImageName(mImageViewer->GetSlice()));
if (!fileName.isEmpty()) {
DcmFileFormat dcmFile;
if (!dcmFile.loadFile(fileName.toStdString()).good()) {
QMessageBox::warning(this,
tr("Error"),
tr("Unable to read file %1").arg(fileName),
QMessageBox::Ok);
return;
}
metaDataWindow *dicomWindow = new metaDataWindow(&dcmFile);
dicomWindow->setAttribute(Qt::WA_DeleteOnClose);
dicomWindow->setWindowTitle("DICOM Tags (" + fileName + ")");
dicomWindow->setWindowFilePath(fileName);
dicomWindow->resize(USER_CONFIG::DEFAULT_TAG_WINDOW_SIZE);
dicomWindow->show();
}
}
//SLOTS------------------------------------------------------------------------
void DicomImageView::scrollBarValueChanged(int slice) {
mImageViewer->SetSlice(slice);
}
void DicomImageView::viewCleared() {
emit beforeViewCleared(this);
resetView();
mTitleBar->setTitleContent("");
emit afterViewCleared(this);
}
void DicomImageView::doubleClicked() {
emit onViewDoubleClick(this);
}
void DicomImageView::fusionWindowChanged(double level, double width) {
if (isFusion()) {
mImageViewer->SetFusionColorLeveL(level);
mImageViewer->SetFusionColorWindow(width);
mImageViewer->Render();
}
}
void DicomImageView::imageTransformed() {
if (hasSeries()){
mImageViewer->UpdateOrientationInfo();
mImageViewer->Render();
}
}
void DicomImageView::clicked() {
emit onViewClick(this);
}
//Widget event----------------------------------------------------------------
void DicomImageView::wheelEvent(QWheelEvent *event) {
if (hasSeries()) {
if (MeasureHelper::measuring) return;
int _Slice = mImageViewer->GetSlice();
int _MinSlice = mImageViewer->GetSliceMin();
int _MaxSlice = mImageViewer->GetSliceMax();
if (event->delta() > 0) {
if (_Slice > _MinSlice) {
_Slice -= 1;
mImageViewer->SetSlice(_Slice);
} else {
_Slice = _MinSlice;
mImageViewer->SetSlice(_Slice);
}
} else {
if (_Slice < _MaxSlice) {
_Slice += 1;
mImageViewer->SetSlice(_Slice);
} else {
_Slice = _MaxSlice;
mImageViewer->SetSlice(_Slice);
}
}
}
}
void DicomImageView::mousePressEvent(QMouseEvent *event) {
emit onViewClick(this);
}
void DicomImageView::resizeEvent(QResizeEvent *event) {
//auto size conner info
if (!mImageViewer) {
QWidget::resizeEvent(event);
if(mfirstShowFlag){
initImageViewerFirstTime();
mfirstShowFlag= false;
}
return;
}
QWidget::resizeEvent(event);
mImageViewer->ResetZoomScaleToFitWindowSize();
mImageViewer->Render();
if (mIsCine) {
int ax = (this->geometry().bottomLeft().x() + this->geometry().bottomRight().x()) / 2 +
VCRHelper::getVCRXOffset();
int ay = (this->geometry().bottomLeft().y() + this->geometry().bottomRight().y()) / 2 +
VCRHelper::getVCRYOffset();
mVcrToolbar->move(ax, ay);
}
}
// DND support-----------------------------------------------------------------
void DicomImageView::dragEnterEvent(QDragEnterEvent *e) {
if (e->mimeData()->hasFormat("text/plain")) {
e->acceptProposedAction();
}
}
void DicomImageView::dragMoveEvent(QDragMoveEvent *e) {
if (e->mimeData()->hasFormat("text/plain")) {
e->acceptProposedAction();
}
}
void DicomImageView::dropEvent(QDropEvent *e) {
if (e->mimeData()->hasFormat("text/plain")) {
e->acceptProposedAction();
thumbnailImage *tb = qobject_cast<thumbnailImage *>(
(QObject *) (e->mimeData()->text().toULongLong()));
if (tb) {
emit onDragDrop(this, tb->getSeriesInfo()->GetUniqueID());
}
}
}
void DicomImageView::dragLeaveEvent(QDragLeaveEvent *) {
return;
}
//Fusion about -------------------------------------------------------------
bool DicomImageView::isFusion() {
if (!mImageViewer) return false;
return mImageViewer->GetFusion();
}
void DicomImageView::setFusionInput(DicomImageView *overlay) {
mOverlayView = overlay;
vtkImageData *overlay_data = mOverlayView->getSeriesInstance()->GetData();
double window;
double level;
mOverlayView->getWindowLevel(level, window);
mImageViewer->FusionOn();
mOverlayView->OverlayOn();
mOverlayView->SetBaseView(this);
mImageViewer->SetFusionInputData(overlay_data, overlay->getSeriesInstance()->GetProperty()->GetModelToWorldMatrix());
mImageViewer->SetFusionColorLeveL(level);
mImageViewer->SetFusionColorWindow(window);
mImageViewer->SetFusionOpacity(mImageViewer->GetFusionOpacity());
// Example for vtkDiscretizableColorTransferFunction
vtkNew<vtkDiscretizableColorTransferFunction> table;
// example table1 d->r->g->w
table->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
table->AddRGBPoint(0.33, 1.0, 0.0, 0.0);
table->AddRGBPoint(0.66, 1.0, 1.0, 0.0);
table->AddRGBPoint(1.0, 1.0, 1.0, 1.0);
mImageViewer->SetFusionColorTable(table);
connect(mOverlayView, &DicomImageView::onFusionWindowChange,
this, &DicomImageView::fusionWindowChanged);
}
DicomImageView * DicomImageView::getFusionInput(){
return mOverlayView;
}
void DicomImageView::setFusionOpacity(double percent) {
if (isFusion()) {
mImageViewer->IncreFusionOpacity(percent);
mImageViewer->Render();
}
}
/**
* Remove Fusion no matter it is base or overlay
*/
void DicomImageView::unloadFusion() {
if (hasSeries()) {
if (isFusion()) {
disconnect(mOverlayView, &DicomImageView::onFusionWindowChange,
this, &DicomImageView::fusionWindowChanged);
this->clearFusionContext();
mOverlayView->SetBaseView(nullptr);
mOverlayView = nullptr;
}
if (IsOverlay()) {
disconnect(this, &DicomImageView::onFusionWindowChange,
mBaseView, &DicomImageView::fusionWindowChanged);
mBaseView->clearFusionContext();
mBaseView->SetOverlayView(nullptr);
mBaseView = nullptr;
}
}
}
void DicomImageView::clearFusionContext() {
mImageViewer->RemoveFusionData();
mImageViewer->FusionOff();
mImageViewer->Render();
mOverlayView->OverlayOff();
}
//Callbacks------------------------------------------------------------------------------------
void DicomImageView::windowLevelHandle() {
mImageViewer->UpdateCornerInfo(BOTTOM_RIGHT);
mImageViewer->Render();
emit onFusionWindowChange(mImageViewer->GetColorLevel(), mImageViewer->GetColorWindow());
}
void DicomImageView::scalarEventHandle(vtkObject *, unsigned long eventId, void *calldata) {
double *r = (double *) calldata;
switch (eventId) {
case (ScalarShiftEvent):
qDebug() << "ScalarShiftEvent";
mImageViewer->SwitchToNextPreset();
break;
case (ScalarOpacityEvent):
qDebug() << "ScalarOpacityEvent" << r[0];
setFusionOpacity(r[0]);
break;
default:
break;
}
}
void DicomImageView::doubleClickHandle() {
emit onViewDoubleClick(this);
}
void DicomImageView::dispatchEvent(vtkObject *, unsigned long eid, void *callData) {
int *r = (int *) callData;
switch (eid) {
case (vtkCommand::EventIds::EndPanEvent):{
emit onEndPan(this, callData);
break;
}
case (vtkCommand::EventIds::EndWindowLevelEvent):{
//update corner info through callback
emit onEndWindowLevel(this,
mImageViewer->GetColorLevel(),
mImageViewer->GetColorWindow());
break;
}
case (DraggableStyleEvents::EndDollyEvent):{
emit onEndZoom(this, (double *) callData);
break;
}
case (DraggableStyleEvents::SlicedEvent): {
mScrollBar->SetValueSilently(mImageViewer->GetSlice());
//invoke event
emit onSlice(this, callData);
break;
}
case (DraggableStyleEvents::StartSyncSlicePointEvent): {
this->setCursor(Qt::BlankCursor);
this->mImageViewer->Render();
//invoke event
break;
}
case (DraggableStyleEvents::SyncSlicePointEvent): {
double * p = (double*)callData;
double focalPoint[3]={0};
focalPoint[0] = p[0];
focalPoint[1] = p[1];
focalPoint[2] = p[2];
mImageViewer->TransformPointM2W(focalPoint);
//invoke event
emit onSyncPointSlice(this, focalPoint);
break;
}
case (DraggableStyleEvents::EndSyncSlicePointEvent): {
this->setCursor(Qt::ArrowCursor);
//invoke event
emit onSyncPointSlice(this, nullptr);
break;
}
default:
break;
}
}
//Image render & operation about--------------------------------------------------------------------------------------
void DicomImageView::render() {
if (hasSeries()) {
mImageViewer->Render();
}
}
int DicomImageView::getReconPlane() {
return mImageViewer->GetReconPlane();
}
void DicomImageView::setReconPlane(int plane) {
if (mImageViewer->GetReconPlane() == plane) return;
unloadFusion();
mImageViewer->SetReconPlane(plane);
int max = 0;
int min = 0;
mImageViewer->GetSliceRange(min, max);
mScrollBar->setValue(min);
mScrollBar->setMaximum(max);
mScrollBar->setValue(0);
}
void DicomImageView::setSlice(int slice) {
if (mImageViewer == nullptr) {
return;
}
if (hasSeries()) {
mImageViewer->SetSlice(slice);
}
}
int DicomImageView::getSlice(){
return mImageViewer->GetSlice();
}
void DicomImageView::addSlice(int step) {
if (mImageViewer == nullptr) {
return;
}
if (hasSeries()) {
int curSlice = mImageViewer->GetSlice() + step;
mImageViewer->SetSlice(curSlice);
}
}
void DicomImageView::setZoomScale(double scale) {
if (hasSeries()) {
mImageViewer->SetZoomScale(scale);
mImageViewer->Render();
}
}
void DicomImageView::setZoomFactor(double factor) {
if (hasSeries()) {
double newScale = factor* mImageViewer->GetRenderer()->GetActiveCamera()->GetParallelScale();
mImageViewer->SetZoomScale(newScale);
mImageViewer->Render();
}
}
void DicomImageView::applyPanOffset(double *pan) {
if (hasSeries()) {
mImageViewer->applyPanOffset(pan);
mImageViewer->Render();
}
}
void DicomImageView::shiftCamera(double *point) {
if (hasSeries()) {
mImageViewer->shiftCamera(point);
mImageViewer->Render();
}
}
void DicomImageView::resetPanZoom() {
if (hasSeries()) {
mImageViewer->GetRenderer()->ResetCamera();
mImageViewer->ResetZoomScaleToFitWindowSize();
}
}
void DicomImageView::setWindowLevel(double level, double width) {
if (hasSeries()) {
mImageViewer->SetColorLevel(level);
mImageViewer->SetColorWindow(width);
//You have to call updateConerInfo manually
//only mouse event can rely on callback
mImageViewer->UpdateCornerInfo(BOTTOM_RIGHT);
mImageViewer->Render();
emit onFusionWindowChange(level, width);
}
}
void DicomImageView::getWindowLevel(double &level, double &width) {
if (hasSeries()) {
level = mImageViewer->GetColorLevel();
width = mImageViewer->GetColorWindow();
}
}
void DicomImageView::negativeWindow() {
if (hasSeries()) {
if (mIsNegative) {
mImageViewer->SetNegativeMode(false);
mIsNegative = false;
} else {
mImageViewer->SetNegativeMode(true);
mIsNegative = true;
}
}
}
void DicomImageView::setColorTable(const QString &aTableName)
{
if (hasSeries()) {
mImageViewer->SetLookupTable(aTableName);
mTableName = aTableName;
}
}
QString DicomImageView::getColorTable()
{
return mTableName;
}
void DicomImageView::hFlipImage() {
if (hasSeries()) {
int slice = mImageViewer->GetSlice();
//HFlip
//mImageViewer->GetRenderer()->GetActiveCamera()->SetViewUp(0, 1, 0);
resetPanZoom();
mImageViewer->GetRenderer()->GetActiveCamera()->Azimuth(180);
FlipExportHelper::toggleFlip();
//to avoid black out problem during slicing
//slicing is related with rotation, you have to recalculate to get it right
mImageViewer->GetRenderer()->ResetCameraClippingRange();
mImageViewer->SetSlice(slice);
mImageViewer->GetRenderWindow()->Render();
emit onTransform(H_FLIP);
}
}
void DicomImageView::vFlipImage() {
if (hasSeries()) {
//double scale = mImageViewer->GetRenderer()->GetActiveCamera()->GetParallelScale();
int slice = mImageViewer->GetSlice();
resetPanZoom();
//Method 2: Order matters
mImageViewer->GetRenderer()->GetActiveCamera()->Elevation(-180);
mImageViewer->GetRenderer()->GetActiveCamera()->Roll(180);
//mImageViewer->GetRenderer()->GetActiveCamera()->SetViewUp(0,-1,0);
FlipExportHelper::toggleFlip();
//to avoid black out problem during slicing
//slicing is related with rotation, you have to recalculate to get it right
mImageViewer->GetRenderer()->ResetCameraClippingRange();
mImageViewer->SetSlice(slice);
mImageViewer->GetRenderWindow()->Render();
emit onTransform(V_FLIP);
}
}
void DicomImageView::rotateImage(double angle, TransFormType operation) {
if (hasSeries()) {
int slice = mImageViewer->GetSlice();
resetPanZoom();
mImageViewer->GetRenderer()->GetActiveCamera()->Roll(angle);
mCurrentRAngle=(mCurrentRAngle+(int)angle)%360;
resetPanZoom();
//to avoid black out problem during slicing
//slcing is related with rotation, you have to recalculate to get it right
mImageViewer->GetRenderer()->ResetCameraClippingRange();
mImageViewer->SetSlice(slice);
// mImageViewer->GetRenderWindow()->Render();
emit onTransform(operation);
}
}
void DicomImageView::ClearTransformations() {
if (hasSeries()) {
int slice = mImageViewer->GetSlice();
//reset flip and rotation
mImageViewer->UpdateReconPlane();
resetPanZoom();
//avoid black out problem
mImageViewer->GetRenderer()->ResetCameraClippingRange();
mImageViewer->SetSlice(slice);
//Render
mImageViewer->GetRenderWindow()->Render();
emit onTransform(CLEAR);
}
}
void DicomImageView::updateCornerInfoAll() {
if (hasSeries()) {
mImageViewer->UpdateCornerInfoAll();
}
}
void DicomImageView::updateCornerInfoPrivacy() {
if (hasSeries()) {
mImageViewer->UpdateCornerInfo(TOP_RIGHT);
mImageViewer->Render();
}
}
//--VCR about------------------------------------------------------------------
bool DicomImageView::isVCRVisible() {
if (!mVcrToolbar) return false;
return mVcrToolbar->isVisible();
}
void DicomImageView::setVCRVisible(bool visible) {
if (!mVcrToolbar) return;
mVcrToolbar->setVisible(visible);
}
void DicomImageView::cineModeOn() {
if (!mVcrToolbar) return;
//updateVCRToolbarPos();
int ax = (this->geometry().bottomLeft().x() + this->geometry().bottomRight().x()) / 2 + VCRHelper::getVCRXOffset();
int ay = (this->geometry().bottomLeft().y() + this->geometry().bottomRight().y()) / 2 + VCRHelper::getVCRYOffset();
mVcrToolbar->move(ax, ay);
mVcrToolbar->show();
this->initCineModeThread();
mVcrToolbar->reConnectController(mVcrController);
}
void DicomImageView::initCineModeThread() {
mVcrController = new pqVCRController(nullptr, this);
mVcrController->moveToThread(&mVcrControlThread);
connect(&mVcrControlThread, &QThread::finished, mVcrController, &QObject::deleteLater);
mVcrControlThread.start();
mIsCine = true;
}
void DicomImageView::onFirstFrame() {
if (hasSeries()) {
mScrollBar->setValue(mImageViewer->GetSliceMin());
}
}
void DicomImageView::onPreviousFrame() {
if (hasSeries()) {
int slice = mImageViewer->GetSlice();
slice = --slice;
int min_slice = mImageViewer->GetSliceMin();
if (slice < min_slice) {
slice = mImageViewer->GetSliceMax();
}
mScrollBar->setValue(slice);
}
}
void DicomImageView::onNextFrame() {
if (hasSeries()) {
int slice = mImageViewer->GetSlice();
slice = ++slice;
int max_slice = mImageViewer->GetSliceMax();
if (slice > max_slice) {
slice = mImageViewer->GetSliceMin();
}
mScrollBar->setValue(slice);
}
}
void DicomImageView::onLastFrame() {
if (hasSeries()) {
mScrollBar->setValue(mImageViewer->GetSliceMax());
}
}
//-- Measure about--------------------------------------------------------------------------------------
void DicomImageView::activeMeasure(Measure *m) {
if (nullptr != mSeries) {
mImageViewer->ActiveMeasure(m);
}
}
void DicomImageView::unactiveMeasure() {
if (nullptr != mSeries) {
mImageViewer->UnActiveMeasure();
}
}
void DicomImageView::deleteSelectedMeasure() {
if (nullptr != mSeries) {
mImageViewer->DeleteSelectedMeasure();
}
}
void DicomImageView::deleteCurrentSliceMeasure() {
if (nullptr != mSeries) {
mImageViewer->DeleteCurrentSliceMeasure();
}
}
void DicomImageView::deleteCurrentSeriesMeasure() {
if (nullptr != mSeries) {
mImageViewer->DeleteCurrentSeriesMeasure();
}
}
void DicomImageView::removeViewWithMeasure() {
mImageViewer->UnActiveMeasure();
mImageViewer->DeleteCurrentSeriesMeasure();
}
bool DicomImageView::checkFusion(DicomImageView *base, DicomImageView *overlap) {
SeriesImageSet *baseSeries = base->getSeriesInstance();
SeriesImageSet *overlapSeries = overlap->getSeriesInstance();
// no data
if (!base->hasSeries() || !overlap->hasSeries()) return false;
// diff study
if (baseSeries->getStudyUID() == nullptr ||
strcmp(baseSeries->getStudyUID(), overlapSeries->getStudyUID()) != 0)
return false;
//same series
if (baseSeries->GetSeriesNumber() == overlapSeries->GetSeriesNumber()) return false;
// not enough slice
if (baseSeries->GetProperty()->GetSliceCount() < 20 ||
overlapSeries->GetProperty()->GetSliceCount() < 20) return false;
// check intersect
if(!baseSeries->IntersectWorldBounds(overlapSeries)) return false;
// check current slice orientation
return base->CompareReconPlane(overlap);
}
bool DicomImageView::checkFusion(DicomImageView *overlap) {
return DicomImageView::checkFusion(this, overlap);
}
bool DicomImageView::checkMPRAble(DicomImageView *view) {
return (view->getSeriesInstance()->GetProperty()->GetSliceCount() > 20 );
}