Updates will be applied April 15th at 12pm EDT (UTC-0400). GitLab could be a little slow between 12 - 12:45pm EDT.

Commit 3857b155 authored by Ken Martin's avatar Ken Martin

update the implicit plane widget/rep to handle vr

Add 3d event support into these classes. Also
add some additional options to the rep to give it a bit
more customizaiton.
parent 3e5cd551
......@@ -22,6 +22,7 @@
#include "vtkCellPicker.h"
#include "vtkConeSource.h"
#include "vtkCutter.h"
#include "vtkEventData.h"
#include "vtkFeatureEdges.h"
#include "vtkImageData.h"
#include "vtkLineSource.h"
......@@ -31,6 +32,7 @@
#include "vtkOutlineFilter.h"
#include "vtkPickingManager.h"
#include "vtkPlane.h"
#include "vtkPlaneSource.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
......@@ -59,6 +61,8 @@ vtkImplicitPlaneRepresentation::vtkImplicitPlaneRepresentation()
this->LockNormalToCamera = 0;
this->CropPlaneToBoundingBox = true;
// Handle size is in pixels for this widget
this->HandleSize = 5.0;
......@@ -88,12 +92,14 @@ vtkImplicitPlaneRepresentation::vtkImplicitPlaneRepresentation()
this->Cutter = vtkCutter::New();
this->Cutter->SetInputData(this->Box);
this->Cutter->SetCutFunction(this->Plane);
this->PlaneSource = vtkPlaneSource::New();
this->CutMapper = vtkPolyDataMapper::New();
this->CutMapper->SetInputConnection(
this->Cutter->GetOutputPort());
this->CutActor = vtkActor::New();
this->CutActor->SetMapper(this->CutMapper);
this->DrawPlane = 1;
this->DrawOutline = 1;
this->Edges = vtkFeatureEdges::New();
this->Edges->SetInputConnection(
......@@ -209,6 +215,7 @@ vtkImplicitPlaneRepresentation::~vtkImplicitPlaneRepresentation()
this->OutlineActor->Delete();
this->Cutter->Delete();
this->PlaneSource->Delete();
this->CutMapper->Delete();
this->CutActor->Delete();
......@@ -284,6 +291,31 @@ void vtkImplicitPlaneRepresentation::SetLockNormalToCamera(int lock)
this->Modified();
}
void vtkImplicitPlaneRepresentation::SetCropPlaneToBoundingBox(bool val)
{
if (this->CropPlaneToBoundingBox == val)
{
return;
}
this->CropPlaneToBoundingBox = val;
if (val)
{
this->CutMapper->SetInputConnection(
this->Cutter->GetOutputPort());
this->Edges->SetInputConnection(
this->Cutter->GetOutputPort());
}
else
{
this->CutMapper->SetInputConnection(
this->PlaneSource->GetOutputPort());
this->Edges->SetInputConnection(
this->PlaneSource->GetOutputPort());
}
this->Modified();
}
//----------------------------------------------------------------------------
int vtkImplicitPlaneRepresentation::ComputeInteractionState(int X, int Y,
int vtkNotUsed(modify))
......@@ -354,6 +386,83 @@ int vtkImplicitPlaneRepresentation::ComputeInteractionState(int X, int Y,
return this->InteractionState;
}
int vtkImplicitPlaneRepresentation::ComputeComplexInteractionState(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long , void *calldata, int )
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
double pos[3];
edd->GetWorldPosition(pos);
vtkAssemblyPath* path = this->GetAssemblyPath3DPoint(pos, this->Picker);
if ( path == nullptr ) // Not picking this widget
{
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
return this->InteractionState;
}
// Something picked, continue
this->ValidPick = 1;
// Depending on the interaction state (set by the widget) we modify
// this state based on what is picked.
if ( this->InteractionState == vtkImplicitPlaneRepresentation::Moving )
{
vtkProp *prop = path->GetFirstNode()->GetViewProp();
if ( prop == this->ConeActor || prop == this->LineActor ||
prop == this->ConeActor2 || prop == this->LineActor2 )
{
this->InteractionState = vtkImplicitPlaneRepresentation::Rotating;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Rotating);
}
else if ( prop == this->CutActor )
{
if(this->LockNormalToCamera)
{ // Allow camera to work
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
}
else
{
this->InteractionState = vtkImplicitPlaneRepresentation::Pushing;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Pushing);
}
}
else if ( prop == this->SphereActor )
{
this->InteractionState = vtkImplicitPlaneRepresentation::MovingOrigin;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::MovingOrigin);
}
else
{
if ( this->OutlineTranslation )
{
this->InteractionState = vtkImplicitPlaneRepresentation::MovingOutline;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::MovingOutline);
}
else
{
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
}
}
}
// We may add a condition to allow the camera to work IO scaling
else if ( this->InteractionState != vtkImplicitPlaneRepresentation::Scaling )
{
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
}
}
return this->InteractionState;
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::SetRepresentationState(int state)
{
......@@ -416,6 +525,25 @@ void vtkImplicitPlaneRepresentation::StartWidgetInteraction(double e[2])
this->LastEventPosition[2] = 0.0;
}
void vtkImplicitPlaneRepresentation::StartComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long, void *calldata)
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
edd->GetWorldPosition(this->StartEventPosition);
this->LastEventPosition[0] = this->StartEventPosition[0];
this->LastEventPosition[1] = this->StartEventPosition[1];
this->LastEventPosition[2] = this->StartEventPosition[2];
edd->GetWorldOrientation(this->StartEventOrientation);
std::copy(this->StartEventOrientation, this->StartEventOrientation + 4,
this->LastEventOrientation);
}
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::WidgetInteraction(double e[2])
{
......@@ -474,12 +602,73 @@ void vtkImplicitPlaneRepresentation::WidgetInteraction(double e[2])
this->LastEventPosition[2] = 0.0;
}
void vtkImplicitPlaneRepresentation::ComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long, void *calldata )
{
vtkEventData *edata = static_cast<vtkEventData *>(calldata);
vtkEventDataDevice3D *edd = edata->GetAsEventDataDevice3D();
if (edd)
{
double eventPos[3];
edd->GetWorldPosition(eventPos);
double eventDir[4];
edd->GetWorldOrientation(eventDir);
// Process the motion
if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingOutline )
{
// this->TranslateOutline(this->LastEventPosition, eventPos);
this->UpdatePose(this->LastEventPosition, this->LastEventOrientation, eventPos, eventDir);
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingOrigin )
{
this->UpdatePose(this->LastEventPosition, this->LastEventOrientation, eventPos, eventDir);
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::Pushing )
{
// this->Push(this->LastEventPosition, eventPos);
this->UpdatePose(this->LastEventPosition, this->LastEventOrientation, eventPos, eventDir);
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::Scaling &&
this->ScaleEnabled )
{
this->Scale(this->LastEventPosition, eventPos, 0.0, 0.0); // todo handle this
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::Rotating )
{
this->Rotate3D(this->LastEventPosition, eventPos);
}
else if( this->InteractionState == vtkImplicitPlaneRepresentation::Outside &&
this->LockNormalToCamera )
{
this->SetNormalToCamera();
}
// Book keeping
this->LastEventPosition[0] = eventPos[0];
this->LastEventPosition[1] = eventPos[1];
this->LastEventPosition[2] = eventPos[2];
std::copy(eventDir, eventDir + 4, this->LastEventOrientation);
this->Modified();
}
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::EndWidgetInteraction(double vtkNotUsed(e)[2])
{
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
}
void vtkImplicitPlaneRepresentation::EndComplexInteraction(
vtkRenderWindowInteractor *,
vtkAbstractWidget *,
unsigned long, void *)
{
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
}
//----------------------------------------------------------------------
double *vtkImplicitPlaneRepresentation::GetBounds()
{
......@@ -527,7 +716,10 @@ int vtkImplicitPlaneRepresentation::RenderOpaqueGeometry(vtkViewport *v)
{
int count=0;
this->BuildRepresentation();
count += this->OutlineActor->RenderOpaqueGeometry(v);
if ( this->DrawOutline )
{
count += this->OutlineActor->RenderOpaqueGeometry(v);
}
count += this->EdgesActor->RenderOpaqueGeometry(v);
if ( ! this->LockNormalToCamera )
{
......@@ -551,7 +743,10 @@ int vtkImplicitPlaneRepresentation::RenderTranslucentPolygonalGeometry(
{
int count=0;
this->BuildRepresentation();
count += this->OutlineActor->RenderTranslucentPolygonalGeometry(v);
if ( this->DrawOutline )
{
count += this->OutlineActor->RenderTranslucentPolygonalGeometry(v);
}
count += this->EdgesActor->RenderTranslucentPolygonalGeometry(v);
if ( ! this->LockNormalToCamera )
{
......@@ -573,7 +768,10 @@ int vtkImplicitPlaneRepresentation::RenderTranslucentPolygonalGeometry(
int vtkImplicitPlaneRepresentation::HasTranslucentPolygonalGeometry()
{
int result=0;
result |= this->OutlineActor->HasTranslucentPolygonalGeometry();
if ( this->DrawOutline )
{
result |= this->OutlineActor->HasTranslucentPolygonalGeometry();
}
result |= this->EdgesActor->HasTranslucentPolygonalGeometry();
if ( ! this->LockNormalToCamera )
{
......@@ -659,6 +857,9 @@ void vtkImplicitPlaneRepresentation::PrintSelf(ostream& os, vtkIndent indent)
os << indent << "Edges Property: (none)\n";
}
os << indent << "Crop plane to bounding box: "
<< (this->CropPlaneToBoundingBox ? "On" : "Off") << "\n";
os << indent << "Normal To X Axis: "
<< (this->NormalToXAxis ? "On" : "Off") << "\n";
os << indent << "Normal To Y Axis: "
......@@ -684,6 +885,7 @@ void vtkImplicitPlaneRepresentation::PrintSelf(ostream& os, vtkIndent indent)
<< (this->ConstrainToWidgetBounds ? "On" : "Off") << "\n";
os << indent << "Scale Enabled: "
<< (this->ScaleEnabled ? "On" : "Off") << "\n";
os << indent << "Draw Outline: " << (this->DrawOutline ? "On" : "Off") << "\n";
os << indent << "Draw Plane: " << (this->DrawPlane ? "On" : "Off") << "\n";
os << indent << "Bump Distance: " << this->BumpDistance << "\n";
......@@ -805,6 +1007,49 @@ void vtkImplicitPlaneRepresentation::Rotate(double X, double Y,
this->SetNormal(nNew);
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::Rotate3D(double *p1, double *p2)
{
if (p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2])
{
return;
}
double *origin = this->Plane->GetOrigin();
double *normal = this->Plane->GetNormal();
double v1[3] = {
p1[0] - origin[0],
p1[1] - origin[1],
p1[2] - origin[2],
};
double v2[3] = {
p2[0] - origin[0],
p2[1] - origin[1],
p2[2] - origin[2],
};
vtkMath::Normalize(v1);
vtkMath::Normalize(v2);
// Create axis of rotation and angle of rotation
double axis[3];
vtkMath::Cross(v1,v2,axis);
double theta = vtkMath::DegreesFromRadians(acos(vtkMath::Dot(v1,v2)));
//Manipulate the transform to reflect the rotation
this->Transform->Identity();
this->Transform->Translate(origin[0],origin[1],origin[2]);
this->Transform->RotateWXYZ(theta,axis);
this->Transform->Translate(-origin[0],-origin[1],-origin[2]);
//Set the new normal
double nNew[3];
this->Transform->TransformNormal(normal,nNew);
this->SetNormal(nNew);
}
//----------------------------------------------------------------------------
// Loop through all points and translate them
void vtkImplicitPlaneRepresentation::TranslateOutline(double *p1, double *p2)
......@@ -858,6 +1103,58 @@ void vtkImplicitPlaneRepresentation::TranslateOrigin(double *p1, double *p2)
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
// Loop through all points and translate and rotate them
void vtkImplicitPlaneRepresentation::UpdatePose(
double *p1, double *d1,
double *p2, double *d2
)
{
double *origin = this->Plane->GetOrigin();
double *normal = this->Plane->GetNormal();
double nNew[3];
double temp1[4];
double temp2[4];
std::copy(d1,d1+4,temp1);
temp1[0] = vtkMath::RadiansFromDegrees(-temp1[0]);
std::copy(d2,d2+4,temp2);
temp2[0] = vtkMath::RadiansFromDegrees(temp2[0]);
vtkMath::RotateVectorByWXYZ(normal, temp1, nNew);
vtkMath::RotateVectorByWXYZ(nNew, temp2, nNew);
this->SetNormal(nNew);
// adjust center for rotation
double v[3];
v[0] = origin[0] - 0.5*(p2[0] + p1[0]);
v[1] = origin[1] - 0.5*(p2[1] + p1[1]);
v[2] = origin[2] - 0.5*(p2[2] + p1[2]);
vtkMath::RotateVectorByWXYZ(v, temp1, v);
vtkMath::RotateVectorByWXYZ(v, temp2, v);
double newOrigin[3];
newOrigin[0] = v[0] + 0.5*(p2[0] + p1[0]);
newOrigin[1] = v[1] + 0.5*(p2[1] + p1[1]);
newOrigin[2] = v[2] + 0.5*(p2[2] + p1[2]);
//Get the motion vector
v[0] = p2[0] - p1[0];
v[1] = p2[1] - p1[1];
v[2] = p2[2] - p1[2];
//Add to the current point, project back down onto plane
newOrigin[0] += v[0];
newOrigin[1] += v[1];
newOrigin[2] += v[2];
// vtkPlane::ProjectPoint(newOrigin,origin,normal,newOrigin);
this->SetOrigin(newOrigin[0],newOrigin[1],newOrigin[2]);
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::Scale(double *p1, double *p2,
double vtkNotUsed(X), double Y)
......@@ -998,21 +1295,32 @@ void vtkImplicitPlaneRepresentation::PlaceWidget(double bds[6])
(bounds[5]-bounds[4]));
this->Outline->Update();
this->InitialLength = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
(bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
(bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
this->LineSource->SetPoint1(this->Plane->GetOrigin());
this->PlaneSource->SetOrigin(0, 0, 0);
if ( this->NormalToYAxis )
{
this->Plane->SetNormal(0,1,0);
this->LineSource->SetPoint2(0,1,0);
this->PlaneSource->SetPoint1(this->InitialLength, 0, 0);
this->PlaneSource->SetPoint2(0, 0, this->InitialLength);
}
else if ( this->NormalToZAxis )
{
this->Plane->SetNormal(0,0,1);
this->LineSource->SetPoint2(0,0,1);
this->PlaneSource->SetPoint1(this->InitialLength, 0, 0);
this->PlaneSource->SetPoint2(0, this->InitialLength, 0);
}
else //default or x-normal
{
this->Plane->SetNormal(1,0,0);
this->LineSource->SetPoint2(1,0,0);
this->PlaneSource->SetPoint1(0, this->InitialLength, 0);
this->PlaneSource->SetPoint2(0, 0, this->InitialLength);
}
for (i=0; i<6; i++)
......@@ -1021,9 +1329,6 @@ void vtkImplicitPlaneRepresentation::PlaceWidget(double bds[6])
this->WidgetBounds[i] = bounds[i];
}
this->InitialLength = sqrt((bounds[1]-bounds[0])*(bounds[1]-bounds[0]) +
(bounds[3]-bounds[2])*(bounds[3]-bounds[2]) +
(bounds[5]-bounds[4])*(bounds[5]-bounds[4]));
this->ValidPick = 1; // since we have positioned the widget successfully
this->BuildRepresentation();
......@@ -1120,6 +1425,27 @@ void vtkImplicitPlaneRepresentation::SetDrawPlane(int drawPlane)
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::SetDrawOutline(int val)
{
if ( val == this->DrawOutline )
{
return;
}
if (val)
{
this->Picker->AddPickList(this->OutlineActor);
}
else
{
this->Picker->DeletePickList(this->OutlineActor);
}
this->Modified();
this->DrawOutline = val;
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::SetNormalToXAxis (int var)
{
......@@ -1323,6 +1649,8 @@ void vtkImplicitPlaneRepresentation::BuildRepresentation()
(bounds[5]-bounds[4]));
this->Outline->Update();
this->PlaneSource->SetCenter(origin);
this->PlaneSource->SetNormal(normal);
// Setup the plane normal
double d = this->Outline->GetOutput()->GetLength();
......
......@@ -49,6 +49,7 @@ class vtkLineSource;
class vtkSphereSource;
class vtkTubeFilter;
class vtkPlane;
class vtkPlaneSource;
class vtkCutter;
class vtkProperty;
class vtkImageData;
......@@ -149,6 +150,15 @@ public:
vtkBooleanMacro(DrawPlane,int);
//@}
//@{
/**
* Enable/disable the drawing of the outline.
*/
void SetDrawOutline(int plane);
vtkGetMacro(DrawOutline,int);
vtkBooleanMacro(DrawOutline,int);
//@}
//@{
/**
* Turn on/off the ability to translate the bounding box by grabbing it
......@@ -307,7 +317,7 @@ public:
//@{
/**
* Methods to interface with the vtkSliderWidget.
* Methods to interface with the vtkImplicitPlaneWidget2.
*/
int ComputeInteractionState(int X, int Y, int modify=0) VTK_OVERRIDE;
void PlaceWidget(double bounds[6]) VTK_OVERRIDE;
......@@ -315,7 +325,24 @@ public:
void StartWidgetInteraction(double eventPos[2]) VTK_OVERRIDE;
void WidgetInteraction(double newEventPos[2]) VTK_OVERRIDE;
void EndWidgetInteraction(double newEventPos[2]) VTK_OVERRIDE;
void StartComplexInteraction(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata) VTK_OVERRIDE;
void ComplexInteraction(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata) VTK_OVERRIDE;
int ComputeComplexInteractionState(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata, int modify = 0) VTK_OVERRIDE;
void EndComplexInteraction(
vtkRenderWindowInteractor *iren,
vtkAbstractWidget *widget,
unsigned long event, void *calldata) VTK_OVERRIDE;
//@}
//@{
/**
* Methods supporting the rendering process.
......@@ -362,6 +389,22 @@ public:
vtkGetMacro(RepresentationState, int);
//@}
// Get the underlying plane object used by this rep
// this can be used as a cropping plane in vtkMapper
vtkPlane *GetUnderlyingPlane() {
return this->Plane; }
//@{
/**
* Control if the plane should be drawn cropped by the bounding box
* or without cropping. Defaults to on.
*/
virtual void SetCropPlaneToBoundingBox(bool);
vtkGetMacro(CropPlaneToBoundingBox,bool);
vtkBooleanMacro(CropPlaneToBoundingBox,bool);
//@}
protected:
vtkImplicitPlaneRepresentation();
~vtkImplicitPlaneRepresentation() VTK_OVERRIDE;
......@@ -370,6 +413,8 @@ protected:
// Keep track of event positions
double LastEventPosition[3];
double LastEventOrientation[4];
double StartEventOrientation[4];
// Controlling ivars
int NormalToXAxis;
......@@ -399,9 +444,11 @@ protected:
// The cut plane is produced with a vtkCutter
vtkCutter *Cutter;
vtkPlaneSource *PlaneSource;
vtkPolyDataMapper *CutMapper;
vtkActor *CutActor;
int DrawPlane;
int DrawOutline;
void HighlightPlane(int highlight);