diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7475d71..750f1f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,7 +19,7 @@ include_directories(
)
#set(VTK_DIR "D:/Libs/binary/VTK8.1.2/lib/cmake/vtk-8.2")
-set(VTK_DIR "D:/Libs/binary/VTK9.2.2/lib/cmake/vtk-9.2")
+set(VTK_DIR "D:/Libs/binary/VTK9.2.2win11/lib/cmake/vtk-9.2")
set(Qt5_DIR "D:/Qt/Qt5.12.0/5.12.0/msvc2017_64/lib/cmake/Qt5")
set(DCMTK_DIR "D:/Libs/binary/DCMTK/cmake")
diff --git a/src/Icon/crosshair.png b/src/Icon/crosshair.png
new file mode 100644
index 0000000..4ff4a70
Binary files /dev/null and b/src/Icon/crosshair.png differ
diff --git a/src/QDicomViewer.qrc b/src/QDicomViewer.qrc
index f8bbca3..ab665d8 100644
--- a/src/QDicomViewer.qrc
+++ b/src/QDicomViewer.qrc
@@ -58,6 +58,7 @@
Icon/Settings.png
Icon/preset.png
Icon/diameter.png
+ Icon/crosshair.png
Icon/pq/pqBold24.png
diff --git a/src/src/Common/QGlobals.h b/src/src/Common/QGlobals.h
index 80e3efc..a977bd7 100644
--- a/src/src/Common/QGlobals.h
+++ b/src/src/Common/QGlobals.h
@@ -83,6 +83,7 @@ enum AnnotationActorType
EllipseAnn,
DiameterAnn,
TextAnn,
+ SyncPoint
};
enum AnnotationDeleteType{
DeleteSelectedAnn,
diff --git a/src/src/Interaction/ActorDraggableInteractorStyle.cpp b/src/src/Interaction/ActorDraggableInteractorStyle.cpp
index 39a3eef..4950f9b 100644
--- a/src/src/Interaction/ActorDraggableInteractorStyle.cpp
+++ b/src/src/Interaction/ActorDraggableInteractorStyle.cpp
@@ -3,7 +3,9 @@
#include
#include
+#include
#include
+
#include
#include
#include
@@ -16,8 +18,11 @@
#include
#include
#include
+#include
+
#include "Rendering/Core/DraggableActor.h"
+#include "Rendering/Measure/CrossCursorAnnotationActor.h"
#include "Common/QGlobals.h"
vtkStandardNewMacro(ActorDraggableInteractorStyle)
@@ -126,6 +131,9 @@ void ActorDraggableInteractorStyle::OnLeftButtonDown() {
} else if (this->InteractionMode == VTKIS_IMAGE_SLICING) {
this->StartSlice();
}
+ else if(this->InteractionMode == VTKIS_SYNCPOINT){
+ this->StartSyncSlicePoint();
+ }
}
@@ -175,6 +183,9 @@ void ActorDraggableInteractorStyle::OnLeftButtonUp() {
case VTKIS_COLORMAP:
this->EndColorMapping();
break;
+ case VTKIS_SYNCPOINT:
+ this->EndSyncSlicePoint();
+ break;
}
vtkInteractorStyleImage::OnLeftButtonUp();
}
@@ -219,6 +230,10 @@ void ActorDraggableInteractorStyle::OnMouseMove() {
this->ColorMapping();
this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
break;
+ case VTKIS_SYNCPOINT:
+ this->SyncSlicePoint();
+ this->InvokeEvent(vtkCommand::InteractionEvent, nullptr);
+ break;
}
vtkInteractorStyleImage::OnMouseMove();
@@ -368,6 +383,74 @@ void ActorDraggableInteractorStyle::Slice() {
this->InvokeEvent(SliceEvent, p);
}
+void ActorDraggableInteractorStyle::StartSyncSlicePoint()
+{
+ this->StartState(VTKIS_SYNCPOINT);
+ vtkNew cross;
+
+ int *pos = this->Interactor->GetEventPosition();
+ this->FindPokedRenderer(pos[0], pos[1]);
+ this->CurrentRenderer->SetDisplayPoint(pos[0], pos[1], 0.0);
+ this->CurrentRenderer->DisplayToWorld();
+ cross->SetRenderer(this->CurrentRenderer);
+ cross->Transform(pos[0] , pos[1] );
+ dragProp = cross;
+ this->InvokeEvent(StartSyncSlicePointEvent,nullptr);
+ SyncSlicePoint();
+ this->Interactor->Render();
+}
+
+void ActorDraggableInteractorStyle::EndSyncSlicePoint()
+{
+ if (this->State != VTKIS_SYNCPOINT) {
+ return;
+ }
+ this->StopState();
+ DraggableActor::SafeDownCast(dragProp)->SetRenderer(nullptr);
+ // dragProp->Delete();
+ dragProp = nullptr;
+ this->InvokeEvent(EndSyncSlicePointEvent,nullptr);
+ this->Interactor->Render();
+}
+
+void ActorDraggableInteractorStyle::SyncSlicePoint()
+{
+ int *pos = this->Interactor->GetEventPosition();
+ this->FindPokedRenderer(pos[0], pos[1]);
+ CrossCursorAnnotationActor::SafeDownCast(dragProp)->Transform(pos[0] , pos[1] );
+ this->Interactor->Render();
+ this->InvokeEvent(SyncSlicePointEvent,CrossCursorAnnotationActor::SafeDownCast(dragProp)->GetWorldSlicePoint());
+}
+
+void ActorDraggableInteractorStyle::AdjustSyncCrossPoint(double* aPoint)
+{
+ if(dragProp == nullptr)
+ {
+ if (CurrentRenderer == nullptr) return;
+ if (aPoint == nullptr) return;
+ if (CurrentImageSlice == nullptr) return;
+ // if (box.ContainsPoint(aPoint))
+ {
+ vtkNew cross;
+ cross->SetRenderer(this->CurrentRenderer);
+ cross->Transform(aPoint[0] , aPoint[1] );
+ dragProp = cross;
+ }
+ }
+ else{
+ if (aPoint == nullptr)
+ {
+ DraggableActor::SafeDownCast(dragProp)->SetRenderer(nullptr);
+ // dragProp->Delete();
+ dragProp = nullptr;
+ }
+ else{
+ CrossCursorAnnotationActor::SafeDownCast(dragProp)->Transform(aPoint[0] , aPoint[1] );
+ this->Interactor->Render();
+ }
+ }
+}
+
void ActorDraggableInteractorStyle::StartPan() {
vtkInteractorStyle::StartPan();
vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();
diff --git a/src/src/Interaction/ActorDraggableInteractorStyle.h b/src/src/Interaction/ActorDraggableInteractorStyle.h
index 2e97854..bcefbef 100644
--- a/src/src/Interaction/ActorDraggableInteractorStyle.h
+++ b/src/src/Interaction/ActorDraggableInteractorStyle.h
@@ -115,6 +115,7 @@ vtkTypeMacro(ActorDraggableInteractorStyle, vtkInteractorStyleImage);
{
return CurrentImageSlice;
}
+ void AdjustSyncCrossPoint(double* aPoint);
protected:
@@ -170,6 +171,12 @@ protected:
void NoneStatePick();
+ void StartSyncSlicePoint();
+
+ void EndSyncSlicePoint() ;
+
+ void SyncSlicePoint();
+
void DispatchEvent();
diff --git a/src/src/Rendering/Core/RenderingDefines.h b/src/src/Rendering/Core/RenderingDefines.h
index b7298a7..42f04bd 100644
--- a/src/src/Rendering/Core/RenderingDefines.h
+++ b/src/src/Rendering/Core/RenderingDefines.h
@@ -8,6 +8,7 @@
#define VTKIS_DRAG 33
#define VTKIS_MEASURE 36
#define VTKIS_COLORMAP 37
+#define VTKIS_SYNCPOINT 38
#define VTKIS_IMAGE_PAN 5
#define VTKIS_IMAGE_ZOOM 6
#define VTKIS_IMAGE_WINDOWLEVEL 7
@@ -34,7 +35,10 @@ enum DraggableStyleEvents {
RightButtonClickEvent,
ScalarOpacityEvent,
ScalarShiftEvent,
- AfterViewerClicked
+ AfterViewerClicked,
+ StartSyncSlicePointEvent,
+ SyncSlicePointEvent,
+ EndSyncSlicePointEvent
};
diff --git a/src/src/Rendering/Measure/CrossCursorAnnotationActor.cpp b/src/src/Rendering/Measure/CrossCursorAnnotationActor.cpp
new file mode 100644
index 0000000..0d0fbc8
--- /dev/null
+++ b/src/src/Rendering/Measure/CrossCursorAnnotationActor.cpp
@@ -0,0 +1,72 @@
+#include "CrossCursorAnnotationActor.h"
+
+#include "Rendering/Source/vtkCrossCursorSource.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+vtkStandardNewMacro(CrossCursorAnnotationActor)
+
+CrossCursorAnnotationActor::CrossCursorAnnotationActor()
+ : DraggableActor(){
+ BaseDataPoints->SetNumberOfPoints(1);
+ BaseDataPoints->SetPoint(0, 0, 0, 0);
+
+ renderPoints->SetNumberOfPoints(1);
+ renderPoints->SetPoint(0, 0, 0, 0);
+
+ this->AddObserver(DraggableActorEvents::DragEvent, this, &CrossCursorAnnotationActor::selfDragCb);
+ this->actor2D->GetProperty()->SetLineWidth(1.0);
+ this->shadow2D->GetProperty()->SetLineWidth(2);
+ this->shadow2D->SetVisibility(1);
+
+}
+
+CrossCursorAnnotationActor::~CrossCursorAnnotationActor() {
+
+}
+
+void CrossCursorAnnotationActor::SetWorldPosition1(double x, double y, double z) {
+ BaseDataPoints->SetPoint(0, x, y, z);
+}
+
+void CrossCursorAnnotationActor::BuildShape() {
+ if (!BaseDataPoints->GetNumberOfPoints()) return;
+ // RebuildRenderPoint();
+ vtkNew source;
+ source->SetPoints(renderPoints);
+ source->Update();
+ renderData->DeepCopy(source->GetOutput());
+}
+
+void CrossCursorAnnotationActor::SetRenderer(vtkRenderer *ren) {
+ DraggableActor::SetRenderer(ren);
+}
+
+void CrossCursorAnnotationActor::selfDragCb(vtkObject *, unsigned long, void *data) {
+ vtkPoints *pts = static_cast(data);
+ double *pos = pts->GetPoint(0);
+
+}
+
+void CrossCursorAnnotationActor::onMeasureMouseMove(vtkRenderWindowInteractor *iren) {
+}
+
+void CrossCursorAnnotationActor::Transform(float x, float y)
+{
+ this->actor2D->SetDisplayPosition(x,y);
+ MapScreenPointToWorld(x,y, this->Renderer, WorldSlicePoint);
+}
+
+bool CrossCursorAnnotationActor::onMeasureLeftButtonDown(vtkRenderWindowInteractor *iren)
+{
+ return true;
+}
+
+bool CrossCursorAnnotationActor::onMeasureLeftButtonUp(vtkRenderWindowInteractor *iren) {
+ return false;
+}
diff --git a/src/src/Rendering/Measure/CrossCursorAnnotationActor.h b/src/src/Rendering/Measure/CrossCursorAnnotationActor.h
new file mode 100644
index 0000000..e499c15
--- /dev/null
+++ b/src/src/Rendering/Measure/CrossCursorAnnotationActor.h
@@ -0,0 +1,60 @@
+#ifndef OMEGAV_CROSSCURSORANNOTATIONACTOR_H
+
+#define OMEGAV_CROSSCURSORANNOTATIONACTOR_H
+
+
+#include "Rendering/Core/DraggableActor.h"
+#include "Rendering/Measure/Measure.h"
+
+
+class CrossCursorAnnotationActor : public DraggableActor, public Measure {
+public:
+ //@{
+ /**
+ * Standard methods for instances of this class.
+ */
+ static CrossCursorAnnotationActor *New();
+
+ vtkTypeMacro(CrossCursorAnnotationActor, DraggableActor);
+
+ //@}
+ void SetRenderer(vtkRenderer *ren) override;
+
+ void BuildShape() override;
+
+ void SetWorldPosition1(double x, double y, double z);
+
+ void SetWorldPosition1(double *pos) {
+ SetWorldPosition1(pos[0], pos[1], pos[2]);
+ }
+
+ void Transform(float x, float y) override;
+ bool onMeasureLeftButtonDown(vtkRenderWindowInteractor *) override;
+
+ void onMeasureMouseMove(vtkRenderWindowInteractor *) override;
+
+ bool onMeasureLeftButtonUp(vtkRenderWindowInteractor *) override;
+
+ // NextMeasureMacro(LineAnnotationActor);
+
+ void ForceDelete() override {
+ this->SetRenderer(nullptr);
+ DraggableActor::Delete();
+ }
+
+ vtkGetVector3Macro(WorldSlicePoint,vtkTypeFloat64);
+
+protected:
+ CrossCursorAnnotationActor();
+
+
+ ~CrossCursorAnnotationActor() override;
+
+ void selfDragCb(vtkObject *, unsigned long event, void *data);
+
+ double WorldSlicePoint[3] = {.0,.0,.0};
+
+};
+
+
+#endif //OMEGAV_CROSSCURSORANNOTATIONACTOR_H
diff --git a/src/src/Rendering/Measure/EllipseAnnotationActor.cpp b/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
index 26bd26e..d7144d7 100644
--- a/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
+++ b/src/src/Rendering/Measure/EllipseAnnotationActor.cpp
@@ -281,8 +281,8 @@ void EllipseAnnotationActor::drawCircle(double *p1, double *p2) {
nIndex[0] = 1;
nIndex[1] = 2;
}
- int CenterX = (p1[nIndex[0]] + p2[nIndex[0]] ) / 2.0;
- int CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
+ double CenterX = (p1[nIndex[0]] + p2[nIndex[0]] ) / 2.0;
+ double CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
double r1 = round(abs(p1[nIndex[0]] - p2[nIndex[0]]) / 2.0*100.0)/100;
double r2 = round(abs(p1[nIndex[1]]- p2[nIndex[1]]) / 2.0*100.0)/100;
diff --git a/src/src/Rendering/Measure/RoundAnnotationActor.cpp b/src/src/Rendering/Measure/RoundAnnotationActor.cpp
index c86fdde..fbfb622 100644
--- a/src/src/Rendering/Measure/RoundAnnotationActor.cpp
+++ b/src/src/Rendering/Measure/RoundAnnotationActor.cpp
@@ -274,11 +274,11 @@ void RoundAnnotationActor::drawCircle(double *p1, double *p2) {
double r2 = round(abs(p1[nIndex[1]]- p2[nIndex[1]]) / 2.0*100.0)/100;
double r = r1r){
CenterX = CenterX > p2[nIndex[0]]?(r+p2[nIndex[0]]):(p2[nIndex[0]]-r);
}
- int CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
+ double CenterY = (p1[nIndex[1]] + p2[nIndex[1]] ) / 2.0;
if (abs(CenterY-p2[nIndex[1]])>r){
CenterY = CenterY > p2[nIndex[1]]?(r+p2[nIndex[1]]):(p2[nIndex[1]]-r);
}
diff --git a/src/src/Rendering/Source/vtkCrossCursorSource.cpp b/src/src/Rendering/Source/vtkCrossCursorSource.cpp
new file mode 100644
index 0000000..463e2ce
--- /dev/null
+++ b/src/src/Rendering/Source/vtkCrossCursorSource.cpp
@@ -0,0 +1,60 @@
+
+#include "vtkCrossCursorSource.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+
+//----------------------------------------------------------------------------
+vtkStandardNewMacro(vtkCrossCursorSource)
+
+//----------------------------------------------------------------------------
+vtkCrossCursorSource::vtkCrossCursorSource() {
+ this->Closed = 0;
+}
+
+//----------------------------------------------------------------------------
+vtkCrossCursorSource::~vtkCrossCursorSource() {}
+
+//----------------------------------------------------------------------------
+int vtkCrossCursorSource::RequestData(vtkInformation * vtkNotUsed(request),
+ vtkInformationVector ** vtkNotUsed(inputVector), vtkInformationVector *outputVector) {
+ // get the info object
+ vtkInformation *outInfo = outputVector->GetInformationObject(0);
+
+ // get the output
+ vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()));
+ vtkIdType numPoints = this->GetNumberOfPoints();
+ // must have a mouse point point
+ if (numPoints < 1) return 1;
+ vtkNew pts;
+ vtkNew lines;
+ double centerPt[3] = {0.0, 0.0, 0.0};
+ this->Points->GetPoint(0, centerPt);
+ vtkIdType pids[2];
+ // pts->InsertNextPoint(centerPt[0]-10, centerPt[1], 0);
+ // pts->InsertNextPoint(centerPt[0]+10, centerPt[1], 0);
+ // lines->InsertNextCell(2, pids);
+ // pts->InsertNextPoint(centerPt[0], centerPt[1]-5, 0);
+ // pts->InsertNextPoint(centerPt[0], centerPt[1]+5, 0);
+ // lines->InsertNextCell(2, pids);
+
+
+ pids[0] = pts->InsertNextPoint(centerPt[0] - 3, centerPt[1], 0);
+ pids[1] = pts->InsertNextPoint(centerPt[0] - 20, centerPt[1], 0);
+ lines->InsertNextCell(2, pids);
+ pids[0] = pts->InsertNextPoint(centerPt[0] + 3, centerPt[1], 0);
+ pids[1] = pts->InsertNextPoint(centerPt[0] + 20, centerPt[1], 0);
+ lines->InsertNextCell(2, pids);
+ pids[0] = pts->InsertNextPoint(centerPt[0], centerPt[1] - 3, 0);
+ pids[1] = pts->InsertNextPoint(centerPt[0], centerPt[1] - 20, 0);
+ lines->InsertNextCell(2, pids);
+ pids[0] = pts->InsertNextPoint(centerPt[0], centerPt[1] + 3, 0);
+ pids[1] = pts->InsertNextPoint(centerPt[0], centerPt[1] + 20, 0);
+ lines->InsertNextCell(2, pids);
+ output->SetPoints(pts);
+ output->SetLines(lines);
+ return 1;
+}
+
+void vtkCrossCursorSource::PrintSelf(ostream &os, vtkIndent indent) {
+ vtkPolyLineSource::PrintSelf(os, indent);
+}
diff --git a/src/src/Rendering/Source/vtkCrossCursorSource.h b/src/src/Rendering/Source/vtkCrossCursorSource.h
new file mode 100644
index 0000000..061df9e
--- /dev/null
+++ b/src/src/Rendering/Source/vtkCrossCursorSource.h
@@ -0,0 +1,32 @@
+#ifndef OMEGAV_VTKCROSSCURSORSOURCE_H
+#define OMEGAV_VTKCROSSCURSORSOURCE_H
+
+
+#include
+
+class vtkCrossCursorSource : public vtkPolyLineSource {
+public:
+ /**
+ * Construct cone with angle of 45 degrees.
+ */
+ static vtkCrossCursorSource *New();
+
+ vtkTypeMacro(vtkCrossCursorSource, vtkPolyDataAlgorithm);
+
+ void PrintSelf(ostream &os, vtkIndent indent) override;
+protected:
+ vtkCrossCursorSource();
+
+ ~vtkCrossCursorSource() override;
+
+ int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override;
+
+private:
+ vtkCrossCursorSource(const vtkCrossCursorSource &) = delete;
+
+ void operator=(const vtkCrossCursorSource &) = delete;
+
+};
+
+
+#endif /* OMEGAV_VTKCROSSCURSORSOURCE_H */
diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.cxx b/src/src/Rendering/Viewer/DICOMImageViewer.cxx
index e8e61b2..5b4e61e 100644
--- a/src/src/Rendering/Viewer/DICOMImageViewer.cxx
+++ b/src/src/Rendering/Viewer/DICOMImageViewer.cxx
@@ -313,7 +313,6 @@ void DICOMImageViewer::InstallPipeline() {
if (!this->InteractorStyle) {
this->InteractorStyle = ActorDraggableInteractorStyle::New();
this->InteractorStyle->SetInteractionModeToImageSlicing();
- this->InteractorStyle->SetCurrentImageNumber(0);
this->InteractorStyle->SetCornerAnnotation(cornerAnnotation);
this->InteractorStyle->AddObserver(DraggableStyleEvents::EndMeasureEvent,
@@ -333,6 +332,12 @@ void DICOMImageViewer::InstallPipeline() {
this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndWindowLevelEvent, this,
&DICOMImageViewer::raiseEvent);
this->InteractorStyle->AddObserver(vtkCommand::EventIds::EndPanEvent, this, &DICOMImageViewer::raiseEvent);
+
+ this->InteractorStyle->AddObserver(DraggableStyleEvents::StartSyncSlicePointEvent, this, &DICOMImageViewer::raiseEvent);
+ this->InteractorStyle->AddObserver(DraggableStyleEvents::SyncSlicePointEvent, this, &DICOMImageViewer::raiseEvent);
+
+ this->InteractorStyle->AddObserver(DraggableStyleEvents::EndSyncSlicePointEvent, this, &DICOMImageViewer::raiseEvent);
+
}
this->Interactor->SetInteractorStyle(this->InteractorStyle);
@@ -467,7 +472,14 @@ void DICOMImageViewer::SetSlice(int slice) {
}
int lastSliceNumber = this->ImageMapper->GetSliceNumber();
+ if (InteractorStyle){
+ if (slice == 0){
+ InteractorStyle->SetCurrentRenderer(this->Renderer);
+ InteractorStyle->SetCurrentImageNumber(0);
+ }
+ }
if (lastSliceNumber == slice) {
+
return;
}
@@ -496,10 +508,6 @@ 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);
@@ -620,6 +628,33 @@ void DICOMImageViewer::SyncSliceWithFocus(double *point)
UpdateTopLeftCornerInfo();
}
+void DICOMImageViewer::SyncSlicePointSameDirection(double *point) {
+ if (point == nullptr){
+ this->ActiveReferenceLine();
+ this->InteractorStyle->AdjustSyncCrossPoint(nullptr);
+ this->Render();
+ }
+ else{
+ double focusPoint[4] = {point[0], point[1], point[2], 1.0};
+ WorldToModelMatrix->MultiplyPoint(focusPoint, focusPoint);
+ double f[3] = {.0, .0, .0};
+ Renderer->GetActiveCamera()->GetFocalPoint(f);
+ double bounds[6] = {.0, .0, .0, .0, .0, .0};
+ ImageMapper->GetBounds(bounds);
+ double displayPoint [3] ={.0};
+ Renderer->SetWorldPoint(focusPoint);
+ Renderer->WorldToDisplay();
+ Renderer->GetDisplayPoint(displayPoint);
+ f[SliceIJK] = focusPoint[SliceIJK];
+ Renderer->GetActiveCamera()->SetFocalPoint(f);
+ this->UnActiveReferenceLine();
+ this->InteractorStyle->AdjustSyncCrossPoint(displayPoint);
+ this->Render();
+ UpdateTopLeftCornerInfo();
+ Slice = ImageMapper->GetSliceNumber();
+ }
+}
+
// zoom------------------------------------------------------------------------
void DICOMImageViewer::SetZoomScale(double scale) {
if (Renderer) {
diff --git a/src/src/Rendering/Viewer/DICOMImageViewer.h b/src/src/Rendering/Viewer/DICOMImageViewer.h
index ce2ed00..c12e704 100644
--- a/src/src/Rendering/Viewer/DICOMImageViewer.h
+++ b/src/src/Rendering/Viewer/DICOMImageViewer.h
@@ -373,6 +373,8 @@ public:
return &raiser;
}
+ void SyncSlicePointSameDirection(double *point);
+
void SyncSliceWithFocus(double *point);
diff --git a/src/src/UI/Manager/ImageViewManager.cpp b/src/src/UI/Manager/ImageViewManager.cpp
index b0abbc5..d29a1a3 100644
--- a/src/src/UI/Manager/ImageViewManager.cpp
+++ b/src/src/UI/Manager/ImageViewManager.cpp
@@ -57,6 +57,8 @@ void ImageViewManager::add(DicomImageView *view) {
connect(view, &DicomImageView::onSlice,
this, &ImageViewManager::viewSliced);
+ connect(view, &DicomImageView::onSyncPointSlice,
+ this, &ImageViewManager::viewSyncPoint);
connect(view, &DicomImageView::onEndPan,
this, &ImageViewManager::viewPaned);
connect(view, &DicomImageView::onEndZoom,
@@ -294,6 +296,20 @@ void ImageViewManager::viewSliced(DicomImageView *src, void *sliceData) {
renderReferenceLine();
}
+void ImageViewManager::viewSyncPoint(DicomImageView *src, void * sliceData){
+ //Sync slice Point
+ if ( src->getImageViewer()->GetInteractorStyle()->GetInteractionMode() == VTKIS_SYNCPOINT){
+ this->smartDo(nullptr,[](auto v, auto callData) {
+ if (v->hasSeries()) {
+ double *r = (double *) callData;
+ v->syncSliceWithPoint(r);
+ v->SyncScrollBar();
+ }
+ }, src, sliceData, ImageViewManager::SameSeries);
+ }
+}
+
+
void ImageViewManager::renderReferenceLine() {
vtkPoints* pts = currentView->hasSeries() ? currentView->getSliceBoundPoints() : nullptr;
smartDo([](auto v, auto callData) {
diff --git a/src/src/UI/Manager/ImageViewManager.h b/src/src/UI/Manager/ImageViewManager.h
index 663fc16..6594255 100644
--- a/src/src/UI/Manager/ImageViewManager.h
+++ b/src/src/UI/Manager/ImageViewManager.h
@@ -61,6 +61,8 @@ public:
void viewDoubleClicked(DicomImageView *view);
+ void viewSyncPoint(DicomImageView *src, void * sliceData);
+
void viewSliced(DicomImageView *src, void *sliceData);
void viewPaned(DicomImageView *src, void* offsetVector);
diff --git a/src/src/UI/Widget/ImageView/dicomimageview.cpp b/src/src/UI/Widget/ImageView/dicomimageview.cpp
index cb4e5a3..b61f8d7 100644
--- a/src/src/UI/Widget/ImageView/dicomimageview.cpp
+++ b/src/src/UI/Widget/ImageView/dicomimageview.cpp
@@ -2,6 +2,8 @@
#include
#include
+#include
+
#include
#include
#include
@@ -488,6 +490,29 @@ void DicomImageView::dispatchEvent(vtkObject *, unsigned long eid, void *callDat
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;
}
diff --git a/src/src/UI/Widget/ImageView/dicomimageview.h b/src/src/UI/Widget/ImageView/dicomimageview.h
index 1b7598e..09fba9f 100644
--- a/src/src/UI/Widget/ImageView/dicomimageview.h
+++ b/src/src/UI/Widget/ImageView/dicomimageview.h
@@ -177,6 +177,10 @@ public:
return this->mImageViewer->GetReconPlane() == view->mImageViewer->GetReconPlane();
}
+ void syncSliceWithPoint(double *point) {
+ mImageViewer->SyncSlicePointSameDirection(point);
+ }
+
void syncSliceFocus(double *point) {
mImageViewer->SyncSliceWithFocus(point);
}
@@ -220,6 +224,8 @@ signals:
void onSlice(DicomImageView *view, void *calldata);
+ void onSyncPointSlice(DicomImageView *view, void *calldata);
+
void onEndPan(DicomImageView *view, void * offsetVector);
void onEndZoom(DicomImageView *view, double* scaleFactor);
diff --git a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
index 38b065e..cf58bf0 100644
--- a/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
+++ b/src/src/UI/Widget/ToolBar/DefaultToolBar.cpp
@@ -17,7 +17,7 @@ namespace {
const char *SYNC_MANUAL_URL = ":/InfiniteViewer/Icon/sync/sync_manual.png";
const char *SYNC_AUTO_URL = ":/InfiniteViewer/Icon/sync/sync_auto.png";
const char *SYNC_DIS_URL = ":/InfiniteViewer/Icon/sync/sync_dis.png";
- const int ACTION_COUNT = 8;
+ const int ACTION_COUNT = 9;
const ActionProperty MEASURE_ACTIIONS[ACTION_COUNT] = {
{ ":/InfiniteViewer/Icon/distance.png", AnnotationActorType::RulerAnn},
{ ":/InfiniteViewer/Icon/angle.png", AnnotationActorType::AngleAnn},
@@ -26,7 +26,9 @@ namespace {
{ ":/InfiniteViewer/Icon/arrow.png", AnnotationActorType::ArrowAnn},
{ ":/InfiniteViewer/Icon/ellipse.png", AnnotationActorType::EllipseAnn},
{ ":/InfiniteViewer/Icon/diameter.png", AnnotationActorType::DiameterAnn},
- { ":/InfiniteViewer/Icon/text.png", AnnotationActorType::TextAnn}
+ { ":/InfiniteViewer/Icon/text.png", AnnotationActorType::TextAnn},
+ { ":/InfiniteViewer/Icon/crosshair.png", AnnotationActorType::SyncPoint}
+
};
}
@@ -413,9 +415,13 @@ void DefaultToolBar::initMeasureButton() {
QMenu *m;
m = new QMenu(this);
- for (int j = 0; j < ACTION_COUNT; ++j) {
+ for (int j = 0; j < ACTION_COUNT-1; ++j) {
ADD_MEASURE_ACTION(j);
}
+
+ m->addAction(tr("Location Point"), this,[=](){
+ emit modeChanged(38);
+ });
m->addSeparator();
ADD_DEL_ACTION(tr("Delete selected"), AnnotationDeleteType::DeleteSelectedAnn);
ADD_DEL_ACTION(tr("Delete all in current slice"), AnnotationDeleteType::DeleteSliceAnn);
@@ -423,10 +429,7 @@ void DefaultToolBar::initMeasureButton() {
mBtnMeasure->setPopupMode(QToolButton::MenuButtonPopup);
mBtnMeasure->setMenu(m);
- m->addSeparator();
- // m->addAction(tr("Localtion Point"), this,[=](){
- // emit modeChanged(38);
- // });
+
}
void DefaultToolBar::initFusionButton() {
diff --git a/src/translations/en_US.ts b/src/translations/en_US.ts
index e136d33..7688141 100644
--- a/src/translations/en_US.ts
+++ b/src/translations/en_US.ts
@@ -261,6 +261,11 @@
Text
+
+
+ Location Point
+
+
Custom window width and level
@@ -297,112 +302,112 @@
-
+
Delete selected
-
+
Delete all in current slice
-
+
Delete all in current series
-
+
Fusion
-
+
Cine
-
+
Delete current series
-
+
Transformations
-
+
Rotate 90 CCW
-
+
Rotate 90 CW
-
+
Rotate 180
-
+
Flip horizontal
-
+
Flip vertical
-
+
Clear transformations
-
+
MPR
-
+
3D MPR
-
+
Coronal
-
+
Sagittal
-
+
Axial
-
+
Full screen
-
+
Exit full screen mode
-
+
Minimize
-
+
Close
@@ -410,12 +415,12 @@
DicomImageView
-
+
Error
-
+
Unable to read file %1
diff --git a/src/translations/zh_CN.ts b/src/translations/zh_CN.ts
index 59df120..7938452 100644
--- a/src/translations/zh_CN.ts
+++ b/src/translations/zh_CN.ts
@@ -337,112 +337,117 @@
测量工具
-
+
Delete selected
删除选中
-
+
Delete all in current slice
删除当前图像中所有测量
-
+
Delete all in current series
删除当前序列所有图像
-
+
+ Location Point
+ 病灶定位
+
+
+
Fusion
-
+
Cine
-
+
Delete current series
删除当前序列所有测量
-
+
Transformations
翻页&旋转
-
+
Rotate 90 CCW
逆时针旋转90度
-
+
Rotate 90 CW
顺时针旋转90度
-
+
Rotate 180
旋转180度
-
+
Flip horizontal
水平翻转
-
+
Flip vertical
垂直翻转
-
+
Clear transformations
清除变换
-
+
MPR
多平面重建
-
+
3D MPR
-
+
Coronal
冠状面
-
+
Sagittal
矢状面
-
+
Axial
横断面
-
+
Full screen
全屏
-
+
Exit full screen mode
退出全屏
-
+
Minimize
最小化
-
+
Close
关闭
@@ -450,12 +455,12 @@
DicomImageView
-
+
Error
错误
-
+
Unable to read file %1
无法读取文件 %1