Orientation marker click change volume view orientation.
This commit is contained in:
@@ -20,11 +20,11 @@
|
|||||||
#include <vtkCornerAnnotation.h>
|
#include <vtkCornerAnnotation.h>
|
||||||
#include <vtkPlane.h>
|
#include <vtkPlane.h>
|
||||||
#include <vtkBoundingBox.h>
|
#include <vtkBoundingBox.h>
|
||||||
#include <vtkOrientationMarkerWidget.h>
|
|
||||||
#include <vtkAnnotatedCubeActor.h>
|
#include <vtkAnnotatedCubeActor.h>
|
||||||
|
#include <vtkVectorText.h>
|
||||||
|
|
||||||
#include "Interaction/VolumeInteractorStyle.h"
|
#include "Interaction/VolumeInteractorStyle.h"
|
||||||
|
#include "Rendering/Widget/ClickableOrientationMarkerWidget.h"
|
||||||
#include "IO/DICOM/ExtendMedicalImageProperties.h"
|
#include "IO/DICOM/ExtendMedicalImageProperties.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -36,6 +36,36 @@ namespace {
|
|||||||
Superior,
|
Superior,
|
||||||
Inferior
|
Inferior
|
||||||
};
|
};
|
||||||
|
const char VIEW_FIRST_LETTER[7] = "APLRHF";
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetViewDirection(vtkAnnotatedCubeActor* cube,int orientation){
|
||||||
|
char faceText = 'A';
|
||||||
|
switch (orientation){
|
||||||
|
case 0:
|
||||||
|
faceText = cube->GetXMinusFaceText()[0];
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
faceText = cube->GetXPlusFaceText()[0];
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
faceText = cube->GetYMinusFaceText()[0];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
faceText = cube->GetYPlusFaceText()[0];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
faceText = cube->GetZMinusFaceText()[0];
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
faceText = cube->GetZPlusFaceText()[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
if (VIEW_FIRST_LETTER[i]==faceText)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vtkStandardNewMacro(VolumeRenderingViewer);
|
vtkStandardNewMacro(VolumeRenderingViewer);
|
||||||
@@ -50,7 +80,7 @@ VolumeRenderingViewer::VolumeRenderingViewer()
|
|||||||
, InteractorStyle(nullptr)
|
, InteractorStyle(nullptr)
|
||||||
, Interactor(nullptr)
|
, Interactor(nullptr)
|
||||||
, firstRender(true)
|
, firstRender(true)
|
||||||
, OrientationMarker(vtkOrientationMarkerWidget::New()){
|
, OrientationMarker(ClickableOrientationMarkerWidget::New()){
|
||||||
if (gpuMode){
|
if (gpuMode){
|
||||||
auto mapper = vtkGPUVolumeRayCastMapper::New();
|
auto mapper = vtkGPUVolumeRayCastMapper::New();
|
||||||
mapper->SetUseJittering(1);
|
mapper->SetUseJittering(1);
|
||||||
@@ -145,7 +175,6 @@ void VolumeRenderingViewer::InstallPipeline() {
|
|||||||
if (this->Interactor) {
|
if (this->Interactor) {
|
||||||
if (!this->InteractorStyle) {
|
if (!this->InteractorStyle) {
|
||||||
auto style = VolumeInteractorStyle::New();
|
auto style = VolumeInteractorStyle::New();
|
||||||
// style->SetInteractionMode(1024);
|
|
||||||
this->InteractorStyle = style;
|
this->InteractorStyle = style;
|
||||||
this->InteractorStyle->AddObserver(vtkCommand::StartWindowLevelEvent,this,
|
this->InteractorStyle->AddObserver(vtkCommand::StartWindowLevelEvent,this,
|
||||||
&VolumeRenderingViewer::DecreaseMaximumImageSampleDistance);
|
&VolumeRenderingViewer::DecreaseMaximumImageSampleDistance);
|
||||||
@@ -261,11 +290,13 @@ void VolumeRenderingViewer::Render() {
|
|||||||
this->OrientationMarker->RemoveAllObservers();
|
this->OrientationMarker->RemoveAllObservers();
|
||||||
this->OrientationMarker->SetInteractor(this->Interactor);
|
this->OrientationMarker->SetInteractor(this->Interactor);
|
||||||
this->OrientationMarker->EnabledOn();
|
this->OrientationMarker->EnabledOn();
|
||||||
this->OrientationMarker->InteractiveOff();
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::WindowResizeEvent, this, &VolumeRenderingViewer::resizeOrientationMarker);
|
this->RenderWindow->AddObserver(vtkCommand::WindowResizeEvent, this, &VolumeRenderingViewer::resizeOrientationMarker);
|
||||||
Render();
|
Render();
|
||||||
|
|
||||||
}
|
}
|
||||||
Interactor->Render();
|
Interactor->Render();
|
||||||
|
renderAnnotation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,14 +349,14 @@ void VolumeRenderingViewer::renderAnnotation() {
|
|||||||
void VolumeRenderingViewer::GetDirectionString(const double *directionVector, std::string &str) const {
|
void VolumeRenderingViewer::GetDirectionString(const double *directionVector, std::string &str) const {
|
||||||
str.clear();
|
str.clear();
|
||||||
char dV [3] = {' ', ' ', ' '};
|
char dV [3] = {' ', ' ', ' '};
|
||||||
if (fabs(directionVector[0]) > 0.5){
|
if (fabs(directionVector[0]) > 0.6){
|
||||||
dV[0] = directionVector[0] > 0 ? 'L' : 'R';
|
dV[0] = directionVector[0] > 0 ? 'L' : 'R';
|
||||||
}
|
}
|
||||||
if (fabs(directionVector[1])>0.5){
|
if (fabs(directionVector[1]) > 0.6){
|
||||||
dV[1] = directionVector[1]>0?'P':'A';
|
dV[1] = directionVector[1]> 0 ? 'P' : 'A';
|
||||||
}
|
}
|
||||||
if (fabs(directionVector[2])>0.5){
|
if (fabs(directionVector[2]) > 0.6){
|
||||||
dV[2] =directionVector[2]>0?'H':'F';
|
dV[2] = directionVector[2] > 0 ? 'H' : 'F';
|
||||||
}
|
}
|
||||||
if (fabs(directionVector[2]) > fabs(directionVector[1])) std::swap(dV[1], dV[2]);
|
if (fabs(directionVector[2]) > fabs(directionVector[1])) std::swap(dV[1], dV[2]);
|
||||||
if (fabs(directionVector[1]) > fabs(directionVector[0])) std::swap(dV[0], dV[1]);
|
if (fabs(directionVector[1]) > fabs(directionVector[0])) std::swap(dV[0], dV[1]);
|
||||||
@@ -348,13 +379,13 @@ char VolumeRenderingViewer::GetDirectionChar(const double *directionVector , int
|
|||||||
worldDirection = 0;
|
worldDirection = 0;
|
||||||
return directionVector[0] > 0 ? 'L' : 'R';
|
return directionVector[0] > 0 ? 'L' : 'R';
|
||||||
}
|
}
|
||||||
if (fabs(directionVector[1])>0.7){
|
if (fabs(directionVector[1]) > 0.7){
|
||||||
worldDirection = 1;
|
worldDirection = 1;
|
||||||
return directionVector[1]>0?'P':'A';
|
return directionVector[1] > 0 ? 'P' : 'A';
|
||||||
}
|
}
|
||||||
if (fabs(directionVector[2])>0.7){
|
if (fabs(directionVector[2]) > 0.7){
|
||||||
worldDirection = 2;
|
worldDirection = 2;
|
||||||
return directionVector[2]>0?'H':'F';
|
return directionVector[2] > 0 ? 'H' : 'F';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,11 +450,25 @@ void VolumeRenderingViewer::SetCoordsTransformMatrix(ExtendMedicalImagePropertie
|
|||||||
cube->SetZFaceTextRotation(-90);
|
cube->SetZFaceTextRotation(-90);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cube->SetTextEdgesVisibility(0);
|
||||||
|
|
||||||
cube->GetTextEdgesProperty()->SetColor(1.0,1.0,.0);
|
cube->GetZMinusFaceProperty()->SetColor(1.0,0.863,.3);
|
||||||
cube->GetTextEdgesProperty()->SetLineWidth(2.0);
|
cube->GetZPlusFaceProperty()->SetColor(1.0,0.863,.3);
|
||||||
cube->GetCubeProperty()->SetColor(.0,.0,1.0);
|
cube->GetYMinusFaceProperty()->SetColor(.839,.784,0.6);
|
||||||
|
cube->GetYPlusFaceProperty()->SetColor(.839,.784,0.6);
|
||||||
|
cube->GetXMinusFaceProperty()->SetColor(.882,.3,0.2);
|
||||||
|
cube->GetXPlusFaceProperty()->SetColor(.882,.3,0.2);
|
||||||
|
cube->GetTextEdgesProperty()->SetEdgeVisibility(0);
|
||||||
|
// cube->GetTextEdgesProperty()->SetEdgeColor(0.149,0.737,.835);
|
||||||
|
// cube->GetTextEdgesProperty()->SetColor(1.0,1.0,.0);
|
||||||
|
// cube->GetTextEdgesProperty()->SetLineWidth(2.0);
|
||||||
|
// cube->GetCubeProperty()->SetEdgeColor(1.0,1.0,.0);
|
||||||
|
// cube->GetCubeProperty()->SetEdgeVisibility(1);
|
||||||
|
cube->GetCubeProperty()->SetColor(0.11,0.471,.539);
|
||||||
|
cube->SetPickable(true);
|
||||||
|
vtkVectorText* text = vtkVectorText::New();
|
||||||
OrientationMarker->SetOrientationMarker(cube);
|
OrientationMarker->SetOrientationMarker(cube);
|
||||||
|
cube->AddObserver(vtkCommand::PickEvent,this,&VolumeRenderingViewer::pressedOrientationMarker);
|
||||||
}
|
}
|
||||||
//change to WToM
|
//change to WToM
|
||||||
OrientationMatrix->Invert();
|
OrientationMatrix->Invert();
|
||||||
@@ -540,3 +585,15 @@ void VolumeRenderingViewer::resizeOrientationMarker() {
|
|||||||
int *size = this->Renderer->GetSize();
|
int *size = this->Renderer->GetSize();
|
||||||
this->OrientationMarker->SetViewport(1.0-(80.0/(double)size[0]),1.0-(80.0/(double)size[1]),1.0,1.0);
|
this->OrientationMarker->SetViewport(1.0-(80.0/(double)size[0]),1.0-(80.0/(double)size[1]),1.0,1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VolumeRenderingViewer::pressedOrientationMarker(vtkObject* sender, unsigned long event, void* data) {
|
||||||
|
vtkVariant* var = static_cast<vtkVariant*>(data);
|
||||||
|
if (var){
|
||||||
|
auto cube = vtkAnnotatedCubeActor::SafeDownCast(OrientationMarker->GetOrientationMarker());
|
||||||
|
if (cube){
|
||||||
|
int v = GetViewDirection(cube,var->ToInt());
|
||||||
|
SetViewDirection(v);
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ private:
|
|||||||
int a;
|
int a;
|
||||||
return GetDirectionChar(directionVector, a);
|
return GetDirectionChar(directionVector, a);
|
||||||
}
|
}
|
||||||
|
void pressedOrientationMarker(vtkObject*, unsigned long, void*);
|
||||||
void resizeOrientationMarker();
|
void resizeOrientationMarker();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/10/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "ClickableOrientationMarkerWidget.h"
|
||||||
|
|
||||||
|
#include <vtkObjectFactory.h>
|
||||||
|
#include <vtkNew.h>
|
||||||
|
#include <vtkRenderWindowInteractor.h>
|
||||||
|
#include <vtkCallbackCommand.h>
|
||||||
|
#include <vtkRenderer.h>
|
||||||
|
#include <vtkPropPicker.h>
|
||||||
|
#include <vtkCamera.h>
|
||||||
|
#include <vtkPlane.h>
|
||||||
|
|
||||||
|
vtkStandardNewMacro(ClickableOrientationMarkerWidget)
|
||||||
|
|
||||||
|
ClickableOrientationMarkerWidget::ClickableOrientationMarkerWidget():vtkOrientationMarkerWidget()
|
||||||
|
, picker(vtkPropPicker::New())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ClickableOrientationMarkerWidget::~ClickableOrientationMarkerWidget() {
|
||||||
|
picker->Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkInCube(double* pt){
|
||||||
|
return fabs(pt[0])<0.5015 && fabs(pt[1])<0.5015 && fabs(pt[2])<0.5015;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClickableOrientationMarkerWidget::OnLeftButtonDown() {
|
||||||
|
// We're only here if we are enabled
|
||||||
|
int X = this->Interactor->GetEventPosition()[0];
|
||||||
|
int Y = this->Interactor->GetEventPosition()[1];
|
||||||
|
|
||||||
|
// are we over the widget?
|
||||||
|
double vp[4];
|
||||||
|
Renderer->GetViewport( vp );
|
||||||
|
|
||||||
|
this->Renderer->NormalizedDisplayToDisplay( vp[0], vp[1] );
|
||||||
|
this->Renderer->NormalizedDisplayToDisplay( vp[2], vp[3] );
|
||||||
|
|
||||||
|
int pos1[2] = { static_cast<int>( vp[0] ), static_cast<int>( vp[1] ) };
|
||||||
|
int pos2[2] = { static_cast<int>( vp[2] ), static_cast<int>( vp[3] ) };
|
||||||
|
|
||||||
|
this->StartPosition[0] = X;
|
||||||
|
this->StartPosition[1] = Y;
|
||||||
|
|
||||||
|
this->State = this->ComputeStateBasedOnPosition( X, Y, pos1, pos2 );
|
||||||
|
// this->SetCursor( this->State );
|
||||||
|
|
||||||
|
if (this->State == vtkOrientationMarkerWidget::Outside)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//add click actor event
|
||||||
|
int result = picker->PickProp(X,Y,this->Renderer);
|
||||||
|
if (result){
|
||||||
|
vtkProp *obj = picker->GetViewProp();
|
||||||
|
this->Renderer->SetDisplayPoint(X,Y,0);
|
||||||
|
this->Renderer->DisplayToWorld();
|
||||||
|
double pt[4] = {.0,.0,.0,.0};
|
||||||
|
this->Renderer->GetWorldPoint(pt);
|
||||||
|
double proj[3] = {.0,.0,.0};
|
||||||
|
this->Renderer->GetActiveCamera()->GetDirectionOfProjection(proj);
|
||||||
|
double pt2[3] = {pt[0] + proj[0]*10, pt[1] + proj[1]*10, pt[2] + proj[2]*10};
|
||||||
|
double* bounds = obj->GetBounds();
|
||||||
|
double ptMin[3]={bounds[0],bounds[2],bounds[4]};
|
||||||
|
double ptMax[3]={bounds[1],bounds[3],bounds[5]};
|
||||||
|
double* originPts[2] = {ptMin,ptMax};
|
||||||
|
double t;
|
||||||
|
double intersectPt[3] = {.0, .0, .0};
|
||||||
|
double dis = VTK_DOUBLE_MAX;
|
||||||
|
int faceIndex = -1;
|
||||||
|
vtkNew<vtkPlane> plane;
|
||||||
|
for (int i = 0; i < 2; ++i) {
|
||||||
|
plane->SetOrigin(originPts[i]);
|
||||||
|
for (int j = 0; j < 3; ++j) {
|
||||||
|
double orientation[3] = {.0, .0, .0};
|
||||||
|
orientation[j] = 1.0;
|
||||||
|
plane->SetNormal(orientation);
|
||||||
|
if(plane->IntersectWithLine(pt, pt2, t, intersectPt)) {
|
||||||
|
if (!checkInCube(intersectPt)) continue;
|
||||||
|
double d = vtkMath::Distance2BetweenPoints(pt, intersectPt);
|
||||||
|
if (d < dis) {
|
||||||
|
dis = d;
|
||||||
|
faceIndex = i * 3 + j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PressedFaceIndex = faceIndex;
|
||||||
|
vtkErrorMacro("face index:" <<faceIndex);
|
||||||
|
obj->InvokeEvent(vtkCommand::PickEvent,&PressedFaceIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
31
src/src/Rendering/Widget/ClickableOrientationMarkerWidget.h
Normal file
31
src/src/Rendering/Widget/ClickableOrientationMarkerWidget.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// Created by Krad on 2022/10/26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OMEGAV_CLICKABLEORIENTATIONMARKERWIDGET_H
|
||||||
|
#define OMEGAV_CLICKABLEORIENTATIONMARKERWIDGET_H
|
||||||
|
|
||||||
|
#include <vtkOrientationMarkerWidget.h>
|
||||||
|
#include <vtkVariant.h>
|
||||||
|
|
||||||
|
class vtkPropPicker;
|
||||||
|
|
||||||
|
class ClickableOrientationMarkerWidget: public vtkOrientationMarkerWidget {
|
||||||
|
public:
|
||||||
|
static ClickableOrientationMarkerWidget* New();
|
||||||
|
vtkTypeMacro(ClickableOrientationMarkerWidget, vtkOrientationMarkerWidget);
|
||||||
|
protected:
|
||||||
|
ClickableOrientationMarkerWidget();
|
||||||
|
~ClickableOrientationMarkerWidget() override;
|
||||||
|
void OnLeftButtonDown()override;
|
||||||
|
void OnLeftButtonUp() override {};
|
||||||
|
void OnMouseMove() override {};
|
||||||
|
private:
|
||||||
|
ClickableOrientationMarkerWidget(const ClickableOrientationMarkerWidget&) = delete;
|
||||||
|
void operator=(const ClickableOrientationMarkerWidget&) = delete;
|
||||||
|
vtkPropPicker* picker;
|
||||||
|
vtkVariant PressedFaceIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //OMEGAV_CLICKABLEORIENTATIONMARKERWIDGET_H
|
||||||
Reference in New Issue
Block a user