Commit dd214570 authored by Will Schroeder's avatar Will Schroeder Committed by Michael Jeulin-L
Browse files

ENH: Automatic plan orientation in vtkImplicitPlaneWidget2

Add vtkImplicitPlaneRepresentation::SlaveNormalToCamera
Fix trailing whitespace

Change-Id: I1835eb6b31fa9ca7bde86782e19555f5f43af38b
parent 8af11a6b
......@@ -39,6 +39,7 @@
#include "vtkTubeFilter.h"
#include "vtkInteractorObserver.h"
#include "vtkBox.h"
#include "vtkCommand.h"
vtkStandardNewMacro(vtkImplicitPlaneRepresentation);
......@@ -49,9 +50,14 @@ vtkImplicitPlaneRepresentation::vtkImplicitPlaneRepresentation()
this->NormalToYAxis = 0;
this->NormalToZAxis = 0;
this->SlaveNormalToCamera = 0;
// Handle size is in pixels for this widget
this->HandleSize = 5.0;
// Pushing operation
this->BumpDistance = 0.01;
// Build the representation of the widget
//
this->Plane = vtkPlane::New();
......@@ -227,6 +233,36 @@ vtkImplicitPlaneRepresentation::~vtkImplicitPlaneRepresentation()
this->BoundingBox->Delete();
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::UpdateSlavedNormal()
{
if ( this->Renderer )
{
double n[3], n2[3];
vtkCamera *cam = this->Renderer->GetActiveCamera();
cam->GetViewPlaneNormal(n);
this->Plane->GetNormal(n2);
if ( n[0] != n2[0] || n[1] != n2[1] || n[2] != n2[2] )
{
this->Plane->SetNormal(n);
this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
}
}
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::SetSlaveNormalToCamera(int lock)
{
vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting "
<< SlaveNormalToCamera << " to " << lock);
if ( lock != this->SlaveNormalToCamera )
{
this->UpdateSlavedNormal();
this->SlaveNormalToCamera = lock;
this->Modified();
}
}
//----------------------------------------------------------------------------
int vtkImplicitPlaneRepresentation::ComputeInteractionState(int X, int Y,
int vtkNotUsed(modify))
......@@ -259,8 +295,17 @@ int vtkImplicitPlaneRepresentation::ComputeInteractionState(int X, int Y,
}
else if ( prop == this->CutActor )
{
this->InteractionState = vtkImplicitPlaneRepresentation::Pushing;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Pushing);
// if ( 0 )
if ( this->SlaveNormalToCamera )
{//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 )
{
......@@ -282,16 +327,18 @@ int vtkImplicitPlaneRepresentation::ComputeInteractionState(int X, int Y,
}
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingPlane )
{
return this->InteractionState;
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::Scaling )
{
return this->InteractionState;
if ( this->SlaveNormalToCamera )
{//allow camera to work
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
this->SetRepresentationState(vtkImplicitPlaneRepresentation::Outside);
}
else
{
return this->InteractionState;
}
}
else
{
this->InteractionState = vtkImplicitPlaneRepresentation::Outside;
......@@ -324,6 +371,7 @@ void vtkImplicitPlaneRepresentation::SetRepresentationState(int state)
}
else if ( state == vtkImplicitPlaneRepresentation::Pushing )
{
this->HighlightNormal(1);
this->HighlightPlane(1);
}
else if ( state == vtkImplicitPlaneRepresentation::MovingOrigin )
......@@ -334,11 +382,6 @@ void vtkImplicitPlaneRepresentation::SetRepresentationState(int state)
{
this->HighlightOutline(1);
}
else if ( state == vtkImplicitPlaneRepresentation::MovingPlane )
{
this->HighlightNormal(1);
this->HighlightPlane(1);
}
else if ( state == vtkImplicitPlaneRepresentation::Scaling &&
this->ScaleEnabled )
{
......@@ -391,11 +434,7 @@ void vtkImplicitPlaneRepresentation::WidgetInteraction(double e[2])
vtkInteractorObserver::ComputeDisplayToWorld(this->Renderer, e[0], e[1], z, pickPoint);
// Process the motion
if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingPlane )
{
this->TranslatePlane(prevPickPoint, pickPoint);
}
else if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingOutline )
if ( this->InteractionState == vtkImplicitPlaneRepresentation::MovingOutline )
{
this->TranslateOutline(prevPickPoint, pickPoint);
}
......@@ -478,11 +517,14 @@ int vtkImplicitPlaneRepresentation::RenderOpaqueGeometry(vtkViewport *v)
this->BuildRepresentation();
count += this->OutlineActor->RenderOpaqueGeometry(v);
count += this->EdgesActor->RenderOpaqueGeometry(v);
count += this->ConeActor->RenderOpaqueGeometry(v);
count += this->LineActor->RenderOpaqueGeometry(v);
count += this->ConeActor2->RenderOpaqueGeometry(v);
count += this->LineActor2->RenderOpaqueGeometry(v);
count += this->SphereActor->RenderOpaqueGeometry(v);
if ( ! this->SlaveNormalToCamera )
{
count += this->ConeActor->RenderOpaqueGeometry(v);
count += this->LineActor->RenderOpaqueGeometry(v);
count += this->ConeActor2->RenderOpaqueGeometry(v);
count += this->LineActor2->RenderOpaqueGeometry(v);
count += this->SphereActor->RenderOpaqueGeometry(v);
}
if ( this->DrawPlane )
{
count += this->CutActor->RenderOpaqueGeometry(v);
......@@ -499,11 +541,14 @@ int vtkImplicitPlaneRepresentation::RenderTranslucentPolygonalGeometry(
this->BuildRepresentation();
count += this->OutlineActor->RenderTranslucentPolygonalGeometry(v);
count += this->EdgesActor->RenderTranslucentPolygonalGeometry(v);
count += this->ConeActor->RenderTranslucentPolygonalGeometry(v);
count += this->LineActor->RenderTranslucentPolygonalGeometry(v);
count += this->ConeActor2->RenderTranslucentPolygonalGeometry(v);
count += this->LineActor2->RenderTranslucentPolygonalGeometry(v);
count += this->SphereActor->RenderTranslucentPolygonalGeometry(v);
if ( ! this->SlaveNormalToCamera )
{
count += this->ConeActor->RenderTranslucentPolygonalGeometry(v);
count += this->LineActor->RenderTranslucentPolygonalGeometry(v);
count += this->ConeActor2->RenderTranslucentPolygonalGeometry(v);
count += this->LineActor2->RenderTranslucentPolygonalGeometry(v);
count += this->SphereActor->RenderTranslucentPolygonalGeometry(v);
}
if ( this->DrawPlane )
{
count += this->CutActor->RenderTranslucentPolygonalGeometry(v);
......@@ -518,11 +563,14 @@ int vtkImplicitPlaneRepresentation::HasTranslucentPolygonalGeometry()
int result=0;
result |= this->OutlineActor->HasTranslucentPolygonalGeometry();
result |= this->EdgesActor->HasTranslucentPolygonalGeometry();
result |= this->ConeActor->HasTranslucentPolygonalGeometry();
result |= this->LineActor->HasTranslucentPolygonalGeometry();
result |= this->ConeActor2->HasTranslucentPolygonalGeometry();
result |= this->LineActor2->HasTranslucentPolygonalGeometry();
result |= this->SphereActor->HasTranslucentPolygonalGeometry();
if ( ! this->SlaveNormalToCamera )
{
result |= this->ConeActor->HasTranslucentPolygonalGeometry();
result |= this->LineActor->HasTranslucentPolygonalGeometry();
result |= this->ConeActor2->HasTranslucentPolygonalGeometry();
result |= this->LineActor2->HasTranslucentPolygonalGeometry();
result |= this->SphereActor->HasTranslucentPolygonalGeometry();
}
if ( this->DrawPlane )
{
result |= this->CutActor->HasTranslucentPolygonalGeometry();
......@@ -614,6 +662,7 @@ void vtkImplicitPlaneRepresentation::PrintSelf(ostream& os, vtkIndent indent)
os << indent << "Scale Enabled: "
<< (this->ScaleEnabled ? "On" : "Off") << "\n";
os << indent << "Draw Plane: " << (this->DrawPlane ? "On" : "Off") << "\n";
os << indent << "Bump Distance: " << this->BumpDistance << "\n";
os << indent << "Representation State: ";
switch ( this->RepresentationState )
......@@ -636,9 +685,6 @@ void vtkImplicitPlaneRepresentation::PrintSelf(ostream& os, vtkIndent indent)
case Pushing:
os << "Pushing\n";
break;
case MovingPlane:
os << "MovingPlane\n";
break;
case Scaling:
os << "Scaling\n";
break;
......@@ -738,27 +784,6 @@ void vtkImplicitPlaneRepresentation::Rotate(double X, double Y,
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
// Loop through all points and translate them
void vtkImplicitPlaneRepresentation::TranslatePlane(double *p1, double *p2)
{
//Get the motion vector
double v[3];
v[0] = p2[0] - p1[0];
v[1] = p2[1] - p1[1];
v[2] = p2[2] - p1[2];
//Translate the plane
double oNew[3];
double *origin = this->Plane->GetOrigin();
oNew[0] = origin[0] + v[0];
oNew[1] = origin[1] + v[1];
oNew[2] = origin[2] + v[2];
this->Plane->SetOrigin(oNew);
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
// Loop through all points and translate them
void vtkImplicitPlaneRepresentation::TranslateOutline(double *p1, double *p2)
......@@ -1128,6 +1153,23 @@ void vtkImplicitPlaneRepresentation::UpdatePlacement()
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::BumpPlane(int dir, double factor)
{
// Compute the distance
double d = this->InitialLength * this->BumpDistance * factor;
// Push the plane
this->PushPlane( (dir > 0 ? d : -d) );
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::PushPlane(double d)
{
this->Plane->Push(d);
this->BuildRepresentation();
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneRepresentation::BuildRepresentation()
{
......@@ -1136,57 +1178,63 @@ void vtkImplicitPlaneRepresentation::BuildRepresentation()
return;
}
double *origin = this->Plane->GetOrigin();
double *normal = this->Plane->GetNormal();
double p2[3];
if( !this->OutsideBounds )
if ( this->GetMTime() > this->BuildTime ||
this->Plane->GetMTime() > this->BuildTime )
{
double *bounds = this->InitialBounds;
for (int i=0; i<3; i++)
double *origin = this->Plane->GetOrigin();
this->UpdateSlavedNormal();
double *normal = this->Plane->GetNormal();
double p2[3];
if( !this->OutsideBounds )
{
if ( origin[i] < bounds[2*i] )
double *bounds = this->InitialBounds;
for (int i=0; i<3; i++)
{
origin[i] = bounds[2*i];
}
else if ( origin[i] > bounds[2*i+1] )
{
origin[i] = bounds[2*i+1];
if ( origin[i] < bounds[2*i] )
{
origin[i] = bounds[2*i];
}
else if ( origin[i] > bounds[2*i+1] )
{
origin[i] = bounds[2*i+1];
}
}
}
}
// Setup the plane normal
double d = this->Outline->GetOutput()->GetLength();
// Setup the plane normal
double d = this->Outline->GetOutput()->GetLength();
p2[0] = origin[0] + 0.30 * d * normal[0];
p2[1] = origin[1] + 0.30 * d * normal[1];
p2[2] = origin[2] + 0.30 * d * normal[2];
p2[0] = origin[0] + 0.30 * d * normal[0];
p2[1] = origin[1] + 0.30 * d * normal[1];
p2[2] = origin[2] + 0.30 * d * normal[2];
this->LineSource->SetPoint1(origin);
this->LineSource->SetPoint2(p2);
this->ConeSource->SetCenter(p2);
this->ConeSource->SetDirection(normal);
this->LineSource->SetPoint1(origin);
this->LineSource->SetPoint2(p2);
this->ConeSource->SetCenter(p2);
this->ConeSource->SetDirection(normal);
p2[0] = origin[0] - 0.30 * d * normal[0];
p2[1] = origin[1] - 0.30 * d * normal[1];
p2[2] = origin[2] - 0.30 * d * normal[2];
p2[0] = origin[0] - 0.30 * d * normal[0];
p2[1] = origin[1] - 0.30 * d * normal[1];
p2[2] = origin[2] - 0.30 * d * normal[2];
this->LineSource2->SetPoint1(origin[0],origin[1],origin[2]);
this->LineSource2->SetPoint2(p2);
this->ConeSource2->SetCenter(p2);
this->ConeSource2->SetDirection(normal[0],normal[1],normal[2]);
this->LineSource2->SetPoint1(origin[0],origin[1],origin[2]);
this->LineSource2->SetPoint2(p2);
this->ConeSource2->SetCenter(p2);
this->ConeSource2->SetDirection(normal[0],normal[1],normal[2]);
// Set up the position handle
this->Sphere->SetCenter(origin[0],origin[1],origin[2]);
// Set up the position handle
this->Sphere->SetCenter(origin[0],origin[1],origin[2]);
// Control the look of the edges
if ( this->Tubing )
{
this->EdgesMapper->SetInput(this->EdgesTuber->GetOutput());
}
else
{
this->EdgesMapper->SetInput(this->Edges->GetOutput());
// Control the look of the edges
if ( this->Tubing )
{
this->EdgesMapper->SetInput(this->EdgesTuber->GetOutput());
}
else
{
this->EdgesMapper->SetInput(this->Edges->GetOutput());
}
}
this->SizeHandles();
......
......@@ -98,6 +98,14 @@ public:
vtkGetMacro(NormalToZAxis,int);
vtkBooleanMacro(NormalToZAxis,int);
// Description:
// If enabled, and a vtkCamera is available through the renderer, then
// SlaveNormalToCamera will cause the normal to follow the camera's
// notmal.
virtual void SetSlaveNormalToCamera(int);
vtkGetMacro(SlaveNormalToCamera,int);
vtkBooleanMacro(SlaveNormalToCamera,int);
// Description:
// Turn on/off tubing of the wire outline of the plane. The tube thickens
// the line by wrapping with a vtkTubeFilter.
......@@ -177,6 +185,29 @@ public:
// applies to the edges when tubed.)
vtkGetObjectMacro(EdgesProperty,vtkProperty);
// Description:
// Specify a translation distance used by the BumpPlane() method. Note that the
// distance is normalized; it is the fraction of the length of the bounding
// box of the wire outline.
vtkSetClampMacro(BumpDistance,double,0.000001,1);
vtkGetMacro(BumpDistance,double);
// Description:
// Translate the plane in the direction of the normal by the
// specified BumpDistance. The dir parameter controls which
// direction the pushing occurs, either in the same direction
// as the normal, or when negative, in the opposite direction.
// The factor controls whether what percentage of the bump is
// used.
void BumpPlane(int dir, double factor);
// Description:
// Push the plane the distance specified along the normal. Positive
// values are in the direction of the normal; negative values are
// in the opposite direction of the normal. The distance value is
// expressed in world coordinates.
void PushPlane(double distance);
// Description:
// Methods to interface with the vtkSliderWidget.
virtual int ComputeInteractionState(int X, int Y, int modify=0);
......@@ -185,7 +216,6 @@ public:
virtual void StartWidgetInteraction(double eventPos[2]);
virtual void WidgetInteraction(double newEventPos[2]);
virtual void EndWidgetInteraction(double newEventPos[2]);
// Decsription:
// Methods supporting the rendering process.
virtual double *GetBounds();
......@@ -204,7 +234,6 @@ public:
MovingOrigin,
Rotating,
Pushing,
MovingPlane,
Scaling
};
//ETX
......@@ -239,6 +268,13 @@ protected:
int NormalToYAxis;
int NormalToZAxis;
// Locking normal to camera
int SlaveNormalToCamera;
void UpdateSlavedNormal();
// Controlling the push operation
double BumpDistance;
// The actual plane which is being manipulated
vtkPlane *Plane;
......
......@@ -27,6 +27,26 @@
vtkStandardNewMacro(vtkImplicitPlaneWidget2);
// The implicit plane widget observes its representation. The representation
// may invoke an InteractionEvent when the camera moves when LockedNormalToCamera
// is enabled.
class vtkInteractionCallback : public vtkCommand
{
public:
static vtkInteractionCallback *New()
{ return new vtkInteractionCallback; }
virtual void Execute(vtkObject*, unsigned long eventId, void*)
{
switch (eventId)
{
case vtkCommand::InteractionEvent:
this->ImplicitPlaneWidget->InvokeInteractionCallback();
break;
}
}
vtkImplicitPlaneWidget2 *ImplicitPlaneWidget;
};
//----------------------------------------------------------------------------
vtkImplicitPlaneWidget2::vtkImplicitPlaneWidget2()
{
......@@ -54,11 +74,27 @@ vtkImplicitPlaneWidget2::vtkImplicitPlaneWidget2()
this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent,
vtkWidgetEvent::Move,
this, vtkImplicitPlaneWidget2::MoveAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent,
vtkEvent::AnyModifier, 60, 1, "less",
vtkWidgetEvent::Up,
this, vtkImplicitPlaneWidget2::MovePlaneAction);
this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent,
vtkEvent::AnyModifier, 62, 1, "greater",
vtkWidgetEvent::Down,
this, vtkImplicitPlaneWidget2::MovePlaneAction);
this->InteractionCallback = vtkInteractionCallback::New();
this->InteractionCallback->ImplicitPlaneWidget = this;
}
//----------------------------------------------------------------------------
vtkImplicitPlaneWidget2::~vtkImplicitPlaneWidget2()
{
if ( this->WidgetRep )
{
this->WidgetRep->RemoveObserver(this->InteractionCallback);
}
this->InteractionCallback->Delete();
}
//----------------------------------------------------------------------
......@@ -234,6 +270,56 @@ void vtkImplicitPlaneWidget2::EndSelectAction(vtkAbstractWidget *w)
self->Render();
}
//----------------------------------------------------------------------
void vtkImplicitPlaneWidget2::MovePlaneAction(vtkAbstractWidget *w)
{
vtkImplicitPlaneWidget2 *self = reinterpret_cast<vtkImplicitPlaneWidget2*>(w);
reinterpret_cast<vtkImplicitPlaneRepresentation*>(self->WidgetRep)->
SetInteractionState(vtkImplicitPlaneRepresentation::Moving);
int X = self->Interactor->GetEventPosition()[0];
int Y = self->Interactor->GetEventPosition()[1];
int interactionState = self->WidgetRep->ComputeInteractionState(X, Y);
// if ( interactionState == vtkImplicitPlaneRepresentation::Outside )
// {
// return;
// }
// Move the plane
double factor = ( self->Interactor->GetControlKey() ? 0.5 : 1.0);
if ( self->Interactor->GetKeyCode() == '<' )
{
self->GetImplicitPlaneRepresentation()->BumpPlane(-1,factor);
}
else
{
self->GetImplicitPlaneRepresentation()->BumpPlane(1,factor);
}
self->EventCallbackCommand->SetAbortFlag(1);
self->InvokeEvent(vtkCommand::UpdateEvent,NULL);
self->Render();
}
//----------------------------------------------------------------------
void vtkImplicitPlaneWidget2::
SetRepresentation(vtkImplicitPlaneRepresentation *r)
{
// Add observer to support normal locking
if ( this->WidgetRep != NULL )
{
this->WidgetRep->RemoveObserver(this->InteractionCallback);
}
if ( r != NULL )
{
r->AddObserver(vtkCommand::InteractionEvent, this->InteractionCallback,
this->Priority);
}
this->Superclass::SetWidgetRepresentation(reinterpret_cast<vtkWidgetRepresentation*>(r));
}
//----------------------------------------------------------------------
void vtkImplicitPlaneWidget2::CreateDefaultRepresentation()
{
......@@ -267,6 +353,12 @@ int vtkImplicitPlaneWidget2::UpdateCursorShape( int state )
return 0;
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneWidget2::InvokeInteractionCallback()
{
this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
}
//----------------------------------------------------------------------------
void vtkImplicitPlaneWidget2::PrintSelf(ostream& os, vtkIndent indent)
{
......
......@@ -44,6 +44,9 @@
// LeftButtonPressEvent - select slider (if on slider)
// LeftButtonReleaseEvent - release slider (if selected)
// MouseMoveEvent - move the outline
// If the keypress characters are used
// '<' Move plane down
// '>' Move plane up
// In all the cases, independent of what is picked, the widget responds to the
// following VTK events:
// MiddleButtonPressEvent - move the plane
......@@ -60,6 +63,7 @@
// vtkWidgetEvent::Select -- some part of the widget has been selected
// vtkWidgetEvent::EndSelect -- the selection process has completed
// vtkWidgetEvent::Move -- a request for slider motion has been invoked
// vtkWidgetEvent::Up and vtkWidgetEvent::Down -- MovePlaneAction
// </pre>
//
// In turn, when these widget events are processed, the vtkImplicitPlaneWidget2
......@@ -89,10 +93,12 @@
#include "vtkAbstractWidget.h"
class vtkImplicitPlaneRepresentation;
class vtkInteractionCallback;
class VTK_WIDGETS_EXPORT vtkImplicitPlaneWidget2 : public vtkAbstractWidget
{
friend class vtkInteractionCallback;
public:
// Description:
// Instantiate the object.
......@@ -107,8 +113,7 @@ public:
// Specify an instance of vtkWidgetRepresentation used to represent this
// widget in the scene. Note that the representation is a subclass of vtkProp
// so it can be added to the renderer independent of the widget.
void SetRepresentation(vtkImplicitPlaneRepresentation *r)
{this->Superclass::SetWidgetRepresentation(reinterpret_cast<vtkWidgetRepresentation*>(r));}
void SetRepresentation(vtkImplicitPlaneRepresentation *r);
// Description:
// Return the representation as a vtkImplicitPlaneRepresentation.
......@@ -134,12 +139,18 @@ protected:
static void ScaleAction(vtkAbstractWidget*);
static void EndSelectAction(vtkAbstractWidget*);