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/vtkResliceCursorPicker.cxx

561 lines
16 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkResliceCursorPicker.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 "vtkResliceCursorPicker.h"
#include "vtkObjectFactory.h"
#include "vtkCommand.h"
#include "vtkMath.h"
#include "vtkPoints.h"
#include "vtkGenericCell.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include "vtkLine.h"
#include "vtkPolyData.h"
#include "vtkRenderWindow.h"
#include "vtkResliceCursor.h"
#include "vtkResliceCursorPolyDataAlgorithm.h"
#include "vtkPlane.h"
#include "vtkMatrix4x4.h"
#include "vtkSmartPointer.h"
vtkStandardNewMacro(vtkResliceCursorPicker);
vtkCxxSetObjectMacro(vtkResliceCursorPicker,
ResliceCursorAlgorithm, vtkResliceCursorPolyDataAlgorithm);
vtkCxxSetObjectMacro(vtkResliceCursorPicker, TransformMatrix, vtkMatrix4x4 );
//----------------------------------------------------------------------------
vtkResliceCursorPicker::vtkResliceCursorPicker()
{
// For polydata picking
this->Cell = vtkGenericCell::New();
// Miscellaneous ivars
this->Tolerance = 1e-6;
this->PickedAxis1 = this->PickedAxis2 = 0;
this->ResliceCursorAlgorithm = NULL;
this->TransformMatrix = NULL;
// Plane on which the cursor lies. This is the picked plane.
this->Plane = vtkPlane::New();
}
//----------------------------------------------------------------------------
vtkResliceCursorPicker::~vtkResliceCursorPicker()
{
this->Cell->Delete();
this->SetResliceCursorAlgorithm(NULL);
this->SetTransformMatrix(NULL);
this->Plane->Delete();
}
//----------------------------------------------------------------------------
int vtkResliceCursorPicker::Pick(double selectionX, double selectionY,
double selectionZ, vtkRenderer *renderer)
{
int i;
vtkCamera *camera;
double p1World[4], p2World[4];
int winSize[2] = {1, 1};
double x, y;
double *viewport;
double cameraPos[4], cameraFP[4];
double *displayCoords, *worldCoords;
double *clipRange;
double ray[3], rayLength;
double windowLowerLeft[4], windowUpperRight[4];
double tF, tB;
double cameraDOP[3];
// Initialize picking process
this->Initialize();
this->Renderer = renderer;
this->SelectionPoint[0] = selectionX;
this->SelectionPoint[1] = selectionY;
this->SelectionPoint[2] = selectionZ;
// Invoke start pick method if defined
this->InvokeEvent(vtkCommand::StartPickEvent,NULL);
if ( renderer == NULL )
{
vtkErrorMacro(<<"Must specify renderer!");
return 0;
}
// Get camera focal point and position. Convert to display (screen)
// coordinates. We need a depth value for z-buffer.
//
camera = renderer->GetActiveCamera();
camera->GetPosition(cameraPos);
cameraPos[3] = 1.0;
camera->GetFocalPoint(cameraFP);
cameraFP[3] = 1.0;
renderer->SetWorldPoint(cameraFP[0],cameraFP[1],cameraFP[2],cameraFP[3]);
renderer->WorldToDisplay();
displayCoords = renderer->GetDisplayPoint();
selectionZ = displayCoords[2];
// Convert the selection point into world coordinates.
//
renderer->SetDisplayPoint(selectionX, selectionY, selectionZ);
renderer->DisplayToWorld();
worldCoords = renderer->GetWorldPoint();
if ( worldCoords[3] == 0.0 )
{
vtkErrorMacro(<<"Bad homogeneous coordinates");
return 0;
}
for (i=0; i < 3; i++)
{
this->PickPosition[i] = worldCoords[i] / worldCoords[3];
}
// Compute the ray endpoints. The ray is along the line running from
// the camera position to the selection point, starting where this line
// intersects the front clipping plane, and terminating where this
// line intersects the back clipping plane.
for (i=0; i<3; i++)
{
ray[i] = this->PickPosition[i] - cameraPos[i];
}
for (i=0; i<3; i++)
{
cameraDOP[i] = cameraFP[i] - cameraPos[i];
}
vtkMath::Normalize(cameraDOP);
if (( rayLength = vtkMath::Dot(cameraDOP,ray)) == 0.0 )
{
vtkWarningMacro("Cannot process points");
return 0;
}
clipRange = camera->GetClippingRange();
if ( camera->GetParallelProjection() )
{
tF = clipRange[0] - rayLength;
tB = clipRange[1] - rayLength;
for (i=0; i<3; i++)
{
p1World[i] = this->PickPosition[i] + tF*cameraDOP[i];
p2World[i] = this->PickPosition[i] + tB*cameraDOP[i];
}
}
else
{
tF = clipRange[0] / rayLength;
tB = clipRange[1] / rayLength;
for (i=0; i<3; i++)
{
p1World[i] = cameraPos[i] + tF*ray[i];
p2World[i] = cameraPos[i] + tB*ray[i];
}
}
p1World[3] = p2World[3] = 1.0;
// Compute the tolerance in world coordinates. Do this by
// determining the world coordinates of the diagonal points of the
// window, computing the width of the window in world coordinates, and
// multiplying by the tolerance.
//
viewport = renderer->GetViewport();
if (renderer->GetRenderWindow())
{
int *winSizePtr = renderer->GetRenderWindow()->GetSize();
if (winSizePtr)
{
winSize[0] = winSizePtr[0];
winSize[1] = winSizePtr[1];
}
}
x = winSize[0] * viewport[0];
y = winSize[1] * viewport[1];
renderer->SetDisplayPoint(x, y, selectionZ);
renderer->DisplayToWorld();
renderer->GetWorldPoint(windowLowerLeft);
x = winSize[0] * viewport[2];
y = winSize[1] * viewport[3];
renderer->SetDisplayPoint(x, y, selectionZ);
renderer->DisplayToWorld();
renderer->GetWorldPoint(windowUpperRight);
double tol;
for (tol=0.0,i=0; i<3; i++)
{
tol += (windowUpperRight[i] - windowLowerLeft[i]) *
(windowUpperRight[i] - windowLowerLeft[i]);
}
tol = sqrt (tol) * this->Tolerance;
vtkResliceCursor *rc =
this->ResliceCursorAlgorithm->GetResliceCursor();
const int axis1 = this->ResliceCursorAlgorithm->GetAxis1();
const int axis2 = this->ResliceCursorAlgorithm->GetAxis2();
//const int axis3 = this->ResliceCursorAlgorithm->GetReslicePlaneNormal();
double center[3];
rc->GetCenter(center);
this->PickedCenter = this->IntersectPointWithLine( p1World, p2World,
center, tol );
this->PickedAxis1 = this->IntersectPolyDataWithLine( p1World, p2World,
rc->GetCenterlineAxisPolyData(axis1), tol);
this->PickedAxis2 = this->IntersectPolyDataWithLine( p1World, p2World,
rc->GetCenterlineAxisPolyData(axis2), tol);
if (this->PickedAxis1 || this->PickedAxis2 || this->PickedCenter)
{
// Pick on transformed plane coords and get the real coords back after
// inverse transformation.
double t, pickPosT[4], pickPos[4];
this->TransformPlane();
this->Plane->IntersectWithLine(p1World, p2World, t, pickPosT);
pickPosT[3] = 1.0;
this->InverseTransformPoint( pickPosT, pickPos );
this->PickPosition[0] = pickPos[0];
this->PickPosition[1] = pickPos[1];
this->PickPosition[2] = pickPos[2];
}
return this->PickedAxis1 + this->PickedAxis2 + this->PickedCenter;
}
//----------------------------------------------------------------------------
// Pick a display coordinate and return the picked world coordinates
//
void vtkResliceCursorPicker::Pick(
double displayPos[2], double world[3], vtkRenderer *ren )
{
// First compute the equivalent of this display point on the focal plane
double fp[4], tmp1[4], camPos[4], eventFPpos[4];
ren->GetActiveCamera()->GetFocalPoint(fp);
ren->GetActiveCamera()->GetPosition(camPos);
fp[3] = 1.0;
ren->SetWorldPoint(fp);
ren->WorldToDisplay();
ren->GetDisplayPoint(tmp1);
tmp1[0] = displayPos[0];
tmp1[1] = displayPos[1];
this->Renderer->SetDisplayPoint(tmp1);
this->Renderer->DisplayToWorld();
// This is the world coordinates of the point on the focal plane.
this->Renderer->GetWorldPoint(eventFPpos);
// Now construct the pick ray
double cameraDOP[3];
for (int i=0; i<3; i++)
{
cameraDOP[i] = fp[i] - camPos[i];
}
double otherPoint[3] = { eventFPpos[0] + cameraDOP[0],
eventFPpos[1] + cameraDOP[1],
eventFPpos[2] + cameraDOP[2] };
double t, pickPosT[4], pickPos[4];
// Transform the plane into one that lies on the resliced plane
this->TransformPlane();
// Pick it
this->Plane->IntersectWithLine(eventFPpos, otherPoint, t, pickPosT);
// Transform it back from the resliced plane coords to actual world coords
pickPosT[3] = 1.0;
this->InverseTransformPoint( pickPosT, pickPos );
// Copy the result
for (int i=0; i<3; i++)
{
world[i] = pickPos[i];
}
}
//----------------------------------------------------------------------------
// Helper function for sanity check - to see if one point is different from
// another.
//
static bool vtkResliceCursorPickerIsDifferentSanityCheck(
const double a[3], const double b[3] )
{
// Tolerance of 0.0001 needs some fluff..
return (fabs(a[0] - b[0]) > 0.0001 ||
fabs(a[1] - b[1]) > 0.0001 ||
fabs(a[2] - b[2]) > 0.0001);
}
//----------------------------------------------------------------------------
// Transform the reslice plane onto the co-ordinate system its displayed in.
//
void vtkResliceCursorPicker::TransformPlane()
{
vtkResliceCursor *rc =
this->ResliceCursorAlgorithm->GetResliceCursor();
const int axis3 = this->ResliceCursorAlgorithm->GetReslicePlaneNormal();
double origin[4] = {0,0,0,1}, originT[4];
double normal[3];
rc->GetPlane(axis3)->GetOrigin(origin);
rc->GetPlane(axis3)->GetNormal(normal);
if (!this->TransformMatrix)
{
this->Plane->SetOrigin(origin);
this->Plane->SetNormal(normal);
// The origin of the reslice cursor will remain untransformed.
double center[3];
rc->GetCenter(center);
// Sanity check
if (vtkResliceCursorPickerIsDifferentSanityCheck(origin,center))
{
vtkErrorMacro( "Reslice cursor center of (" << center[0]
<< "," << center[1] << "," << center[2] << ") is not equal to plane "
<< "origin along axis " << axis3 << " of (" << origin[0]
<< "," << origin[1] << "," << origin[2] << ").");
}
return;
}
double normalPoint[4] = { origin[0] + normal[0],
origin[1] + normal[1],
origin[2] + normal[2],
1.0 };
double normalPointT[4];
this->TransformPoint(origin, originT);
// Sanity check
if (vtkResliceCursorPickerIsDifferentSanityCheck(origin,originT))
{
vtkErrorMacro( "Reslice cursor after transformation (" << originT[0]
<< "," << originT[1] << "," << originT[2] << ") is not equal to before "
<< "transformation along axis " << axis3 << " of (" << origin[0]
<< "," << origin[1] << "," << origin[2] << ").");
}
this->TransformPoint(normalPoint, normalPointT);
double normalT[3];
vtkMath::Subtract( normalPointT, originT, normalT );
vtkMath::Normalize(normalT);
// The origin of the reslice cursor will remain untransformed.
double center[3];
rc->GetCenter(center);
// Sanity check
if (vtkResliceCursorPickerIsDifferentSanityCheck(origin,center))
{
vtkErrorMacro( "Reslice cursor center of (" << center[0]
<< "," << center[1] << "," << center[2] << ") is not equal to plane "
<< "origin along axis " << axis3 << " of (" << origin[0]
<< "," << origin[1] << "," << origin[2] << ").");
}
this->Plane->SetOrigin(originT);
this->Plane->SetNormal(normalT);
}
//----------------------------------------------------------------------------
void vtkResliceCursorPicker::TransformPoint( double pIn[4], double pOut[4] )
{
this->TransformMatrix->MultiplyPoint(pIn, pOut);
}
//----------------------------------------------------------------------------
void vtkResliceCursorPicker::InverseTransformPoint( double pIn[4], double pOut[4] )
{
if (!this->TransformMatrix)
{
for (int i = 0; i < 3; i++)
{
pOut[i] = pIn[i];
}
return;
}
// Maintain a copy of the existing elements.
double elements[4][4];
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
elements[i][j] = this->TransformMatrix->Element[i][j];
}
}
// Invert matrix
this->TransformMatrix->Invert();
// Transform point
this->TransformPoint(pIn, pOut);
// Copy back the elements.
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
this->TransformMatrix->Element[i][j] = elements[i][j];
}
}
}
//----------------------------------------------------------------------------
int vtkResliceCursorPicker::IntersectPolyDataWithLine(
double p1[3], double p2[3], vtkPolyData *data, double tol )
{
vtkIdType numCells = data->GetNumberOfCells();
for (vtkIdType cellId = 0; cellId < numCells; cellId++)
{
double t;
double x[3];
double pcoords[3];
pcoords[0] = pcoords[1] = pcoords[2] = 0;
int newSubId = -1;
int numSubIds = 1;
// This will only loop once unless we need to deal with a strip
for (int subId = 0; subId < numSubIds; subId++)
{
data->GetCell(cellId, this->Cell);
// Transform the points using any transform matrix that may be set.
for (int i = 0; i < this->Cell->GetPoints()->GetNumberOfPoints(); i++)
{
if (this->TransformMatrix)
{
double pIn[4] = {0,0,0,1}, pOut[4];
this->Cell->GetPoints()->GetPoint(i,pIn);
this->TransformMatrix->MultiplyPoint(pIn,pOut);
this->Cell->GetPoints()->SetPoint(i,pOut);
}
}
int cellPicked = 0;
cellPicked = this->Cell->IntersectWithLine(
const_cast<double *>(p1), const_cast<double *>(p2),
tol, t, x, pcoords, newSubId);
if (cellPicked)
{
return cellPicked;
}
} // if a close cell
} // for all cells
return 0;
}
//----------------------------------------------------------------------------
int vtkResliceCursorPicker::IntersectPointWithLine(
double p1[3], double p2[3], double x[3], double tol )
{
double X[4] = {x[0], x[1], x[2], 1};
if (this->TransformMatrix)
{
double pIn[4] = {x[0], x[1], x[2], 1};
this->TransformMatrix->MultiplyPoint(pIn,X);
}
int i;
double ray[3], rayFactor, projXYZ[3];
for (i=0; i<3; i++)
{
ray[i] = p2[i] - p1[i];
}
if (( rayFactor = vtkMath::Dot(ray,ray)) == 0.0 )
{
return 0;
}
//
// Project each point onto ray. Determine if point is within tolerance.
//
const double t = (ray[0]*(X[0]-p1[0]) +
ray[1]*(X[1]-p1[1]) +
ray[2]*(X[2]-p1[2])) / rayFactor;
if ( t >= 0.0 && t <= 1.0 )
{
for (i=0; i<3; i++)
{
projXYZ[i] = p1[i] + t*ray[i];
if ( fabs(X[i]-projXYZ[i]) > tol )
{
break;
}
}
if ( i > 2 ) // within tolerance
{
return 1;
}
}
return 0;
}
//----------------------------------------------------------------------------
void vtkResliceCursorPicker::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "PickedAxis1: " << this->PickedAxis1 << endl;
os << indent << "PickedAxis2: " << this->PickedAxis2 << endl;
os << indent << "PickedCenter: " << this->PickedCenter << endl;
os << indent << "ResliceCursorAlgorithm: " <<
this->ResliceCursorAlgorithm << "\n";
if (this->ResliceCursorAlgorithm)
{
this->ResliceCursorAlgorithm->PrintSelf(os, indent);
}
os << indent << "TransformMatrix: " << this->TransformMatrix << "\n";
if (this->TransformMatrix)
{
this->TransformMatrix->PrintSelf(os, indent);
}
// this->PointIds;
// this->Plane;
// this->Cell;
}