You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/3rd/VTK7.1/source/VTK-7.1.1/Interaction/Widgets/vtkBrokenLineWidget.cxx

1376 lines
36 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkBrokenLineWidget.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkBrokenLineWidget.h"
#include "vtkActor.h"
#include "vtkAssemblyNode.h"
#include "vtkAssemblyPath.h"
#include "vtkCallbackCommand.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkCellPicker.h"
#include "vtkLineSource.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPickingManager.h"
#include "vtkPlaneSource.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkSphereSource.h"
#include "vtkTransform.h"
vtkStandardNewMacro(vtkBrokenLineWidget);
vtkCxxSetObjectMacro(vtkBrokenLineWidget, HandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkBrokenLineWidget, SelectedHandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkBrokenLineWidget, LineProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkBrokenLineWidget, SelectedLineProperty, vtkProperty);
vtkBrokenLineWidget::vtkBrokenLineWidget()
{
this->State = vtkBrokenLineWidget::Start;
this->EventCallbackCommand->SetCallback( vtkBrokenLineWidget::ProcessEventsHandler );
this->ProjectToPlane = 0; //default off
this->ProjectionNormal = 0; //default YZ not used
this->ProjectionPosition = 0.;
this->PlaneSource = NULL;
// Does this widget respond to interaction?
this->ProcessEvents = 1;
// Default handle size factor
this->HandleSizeFactor = 1.;
// Build the representation of the widget
// Default bounds to get started
double bounds[6] = { -.5, .5, -.5, .5, -.5, .5 };
// Create the handles along a straight line within the bounds of a unit cube
this->NumberOfHandles = 5;
this->Handle = new vtkActor* [this->NumberOfHandles];
this->HandleGeometry = new vtkSphereSource* [this->NumberOfHandles];
double u;
double x0 = bounds[0];
double x1 = bounds[1];
double y0 = bounds[2];
double y1 = bounds[3];
double z0 = bounds[4];
double z1 = bounds[5];
double x;
double y;
double z;
vtkPoints* points = vtkPoints::New( VTK_DOUBLE );
points->SetNumberOfPoints( this->NumberOfHandles );
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i] = vtkSphereSource::New();
this->HandleGeometry[i]->SetThetaResolution( 16 );
this->HandleGeometry[i]->SetPhiResolution( 8 );
vtkPolyDataMapper* handleMapper = vtkPolyDataMapper::New();
handleMapper->SetInputConnection(this->HandleGeometry[i]->GetOutputPort() );
this->Handle[i] = vtkActor::New();
this->Handle[i]->SetMapper( handleMapper );
handleMapper->Delete();
u = i / ( this->NumberOfHandles - 1. );
x = ( 1. - u ) * x0 + u * x1;
y = ( 1. - u ) * y0 + u * y1;
z = ( 1. - u ) * z0 + u * z1;
points->SetPoint( i, x, y, z );
this->HandleGeometry[i]->SetCenter( x,y,z );
}
// Create the broken line
this->LineSource = vtkLineSource::New();
this->LineSource->SetPoints( points );
points->Delete();
// Represent the broken line
this->LineMapper = vtkPolyDataMapper::New();
this->LineMapper->SetInputConnection( this->LineSource->GetOutputPort() );
this->LineMapper->ImmediateModeRenderingOn();
this->LineMapper->SetResolveCoincidentTopologyToPolygonOffset();
this->LineActor = vtkActor::New();
this->LineActor->SetMapper( this->LineMapper );
// Initial creation of the widget, serves to initialize it
this->PlaceFactor = 1.;
this->PlaceWidget( bounds );
// Manage the picking stuff
this->HandlePicker = vtkCellPicker::New();
this->HandlePicker->SetTolerance( .005 );
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandlePicker->AddPickList( this->Handle[i]);
}
this->HandlePicker->PickFromListOn();
this->LinePicker = vtkCellPicker::New();
this->LinePicker->SetTolerance( .01 );
this->LinePicker->AddPickList( this->LineActor );
this->LinePicker->PickFromListOn();
this->CurrentHandle = NULL;
this->CurrentHandleIndex = -1;
this->Transform = vtkTransform::New();
// Set up the initial properties
this->HandleProperty = NULL;
this->SelectedHandleProperty = NULL;
this->LineProperty = NULL;
this->SelectedLineProperty = NULL;
this->CreateDefaultProperties();
}
vtkBrokenLineWidget::~vtkBrokenLineWidget()
{
this->LineActor->Delete();
this->LineMapper->Delete();
this->LineSource->Delete();
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->Delete();
this->Handle[i]->Delete();
}
delete [] this->Handle;
delete [] this->HandleGeometry;
this->HandlePicker->Delete();
this->LinePicker->Delete();
if ( this->HandleProperty )
{
this->HandleProperty->Delete();
}
if ( this->SelectedHandleProperty )
{
this->SelectedHandleProperty->Delete();
}
if ( this->LineProperty )
{
this->LineProperty->Delete();
}
if ( this->SelectedLineProperty )
{
this->SelectedLineProperty->Delete();
}
this->Transform->Delete();
}
void vtkBrokenLineWidget::SetHandlePosition( int handle, double x,
double y, double z )
{
if ( handle < 0 || handle >= this->NumberOfHandles )
{
vtkErrorMacro(<<"vtkBrokenLineWidget: handle index out of range.");
return;
}
this->HandleGeometry[handle]->SetCenter( x,y,z );
this->HandleGeometry[handle]->Update();
if ( this->ProjectToPlane )
{
this->ProjectPointsToPlane();
}
this->BuildRepresentation();
}
void vtkBrokenLineWidget::SetHandlePosition( int handle, double xyz[3])
{
this->SetHandlePosition( handle,xyz[0],xyz[1],xyz[2]);
}
void vtkBrokenLineWidget::GetHandlePosition( int handle, double xyz[3])
{
if ( handle < 0 || handle >= this->NumberOfHandles )
{
vtkErrorMacro(<<"vtkBrokenLineWidget: handle index out of range.");
return;
}
this->HandleGeometry[handle]->GetCenter( xyz );
}
double* vtkBrokenLineWidget::GetHandlePosition( int handle )
{
if ( handle < 0 || handle >= this->NumberOfHandles )
{
vtkErrorMacro(<<"vtkBrokenLineWidget: handle index out of range.");
return NULL;
}
return this->HandleGeometry[handle]->GetCenter();
}
void vtkBrokenLineWidget::SetEnabled( int enabling )
{
if ( ! this->Interactor )
{
vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget");
return;
}
if ( enabling ) //------------------------------------------------------------
{
vtkDebugMacro(<<"Enabling broken line widget");
if ( this->Enabled ) //already enabled, just return
{
return;
}
if ( ! this->CurrentRenderer )
{
this->SetCurrentRenderer( this->Interactor->FindPokedRenderer(
this->Interactor->GetLastEventPosition()[0],
this->Interactor->GetLastEventPosition()[1]) );
if ( this->CurrentRenderer == NULL )
{
return;
}
}
this->Enabled = 1;
// Listen for the following events
vtkRenderWindowInteractor *i = this->Interactor;
i->AddObserver( vtkCommand::MouseMoveEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::LeftButtonPressEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::LeftButtonReleaseEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::MiddleButtonPressEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::MiddleButtonReleaseEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::RightButtonPressEvent, this->EventCallbackCommand,
this->Priority );
i->AddObserver( vtkCommand::RightButtonReleaseEvent, this->EventCallbackCommand,
this->Priority );
// Add the line
this->CurrentRenderer->AddActor( this->LineActor );
this->LineActor->SetProperty( this->LineProperty );
// Turn on the handles
for ( int j = 0; j < this->NumberOfHandles; ++j )
{
this->CurrentRenderer->AddActor( this->Handle[j]);
this->Handle[j]->SetProperty( this->HandleProperty );
}
this->BuildRepresentation();
this->SizeHandles();
this->InvokeEvent( vtkCommand::EnableEvent,NULL );
}
else //disabling----------------------------------------------------------
{
vtkDebugMacro(<<"Disabling broken line widget");
if ( ! this->Enabled ) //already disabled, just return
{
return;
}
this->Enabled = 0;
// Don't listen for events any more
this->Interactor->RemoveObserver( this->EventCallbackCommand );
// Turn off the line
this->CurrentRenderer->RemoveActor( this->LineActor );
// Turn off the handles
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->CurrentRenderer->RemoveActor( this->Handle[i]);
}
this->CurrentHandle = NULL;
this->InvokeEvent( vtkCommand::DisableEvent,NULL );
this->SetCurrentRenderer( NULL );
}
this->Interactor->Render();
}
void vtkBrokenLineWidget::ProcessEventsHandler( vtkObject* vtkNotUsed( object ),
unsigned long event,
void* clientdata,
void* vtkNotUsed( calldata ) )
{
vtkBrokenLineWidget* self = reinterpret_cast<vtkBrokenLineWidget *>( clientdata );
// if ProcessEvents is Off, we ignore all interaction events.
if (! self->GetProcessEvents() )
{
return;
}
// Okay, let's do the right thing
switch( event )
{
case vtkCommand::LeftButtonPressEvent:
self->OnLeftButtonDown();
break;
case vtkCommand::LeftButtonReleaseEvent:
self->OnLeftButtonUp();
break;
case vtkCommand::MiddleButtonPressEvent:
self->OnMiddleButtonDown();
break;
case vtkCommand::MiddleButtonReleaseEvent:
self->OnMiddleButtonUp();
break;
case vtkCommand::RightButtonPressEvent:
self->OnRightButtonDown();
break;
case vtkCommand::RightButtonReleaseEvent:
self->OnRightButtonUp();
break;
case vtkCommand::MouseMoveEvent:
self->OnMouseMove();
break;
}
}
void vtkBrokenLineWidget::PrintSelf( ostream& os, vtkIndent indent )
{
this->Superclass::PrintSelf( os,indent );
os << indent << "ProcessEvents: "
<< ( this->ProcessEvents? "On" : "Off") << "\n";
if ( this->HandleProperty )
{
os << indent << "Handle Property: " << this->HandleProperty << "\n";
}
else
{
os << indent << "Handle Property: ( none )\n";
}
if ( this->SelectedHandleProperty )
{
os << indent << "Selected Handle Property: "
<< this->SelectedHandleProperty << "\n";
}
else
{
os << indent << "Selected Handle Property: ( none )\n";
}
if ( this->LineProperty )
{
os << indent << "Line Property: " << this->LineProperty << "\n";
}
else
{
os << indent << "Line Property: ( none )\n";
}
if ( this->SelectedLineProperty )
{
os << indent << "Selected Line Property: "
<< this->SelectedLineProperty << "\n";
}
else
{
os << indent << "Selected Line Property: ( none )\n";
}
os << indent << "Project To Plane: "
<< ( this->ProjectToPlane ? "On" : "Off") << "\n";
os << indent << "Projection Normal: " << this->ProjectionNormal << "\n";
os << indent << "Projection Position: " << this->ProjectionPosition << "\n";
os << indent << "Number Of Handles: " << this->NumberOfHandles << "\n";
os << indent << "Handle Size Factor" << this->HandleSizeFactor << "\n";
}
void vtkBrokenLineWidget::ProjectPointsToPlane()
{
if ( this->ProjectionNormal == VTK_PROJECTION_OBLIQUE )
{
if ( this->PlaneSource != NULL )
{
this->ProjectPointsToObliquePlane();
}
else
{
vtkGenericWarningMacro(<<"Set the plane source for oblique projections...");
}
}
else
{
this->ProjectPointsToOrthoPlane();
}
}
void vtkBrokenLineWidget::ProjectPointsToObliquePlane()
{
double o[3];
double u[3];
double v[3];
this->PlaneSource->GetPoint1( u );
this->PlaneSource->GetPoint2( v );
this->PlaneSource->GetOrigin( o );
int i;
for ( i = 0; i < 3; ++ i )
{
u[i] = u[i] - o[i];
v[i] = v[i] - o[i];
}
vtkMath::Normalize( u );
vtkMath::Normalize( v );
double o_dot_u = vtkMath::Dot( o,u );
double o_dot_v = vtkMath::Dot( o,v );
double fac1;
double fac2;
double ctr[3];
for ( i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->GetCenter( ctr );
fac1 = vtkMath::Dot( ctr,u ) - o_dot_u;
fac2 = vtkMath::Dot( ctr,v ) - o_dot_v;
ctr[0] = o[0] + fac1*u[0] + fac2*v[0];
ctr[1] = o[1] + fac1*u[1] + fac2*v[1];
ctr[2] = o[2] + fac1*u[2] + fac2*v[2];
this->HandleGeometry[i]->SetCenter( ctr );
this->HandleGeometry[i]->Update();
}
}
void vtkBrokenLineWidget::ProjectPointsToOrthoPlane()
{
double ctr[3];
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->GetCenter( ctr );
ctr[this->ProjectionNormal] = this->ProjectionPosition;
this->HandleGeometry[i]->SetCenter( ctr );
this->HandleGeometry[i]->Update();
}
}
//------------------------------------------------------------------------------
void vtkBrokenLineWidget::RegisterPickers()
{
this->Interactor->GetPickingManager()->AddPicker(this->HandlePicker, this);
this->Interactor->GetPickingManager()->AddPicker(this->LinePicker, this);
}
void vtkBrokenLineWidget::BuildRepresentation()
{
// Get points array from line source
vtkPoints* points = this->LineSource->GetPoints();
if ( points->GetNumberOfPoints() != this->NumberOfHandles )
{
points->SetNumberOfPoints( this->NumberOfHandles );
}
double pt[3];
int i;
for ( i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->GetCenter( pt );
points->SetPoint( i, pt );
}
this->LineSource->Modified();
}
int vtkBrokenLineWidget::HighlightHandle( vtkProp *prop )
{
// First unhighlight anything picked
if ( this->CurrentHandle )
{
this->CurrentHandle->SetProperty( this->HandleProperty );
}
this->CurrentHandle = static_cast<vtkActor *>( prop );
if ( this->CurrentHandle )
{
for ( int i = 0; i < this->NumberOfHandles; ++ i ) // find handle
{
if ( this->CurrentHandle == this->Handle[i] )
{
this->ValidPick = 1;
this->HandlePicker->GetPickPosition( this->LastPickPosition );
this->CurrentHandle->SetProperty( this->SelectedHandleProperty );
return i;
}
}
}
return -1;
}
void vtkBrokenLineWidget::HighlightLine( int highlight )
{
if ( highlight )
{
this->ValidPick = 1;
this->LinePicker->GetPickPosition( this->LastPickPosition );
this->LineActor->SetProperty( this->SelectedLineProperty );
}
else
{
this->LineActor->SetProperty( this->LineProperty );
}
}
void vtkBrokenLineWidget::OnLeftButtonDown()
{
int X = this->Interactor->GetEventPosition()[0];
int Y = this->Interactor->GetEventPosition()[1];
// Okay, make sure that the pick is in the current renderer
if ( ! this->CurrentRenderer || ! this->CurrentRenderer->IsInViewport( X, Y ) )
{
this->State = vtkBrokenLineWidget::Outside;
return;
}
this->State = vtkBrokenLineWidget::Moving;
// Okay, we can process this. Try to pick handles first;
// if no handles picked, then try to pick the line.
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
if ( path != NULL )
{
this->CurrentHandleIndex = this->HighlightHandle( path->GetFirstNode()->GetViewProp() );
}
else
{
path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
if ( path != NULL )
{
this->HighlightLine( 1 );
}
else
{
this->CurrentHandleIndex = this->HighlightHandle( NULL );
this->State = vtkBrokenLineWidget::Outside;
return;
}
}
this->EventCallbackCommand->SetAbortFlag( 1 );
this->StartInteraction();
this->InvokeEvent( vtkCommand::StartInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnLeftButtonUp()
{
if ( this->State == vtkBrokenLineWidget::Outside ||
this->State == vtkBrokenLineWidget::Start )
{
return;
}
this->State = vtkBrokenLineWidget::Start;
this->HighlightHandle( NULL );
this->HighlightLine( 0 );
this->SizeHandles();
this->EventCallbackCommand->SetAbortFlag( 1 );
this->EndInteraction();
this->InvokeEvent( vtkCommand::EndInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnMiddleButtonDown()
{
int X = this->Interactor->GetEventPosition()[0];
int Y = this->Interactor->GetEventPosition()[1];
// Okay, make sure that the pick is in the current renderer
if ( ! this->CurrentRenderer || ! this->CurrentRenderer->IsInViewport( X, Y ) )
{
this->State = vtkBrokenLineWidget::Outside;
return;
}
if ( this->Interactor->GetControlKey() )
{
this->State = vtkBrokenLineWidget::Spinning;
this->CalculateCentroid();
}
else
{
this->State = vtkBrokenLineWidget::Moving;
}
// Okay, we can process this. Try to pick handles first;
// if no handles picked, then try to pick the line.
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
if ( path == NULL )
{
path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
if ( path == NULL )
{
this->State = vtkBrokenLineWidget::Outside;
this->HighlightLine( 0 );
return;
}
else
{
this->HighlightLine( 1 );
}
}
else //we picked a handle but lets make it look like the line is picked
{
this->HighlightLine( 1 );
}
this->EventCallbackCommand->SetAbortFlag( 1 );
this->StartInteraction();
this->InvokeEvent( vtkCommand::StartInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnMiddleButtonUp()
{
if ( this->State == vtkBrokenLineWidget::Outside ||
this->State == vtkBrokenLineWidget::Start )
{
return;
}
this->State = vtkBrokenLineWidget::Start;
this->HighlightLine( 0 );
this->SizeHandles();
this->EventCallbackCommand->SetAbortFlag( 1 );
this->EndInteraction();
this->InvokeEvent( vtkCommand::EndInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnRightButtonDown()
{
int X = this->Interactor->GetEventPosition()[0];
int Y = this->Interactor->GetEventPosition()[1];
// Okay, make sure that the pick is in the current renderer
if ( ! this->CurrentRenderer || ! this->CurrentRenderer->IsInViewport( X, Y ) )
{
this->State = vtkBrokenLineWidget::Outside;
return;
}
if ( this->Interactor->GetShiftKey() )
{
this->State = vtkBrokenLineWidget::Inserting;
}
else if ( this->Interactor->GetControlKey() )
{
this->State = vtkBrokenLineWidget::Erasing;
}
else
{
this->State = vtkBrokenLineWidget::Scaling;
}
vtkAssemblyPath* path = this->GetAssemblyPath(X, Y, 0., this->HandlePicker);
if ( path != NULL )
{
switch ( this->State )
{
// deny insertion over existing handles
case vtkBrokenLineWidget::Inserting:
this->State = vtkBrokenLineWidget::Outside;
return;
case vtkBrokenLineWidget::Erasing:
this->CurrentHandleIndex = \
this->HighlightHandle( path->GetFirstNode()->GetViewProp() );
break;
case vtkBrokenLineWidget::Scaling:
this->HighlightLine( 1 );
break;
}
}
else
{
// trying to erase handle but nothing picked
if ( this->State == vtkBrokenLineWidget::Erasing )
{
this->State = vtkBrokenLineWidget::Outside;
return;
}
// try to insert or scale so pick the line
path = this->GetAssemblyPath(X, Y, 0., this->LinePicker);
if ( path != NULL )
{
this->HighlightLine( 1 );
}
else
{
this->State = vtkBrokenLineWidget::Outside;
return;
}
}
this->EventCallbackCommand->SetAbortFlag( 1 );
this->StartInteraction();
this->InvokeEvent( vtkCommand::StartInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnRightButtonUp()
{
if ( this->State == vtkBrokenLineWidget::Outside ||
this->State == vtkBrokenLineWidget::Start )
{
return;
}
if ( this->State == vtkBrokenLineWidget::Inserting )
{
this->InsertHandleOnLine( this->LastPickPosition );
}
else if ( this->State == vtkBrokenLineWidget::Erasing )
{
int index = this->CurrentHandleIndex;
this->CurrentHandleIndex = this->HighlightHandle( NULL );
this->EraseHandle( index );
}
this->State = vtkBrokenLineWidget::Start;
this->HighlightLine( 0 );
this->SizeHandles();
this->EventCallbackCommand->SetAbortFlag( 1 );
this->EndInteraction();
this->InvokeEvent( vtkCommand::EndInteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::OnMouseMove()
{
// See whether we're active
if ( this->State == vtkBrokenLineWidget::Outside ||
this->State == vtkBrokenLineWidget::Start )
{
return;
}
int X = this->Interactor->GetEventPosition()[0];
int Y = this->Interactor->GetEventPosition()[1];
// Do different things depending on state
// Calculations everybody does
double focalPoint[4], pickPoint[4], prevPickPoint[4];
double z, vpn[3];
vtkCamera *camera = this->CurrentRenderer->GetActiveCamera();
if ( ! camera )
{
return;
}
// Compute the two points defining the motion vector
this->ComputeWorldToDisplay( this->LastPickPosition[0], this->LastPickPosition[1],
this->LastPickPosition[2], focalPoint );
z = focalPoint[2];
this->ComputeDisplayToWorld( double( this->Interactor->GetLastEventPosition()[0]),
double( this->Interactor->GetLastEventPosition()[1]),
z, prevPickPoint );
this->ComputeDisplayToWorld( double( X ), double( Y ), z, pickPoint );
// Process the motion
if ( this->State == vtkBrokenLineWidget::Moving )
{
// Okay to process
if ( this->CurrentHandle )
{
this->MovePoint( prevPickPoint, pickPoint );
}
else // Must be moving the spline
{
this->Translate( prevPickPoint, pickPoint );
}
}
else if ( this->State == vtkBrokenLineWidget::Scaling )
{
this->Scale( prevPickPoint, pickPoint, X, Y );
}
else if ( this->State == vtkBrokenLineWidget::Spinning )
{
camera->GetViewPlaneNormal( vpn );
this->Spin( prevPickPoint, pickPoint, vpn );
}
if ( this->ProjectToPlane )
{
this->ProjectPointsToPlane();
}
this->BuildRepresentation();
// Interact, if desired
this->EventCallbackCommand->SetAbortFlag( 1 );
this->InvokeEvent( vtkCommand::InteractionEvent,NULL );
this->Interactor->Render();
}
void vtkBrokenLineWidget::MovePoint( double *p1, double *p2 )
{
if ( this->CurrentHandleIndex < 0 || this->CurrentHandleIndex >= this->NumberOfHandles )
{
vtkGenericWarningMacro(<<"BrokenLine handle index out of range.");
return;
}
// 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];
double *ctr = this->HandleGeometry[this->CurrentHandleIndex]->GetCenter();
double newCtr[3];
newCtr[0] = ctr[0] + v[0];
newCtr[1] = ctr[1] + v[1];
newCtr[2] = ctr[2] + v[2];
this->HandleGeometry[this->CurrentHandleIndex]->SetCenter( newCtr );
this->HandleGeometry[this->CurrentHandleIndex]->Update();
}
void vtkBrokenLineWidget::Translate( 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];
double newCtr[3];
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
double* ctr = this->HandleGeometry[i]->GetCenter();
for ( int j = 0; j < 3; ++j )
{
newCtr[j] = ctr[j] + v[j];
}
this->HandleGeometry[i]->SetCenter( newCtr );
this->HandleGeometry[i]->Update();
}
}
void vtkBrokenLineWidget::Scale( double *p1, double *p2, int vtkNotUsed( X ), int Y )
{
// 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];
double center[3] = { 0., 0., 0. };
double avgdist = 0.;
double *prevctr = this->HandleGeometry[0]->GetCenter();
double *ctr;
center[0] += prevctr[0];
center[1] += prevctr[1];
center[2] += prevctr[2];
int i;
for ( i = 1; i < this->NumberOfHandles; ++ i )
{
ctr = this->HandleGeometry[i]->GetCenter();
center[0] += ctr[0];
center[1] += ctr[1];
center[2] += ctr[2];
avgdist += sqrt( vtkMath::Distance2BetweenPoints( ctr,prevctr ) );
prevctr = ctr;
}
avgdist /= this->NumberOfHandles;
center[0] /= this->NumberOfHandles;
center[1] /= this->NumberOfHandles;
center[2] /= this->NumberOfHandles;
// Compute the scale factor
double sf = vtkMath::Norm( v ) / avgdist;
if ( Y > this->Interactor->GetLastEventPosition()[1] )
{
sf = 1.0 + sf;
}
else
{
sf = 1.0 - sf;
}
// Move the handle points
double newCtr[3];
for ( i = 0; i < this->NumberOfHandles; ++ i )
{
ctr = this->HandleGeometry[i]->GetCenter();
for ( int j = 0; j < 3; ++j )
{
newCtr[j] = sf * ( ctr[j] - center[j]) + center[j];
}
this->HandleGeometry[i]->SetCenter( newCtr );
this->HandleGeometry[i]->Update();
}
}
void vtkBrokenLineWidget::Spin( double *p1, double *p2, double *vpn )
{
// Mouse motion vector in world space
double v[3];
v[0] = p2[0] - p1[0];
v[1] = p2[1] - p1[1];
v[2] = p2[2] - p1[2];
// Axis of rotation
double axis[3] = { 0., 0., 0. };
if ( this->ProjectToPlane )
{
if ( this->ProjectionNormal == VTK_PROJECTION_OBLIQUE)
{
if (this->PlaneSource != NULL )
{
double* normal = this->PlaneSource->GetNormal();
axis[0] = normal[0];
axis[1] = normal[1];
axis[2] = normal[2];
vtkMath::Normalize( axis );
}
else
{
axis[0] = 1.;
}
}
else
{
axis[ this->ProjectionNormal ] = 1.;
}
}
else
{
// Create axis of rotation and angle of rotation
vtkMath::Cross( vpn,v,axis );
if ( vtkMath::Normalize( axis ) == 0. )
{
return;
}
}
// Radius vector ( from mean center to cursor position )
double rv[3] = {p2[0] - this->Centroid[0],
p2[1] - this->Centroid[1],
p2[2] - this->Centroid[2]};
// Distance between center and cursor location
double rs = vtkMath::Normalize( rv );
// Spin direction
double ax_cross_rv[3];
vtkMath::Cross( axis,rv,ax_cross_rv );
// Spin angle
double theta = 360. * vtkMath::Dot( v,ax_cross_rv ) / rs;
// Manipulate the transform to reflect the rotation
this->Transform->Identity();
this->Transform->Translate( this->Centroid[0],this->Centroid[1],this->Centroid[2]);
this->Transform->RotateWXYZ( theta,axis );
this->Transform->Translate(-this->Centroid[0],-this->Centroid[1],-this->Centroid[2]);
// Set the handle points
double newCtr[3];
double ctr[3];
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->GetCenter( ctr );
this->Transform->TransformPoint( ctr,newCtr );
this->HandleGeometry[i]->SetCenter( newCtr );
this->HandleGeometry[i]->Update();
}
}
void vtkBrokenLineWidget::CreateDefaultProperties()
{
if ( ! this->HandleProperty )
{
this->HandleProperty = vtkProperty::New();
this->HandleProperty->SetColor( 1,1,1 );
}
if ( ! this->SelectedHandleProperty )
{
this->SelectedHandleProperty = vtkProperty::New();
this->SelectedHandleProperty->SetColor( 1,0,0 );
}
if ( ! this->LineProperty )
{
this->LineProperty = vtkProperty::New();
this->LineProperty->SetRepresentationToWireframe();
this->LineProperty->SetAmbient( 1. );
this->LineProperty->SetColor( 1., 1., 0. );
this->LineProperty->SetLineWidth( 2. );
}
if ( ! this->SelectedLineProperty )
{
this->SelectedLineProperty = vtkProperty::New();
this->SelectedLineProperty->SetRepresentationToWireframe();
this->SelectedLineProperty->SetAmbient( 1. );
this->SelectedLineProperty->SetAmbientColor( 0., 1., 0. );
this->SelectedLineProperty->SetLineWidth( 2. );
}
}
void vtkBrokenLineWidget::PlaceWidget( double bds[6])
{
double bounds[6], center[3];
this->AdjustBounds( bds, bounds, center );
if ( this->ProjectToPlane )
{
this->ProjectPointsToPlane();
}
else //place the center
{
// Create a default straight line within the data bounds
double x0 = bounds[0];
double x1 = bounds[1];
double y0 = bounds[2];
double y1 = bounds[3];
double z0 = bounds[4];
double z1 = bounds[5];
double x;
double y;
double z;
double u;
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
u = i/( this->NumberOfHandles - 1.0 );
x = ( 1.0 - u )*x0 + u*x1;
y = ( 1.0 - u )*y0 + u*y1;
z = ( 1.0 - u )*z0 + u*z1;
this->HandleGeometry[i]->SetCenter( x, y, z );
}
}
for ( int i = 0; i < 6; ++ i )
{
this->InitialBounds[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->BuildRepresentation();
this->SizeHandles();
}
void vtkBrokenLineWidget::SetProjectionPosition( double position )
{
this->ProjectionPosition = position;
if ( this->ProjectToPlane )
{
this->ProjectPointsToPlane();
}
this->BuildRepresentation();
}
void vtkBrokenLineWidget::SetPlaneSource( vtkPlaneSource* plane )
{
if ( this->PlaneSource == plane )
{
return;
}
this->PlaneSource = plane;
}
void vtkBrokenLineWidget::SetNumberOfHandles( int npts )
{
if ( this->NumberOfHandles == npts )
{
return;
}
if ( npts < 2 )
{
vtkGenericWarningMacro(<<"Minimum of 2 points required to define a broken line.");
return;
}
double radius = this->HandleGeometry[0]->GetRadius();
this->Initialize();
this->NumberOfHandles = npts;
// Create the handles
this->Handle = new vtkActor* [this->NumberOfHandles];
this->HandleGeometry = new vtkSphereSource* [this->NumberOfHandles];
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i] = vtkSphereSource::New();
this->HandleGeometry[i]->SetThetaResolution( 16 );
this->HandleGeometry[i]->SetPhiResolution( 8 );
vtkPolyDataMapper* handleMapper = vtkPolyDataMapper::New();
handleMapper->SetInputConnection( this->HandleGeometry[i]->GetOutputPort() );
this->Handle[i] = vtkActor::New();
this->Handle[i]->SetMapper( handleMapper );
handleMapper->Delete();
this->Handle[i]->SetProperty( this->HandleProperty );
this->HandleGeometry[i]->SetRadius( radius );
this->HandlePicker->AddPickList( this->Handle[i]);
}
if ( this->Interactor )
{
if ( ! this->CurrentRenderer )
{
this->SetCurrentRenderer(
this->Interactor->FindPokedRenderer(
this->Interactor->GetLastEventPosition()[0],
this->Interactor->GetLastEventPosition()[1]) );
}
if ( this->CurrentRenderer != NULL )
{
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->CurrentRenderer->AddViewProp( this->Handle[i]);
}
this->SizeHandles();
}
this->Interactor->Render();
}
}
void vtkBrokenLineWidget::Initialize( void )
{
int i;
if ( this->Interactor )
{
if ( ! this->CurrentRenderer )
{
this->SetCurrentRenderer( this->Interactor->FindPokedRenderer(
this->Interactor->GetLastEventPosition()[0],
this->Interactor->GetLastEventPosition()[1]) );
}
if ( this->CurrentRenderer != NULL )
{
for ( i = 0; i < this->NumberOfHandles; ++ i )
{
this->CurrentRenderer->RemoveViewProp( this->Handle[i]);
}
}
}
for ( i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandlePicker->DeletePickList( this->Handle[i]);
this->HandleGeometry[i]->Delete();
this->Handle[i]->Delete();
}
this->NumberOfHandles = 0;
delete [] this->Handle;
delete [] this->HandleGeometry;
}
void vtkBrokenLineWidget::GetPolyData( vtkPolyData *pd )
{
pd->ShallowCopy( this->LineSource->GetOutput() );
}
void vtkBrokenLineWidget::SizeHandles()
{
double radius = this->vtk3DWidget::SizeHandles( this->HandleSizeFactor );
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->SetRadius( radius );
}
}
double vtkBrokenLineWidget::GetSummedLength()
{
vtkPoints* points = this->LineSource->GetOutput()->GetPoints();
if(!points)
{
return 0.;
}
int npts = points->GetNumberOfPoints();
if ( npts < 2 )
{
return 0.;
}
double a[3];
double b[3];
double sum = 0.;
int i = 0;
points->GetPoint( i, a );
int imax = ( npts % 2 == 0 ) ? npts - 2 : npts - 1;
while ( i < imax )
{
points->GetPoint( i + 1, b );
sum += sqrt( vtkMath::Distance2BetweenPoints( a, b ) );
i = i + 2;
points->GetPoint( i, a );
sum = sum + sqrt( vtkMath::Distance2BetweenPoints( a, b ) );
}
if ( npts%2 == 0 )
{
points->GetPoint( i + 1, b );
sum += sqrt( vtkMath::Distance2BetweenPoints( a, b ) );
}
return sum;
}
void vtkBrokenLineWidget::CalculateCentroid()
{
this->Centroid[0] = 0.;
this->Centroid[1] = 0.;
this->Centroid[2] = 0.;
double ctr[3];
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
this->HandleGeometry[i]->GetCenter( ctr );
this->Centroid[0] += ctr[0];
this->Centroid[1] += ctr[1];
this->Centroid[2] += ctr[2];
}
this->Centroid[0] /= this->NumberOfHandles;
this->Centroid[1] /= this->NumberOfHandles;
this->Centroid[2] /= this->NumberOfHandles;
}
void vtkBrokenLineWidget::InsertHandleOnLine( double* pos )
{
if ( this->NumberOfHandles < 2 ) { return; }
vtkIdType id = this->LinePicker->GetCellId();
if ( id == -1 ){ return; }
vtkIdType subid = this->LinePicker->GetSubId();
vtkPoints* newpoints = vtkPoints::New( VTK_DOUBLE );
newpoints->SetNumberOfPoints( this->NumberOfHandles + 1 );
int istart = subid;
int istop = istart + 1;
int count = 0;
int i;
for ( i = 0; i <= istart; ++ i )
{
newpoints->SetPoint( count ++, this->HandleGeometry[i]->GetCenter() );
}
newpoints->SetPoint( count ++, pos );
for ( i = istop; i < this->NumberOfHandles; ++ i )
{
newpoints->SetPoint( count ++, this->HandleGeometry[i]->GetCenter() );
}
this->InitializeHandles( newpoints );
newpoints->Delete();
}
void vtkBrokenLineWidget::EraseHandle( const int& index )
{
if ( this->NumberOfHandles < 3 || index < 0 || index >= this->NumberOfHandles )
{
return;
}
vtkPoints* newpoints = vtkPoints::New( VTK_DOUBLE );
newpoints->SetNumberOfPoints( this->NumberOfHandles-1 );
int count = 0;
for ( int i = 0; i < this->NumberOfHandles; ++ i )
{
if ( i != index )
{
newpoints->SetPoint( count++,this->HandleGeometry[i]->GetCenter() );
}
}
this->InitializeHandles( newpoints );
newpoints->Delete();
}
void vtkBrokenLineWidget::InitializeHandles( vtkPoints* points )
{
if ( ! points )
{
return;
}
int npts = points->GetNumberOfPoints();
if ( npts < 2 )
{
return;
}
double p0[3];
double p1[3];
points->GetPoint( 0, p0 );
points->GetPoint( npts - 1 , p1 );
if ( vtkMath::Distance2BetweenPoints( p0, p1 ) == 0. )
{
--npts;
}
this->SetNumberOfHandles( npts );
int i;
for ( i = 0; i < npts; ++ i )
{
this->SetHandlePosition( i, points->GetPoint( i ) );
}
if ( this->Interactor && this->Enabled )
{
this->Interactor->Render();
}
}