Orientation marker click change volume view orientation.
This commit is contained in:
@@ -20,11 +20,11 @@
|
||||
#include <vtkCornerAnnotation.h>
|
||||
#include <vtkPlane.h>
|
||||
#include <vtkBoundingBox.h>
|
||||
#include <vtkOrientationMarkerWidget.h>
|
||||
#include <vtkAnnotatedCubeActor.h>
|
||||
|
||||
#include <vtkVectorText.h>
|
||||
|
||||
#include "Interaction/VolumeInteractorStyle.h"
|
||||
#include "Rendering/Widget/ClickableOrientationMarkerWidget.h"
|
||||
#include "IO/DICOM/ExtendMedicalImageProperties.h"
|
||||
|
||||
namespace {
|
||||
@@ -36,6 +36,36 @@ namespace {
|
||||
Superior,
|
||||
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);
|
||||
@@ -50,7 +80,7 @@ VolumeRenderingViewer::VolumeRenderingViewer()
|
||||
, InteractorStyle(nullptr)
|
||||
, Interactor(nullptr)
|
||||
, firstRender(true)
|
||||
, OrientationMarker(vtkOrientationMarkerWidget::New()){
|
||||
, OrientationMarker(ClickableOrientationMarkerWidget::New()){
|
||||
if (gpuMode){
|
||||
auto mapper = vtkGPUVolumeRayCastMapper::New();
|
||||
mapper->SetUseJittering(1);
|
||||
@@ -145,7 +175,6 @@ void VolumeRenderingViewer::InstallPipeline() {
|
||||
if (this->Interactor) {
|
||||
if (!this->InteractorStyle) {
|
||||
auto style = VolumeInteractorStyle::New();
|
||||
// style->SetInteractionMode(1024);
|
||||
this->InteractorStyle = style;
|
||||
this->InteractorStyle->AddObserver(vtkCommand::StartWindowLevelEvent,this,
|
||||
&VolumeRenderingViewer::DecreaseMaximumImageSampleDistance);
|
||||
@@ -261,11 +290,13 @@ void VolumeRenderingViewer::Render() {
|
||||
this->OrientationMarker->RemoveAllObservers();
|
||||
this->OrientationMarker->SetInteractor(this->Interactor);
|
||||
this->OrientationMarker->EnabledOn();
|
||||
this->OrientationMarker->InteractiveOff();
|
||||
|
||||
this->RenderWindow->AddObserver(vtkCommand::WindowResizeEvent, this, &VolumeRenderingViewer::resizeOrientationMarker);
|
||||
Render();
|
||||
|
||||
}
|
||||
Interactor->Render();
|
||||
renderAnnotation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,14 +349,14 @@ void VolumeRenderingViewer::renderAnnotation() {
|
||||
void VolumeRenderingViewer::GetDirectionString(const double *directionVector, std::string &str) const {
|
||||
str.clear();
|
||||
char dV [3] = {' ', ' ', ' '};
|
||||
if (fabs(directionVector[0]) > 0.5){
|
||||
if (fabs(directionVector[0]) > 0.6){
|
||||
dV[0] = directionVector[0] > 0 ? 'L' : 'R';
|
||||
}
|
||||
if (fabs(directionVector[1])>0.5){
|
||||
dV[1] = directionVector[1]>0?'P':'A';
|
||||
if (fabs(directionVector[1]) > 0.6){
|
||||
dV[1] = directionVector[1]> 0 ? 'P' : 'A';
|
||||
}
|
||||
if (fabs(directionVector[2])>0.5){
|
||||
dV[2] =directionVector[2]>0?'H':'F';
|
||||
if (fabs(directionVector[2]) > 0.6){
|
||||
dV[2] = directionVector[2] > 0 ? 'H' : 'F';
|
||||
}
|
||||
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]);
|
||||
@@ -348,13 +379,13 @@ char VolumeRenderingViewer::GetDirectionChar(const double *directionVector , int
|
||||
worldDirection = 0;
|
||||
return directionVector[0] > 0 ? 'L' : 'R';
|
||||
}
|
||||
if (fabs(directionVector[1])>0.7){
|
||||
if (fabs(directionVector[1]) > 0.7){
|
||||
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;
|
||||
return directionVector[2]>0?'H':'F';
|
||||
return directionVector[2] > 0 ? 'H' : 'F';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,11 +450,25 @@ void VolumeRenderingViewer::SetCoordsTransformMatrix(ExtendMedicalImagePropertie
|
||||
cube->SetZFaceTextRotation(-90);
|
||||
}
|
||||
}
|
||||
cube->SetTextEdgesVisibility(0);
|
||||
|
||||
cube->GetTextEdgesProperty()->SetColor(1.0,1.0,.0);
|
||||
cube->GetTextEdgesProperty()->SetLineWidth(2.0);
|
||||
cube->GetCubeProperty()->SetColor(.0,.0,1.0);
|
||||
cube->GetZMinusFaceProperty()->SetColor(1.0,0.863,.3);
|
||||
cube->GetZPlusFaceProperty()->SetColor(1.0,0.863,.3);
|
||||
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);
|
||||
cube->AddObserver(vtkCommand::PickEvent,this,&VolumeRenderingViewer::pressedOrientationMarker);
|
||||
}
|
||||
//change to WToM
|
||||
OrientationMatrix->Invert();
|
||||
@@ -540,3 +585,15 @@ void VolumeRenderingViewer::resizeOrientationMarker() {
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
return GetDirectionChar(directionVector, a);
|
||||
}
|
||||
void pressedOrientationMarker(vtkObject*, unsigned long, void*);
|
||||
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