Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
1680 lines (1440 sloc) 60.1 KB
/*=========================================================================
Program: Visualization Toolkit
Module: vtkParallelopipedRepresentation.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 "vtkParallelopipedRepresentation.h"
#include "vtkSmartPointer.h"
#include "vtkActor.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkDoubleArray.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkInteractorObserver.h"
#include "vtkEvent.h"
#include "vtkSphereHandleRepresentation.h"
#include "vtkLine.h"
#include "vtkClosedSurfacePointPlacer.h"
#include "vtkPlaneCollection.h"
#include "vtkPlane.h"
#include <vtkstd/vector>
#include <vtkstd/set>
#include <vtkstd/algorithm>
#define min(x,y) ((x<y) ? (x) : (y))
#define max(x,y) ((x>y) ? (x) : (y))
//----------------------------------------------------------------------------
// This class manages topological information for a parallelopiped with a
// chair etched out at any node.
// README : Uncomment the line that reads "PrintTopology(cout) to
// understand what the class does. The goal of the class is succintly
// described in that one line.
class vtkParallelopipedTopology
{
public:
typedef struct Line { vtkIdType Id[2];
Line(vtkIdType a, vtkIdType b) { Id[0]=a; Id[1]=b; } } LineType;
typedef vtkstd::vector< vtkIdType > CellType;
typedef vtkstd::vector< CellType > CliqueType;
// Diametric opposite of Corner 0 = 6, 1 = 7, 2 = 4, 3 = 5.
// Mathematically, if a diametric corner is represented by a 3 bit value:
// abc, its diametric opposite = a'b'c.
static int GetDiametricOppositeOfCorner( int i )
{
return ((~i) & 0x6) | (i & 0x1);
}
// Get the corners connected to corner 'i'. There will be three such corners
void GetNeighbors( int c, vtkIdType neighborPtIds[3], int configuration = 0 ) const
{
vtkstd::set< vtkIdType > neighbors;
const CliqueType & clique = m_Topology[configuration];
for (CliqueType::const_iterator clit = clique.begin();
clit != clique.end(); ++clit)
{
if (vtkstd::find(clit->begin(), clit->end(), c) != clit->end())
{
const CellType cell = RotateCell( *clit, c );
neighbors.insert(cell[0]);
neighbors.insert(cell[cell.size()-2]);
}
}
int i = 0;
for (vtkstd::set< vtkIdType >::const_iterator it = neighbors.begin();
it != neighbors.end(); neighborPtIds[i++] = *it, ++it)
{
;
}
}
void GetNeighbors( vtkIdType node, vtkIdType neighborPtIds[3],
vtkCellArray *neighborCells, vtkstd::vector< LineType > & lines )
{
GetNeighbors( 8 + GetDiametricOppositeOfCorner(node), neighborPtIds, node+1 );
vtkIdType opposingNeighborPtIds[3],
opposite = GetDiametricOppositeOfCorner(node);
GetNeighbors( opposite, opposingNeighborPtIds );
vtkstd::vector< vtkIdType > nodes(2);
for (int i = 0; i < 3; i++)
{
nodes[0] = neighborPtIds[i];
for (int j = 0; j < 3; j++)
{
nodes[1] = opposingNeighborPtIds[j];
const CliqueType cells =
FindCellsContainingNodes( m_Topology[node+1], nodes );
if (cells.size())
{
PopulateTopology( cells, neighborCells );
lines.push_back( LineType(opposite, nodes[1]) );
}
}
}
}
void FindCellsContainingNodes( int configuration, vtkCellArray *cellArray,
const vtkstd::vector< vtkIdType > & nodes ) const
{
vtkParallelopipedTopology::PopulateTopology(
FindCellsContainingNodes( m_Topology[configuration], nodes), cellArray );
}
vtkstd::vector< CellType > FindCellsContainingNodes(
int configuration, const vtkstd::vector< vtkIdType > & nodes )
{ return FindCellsContainingNodes( m_Topology[configuration], nodes); }
vtkParallelopipedTopology()
{
// The topology of a parallelopiped.
CliqueType clique;
AddCellToClique(clique, 3,0,4,7);
AddCellToClique(clique, 1,2,6,5);
AddCellToClique(clique, 0,1,5,4);
AddCellToClique(clique, 2,3,7,6);
AddCellToClique(clique, 0,3,2,1);
AddCellToClique(clique, 4,5,6,7);
m_Topology.push_back(clique);
for ( vtkIdType i = 0; i < 8;
m_Topology.push_back( GetChairClique( i++, clique ) ) )
{
;
}
// README : The goal of the class is succintly described by the line below
// PrintTopology( cout );
}
// Populate topoplogy into a vtkCellArray.
// If configuration is 0, the topoology populated is that of a parallelopiped.
// If configuration > 0, the topology populated is that of a parallelopiped
// with a chair at node = (configuration - 1).
void PopulateTopology( int configuration, vtkCellArray * cellArray ) const
{ vtkParallelopipedTopology::PopulateTopology(
m_Topology[configuration], cellArray ); }
void PrintTopology(ostream &os) const
{
os << "Connectivity of Point Ids in a parallelopiped: " << endl;
PrintClique(m_Topology[0], os);
for (int i = 0; i < 8; i++)
{
os << "Connectivity of Point Ids in a parallelopiped "
<< "with chair carved out at node: " << i << endl;
PrintClique(m_Topology[i+1], os);
}
}
private:
void AddCellToClique( CliqueType & clique,
vtkIdType a, vtkIdType b, vtkIdType c, vtkIdType d)
{
CellType v(4);
v[0] = a; v[1] = b; v[2] = c; v[3] = d;
clique.push_back(v);
}
static CellType RotateCell( const CellType & cell, vtkIdType endval )
{
CellType outputCell;
for (CellType::const_iterator cit = cell.begin(); cit != cell.end(); ++cit)
{
outputCell.push_back(*cit);
if (*cit == endval) break;
}
for (CellType::const_reverse_iterator cit = cell.rbegin(); cit != cell.rend(); ++cit)
{
if (*cit == endval) break;
outputCell.insert(outputCell.begin(), *cit);
}
return outputCell;
}
static CellType ReverseCell( const CellType & cell )
{
CellType outputCell;
for (CellType::const_reverse_iterator cit = cell.rbegin(); cit != cell.rend(); ++cit)
outputCell.push_back(*cit);
return outputCell;
}
static CellType ChairCell( const CellType & cell )
{
CellType outputCell = ReverseCell(cell);
for (CellType::iterator cit = outputCell.begin(); cit != outputCell.end(); ++cit)
*cit += 8;
return outputCell;
}
static CellType ChairCell( vtkIdType c, const CellType & cell )
{
CellType tmpCell = RotateCell(cell, c);
CellType::iterator it = tmpCell.end();
tmpCell.erase(--it);
CellType outputCell = tmpCell;
for (CellType::reverse_iterator cit = tmpCell.rbegin(); cit != tmpCell.rend(); ++cit)
outputCell.push_back(*cit + 8);
return outputCell;
}
static CliqueType GetChairClique( vtkIdType c, const CliqueType & clique )
{
CliqueType outputClique;
for (CliqueType::const_iterator clit = clique.begin();
clit != clique.end(); ++clit)
{
if (vtkstd::find(clit->begin(), clit->end(), c) == clit->end())
{
outputClique.insert( outputClique.begin(), *clit );
outputClique.push_back( ChairCell(*clit) );
}
else
{
outputClique.insert( outputClique.begin(), ChairCell(c, *clit) );
}
}
return outputClique;
}
static void PopulateTopology( const CliqueType & clique, vtkCellArray * cellArray )
{
for (CliqueType::const_iterator clit = clique.begin();
clit != clique.end(); ++clit)
{
vtkIdType *ids = new vtkIdType[clit->size()];
int i = 0;
for (CellType::const_iterator cit = clit->begin();
cit != clit->end(); ids[i++] = *cit, ++cit )
{
;
}
cellArray->InsertNextCell( clit->size(), ids );
delete [] ids;
}
}
// Find all the cells in a given a configuration (specified by the clique)
// that contain the nodes. (specified by nodes). Each cell returned must
// contain all the nodes specified.
static vtkstd::vector< CellType > FindCellsContainingNodes(
const CliqueType & clique, const vtkstd::vector< vtkIdType > & nodes )
{
vtkstd::vector< CellType > cells;
for (CliqueType::const_iterator clit = clique.begin();
clit != clique.end(); ++clit)
{
bool found = true;
for (vtkstd::vector< vtkIdType >::const_iterator nit = nodes.begin();
nit != nodes.end(); ++nit)
found &= (vtkstd::find(clit->begin(), clit->end(), *nit) != clit->end());
if (found) cells.push_back(*clit);
}
return cells;
}
static void PrintCell( const CellType & cell, ostream &os )
{
for (CellType::const_iterator cit = cell.begin();
cit != cell.end(); os << *cit << " ", ++cit )
{
;
}
}
static void PrintClique( const CliqueType & clique, ostream &os )
{
os << " Clique has " << clique.size() << " cells." << endl;
for (CliqueType::const_iterator clit = clique.begin();
clit != clique.end(); ++clit)
{
os << " Cell PtIds: ";
PrintCell( *clit, os );
os << endl;
}
}
vtkstd::vector< CliqueType > m_Topology;
};
//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkParallelopipedRepresentation);
vtkCxxSetObjectMacro(vtkParallelopipedRepresentation,
HandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkParallelopipedRepresentation,
SelectedHandleProperty, vtkProperty);
vtkCxxSetObjectMacro(vtkParallelopipedRepresentation,
HoveredHandleProperty, vtkProperty);
//----------------------------------------------------------------------------
vtkParallelopipedRepresentation::vtkParallelopipedRepresentation()
{
// This contains all the connectivity information.
this->Topology = new vtkParallelopipedTopology;
this->LastEventPosition[0] = this->LastEventPosition[1] = 0.0;
// Construct the poly data representing the hex
this->HexPolyData = vtkPolyData::New();
this->HexMapper = vtkPolyDataMapper::New();
this->HexActor = vtkActor::New();
this->HexMapper->SetInput(HexPolyData);
this->HexActor->SetMapper(this->HexMapper);
// 16 points from the parallelopiped and the chair (also modelled as a
// parallelopiped).
this->Points = vtkPoints::New(VTK_DOUBLE);
this->Points->SetNumberOfPoints(16);
this->HexPolyData->SetPoints(this->Points);
vtkCellArray *cellArray = vtkCellArray::New();
this->Topology->PopulateTopology( 0, cellArray );
this->HexPolyData->SetPolys(cellArray);
this->HexPolyData->BuildCells();
cellArray->Delete();
// The face of the polyhedron
vtkIdType pts[4] = { 4, 5, 6, 7 };
vtkCellArray * cells = vtkCellArray::New();
cells->Allocate(cells->EstimateSize(1,4));
cells->InsertNextCell(4,pts); //temporary, replaced later
this->HexFacePolyData = vtkPolyData::New();
this->HexFaceMapper = vtkPolyDataMapper::New();
this->HexFaceActor = vtkActor::New();
this->HexFacePolyData->SetPoints(this->Points);
this->HexFacePolyData->SetPolys(cells);
this->HexFaceMapper->SetInput(HexFacePolyData);
this->HexFaceActor->SetMapper(this->HexFaceMapper);
cells->Delete();
// Set some default properties.
// Handle properties
this->HandleProperty = vtkProperty::New();
this->SelectedHandleProperty = vtkProperty::New();
this->HoveredHandleProperty = vtkProperty::New();
this->HandleProperty ->SetColor(1.0,1.0,0.7);
this->SelectedHandleProperty->SetColor(1.0,0.2,0.1);
this->HoveredHandleProperty ->SetColor(1.0,0.7,0.5);
// Face properties
this->FaceProperty = vtkProperty::New();
this->SelectedFaceProperty = vtkProperty::New();
this->FaceProperty ->SetColor(1,1,1);
this->SelectedFaceProperty->SetColor(0,0,1);
this->FaceProperty->SetOpacity(0.0);
this->SelectedFaceProperty->SetOpacity(0.25);
// Outline properties (for the hex and the chair)
this->OutlineProperty = vtkProperty::New();
this->OutlineProperty->SetRepresentationToWireframe();
this->OutlineProperty->SetAmbient(1.0);
this->OutlineProperty->SetAmbientColor(1.0,1.0,1.0);
this->OutlineProperty->SetLineWidth(2.0);
this->SelectedOutlineProperty = vtkProperty::New();
this->SelectedOutlineProperty->SetRepresentationToWireframe();
this->SelectedOutlineProperty->SetAmbient(1.0);
this->SelectedOutlineProperty->SetAmbientColor(0.0,0.0,1.0);
this->SelectedOutlineProperty->SetLineWidth(2.0);
this->HexActor->SetProperty(this->OutlineProperty);
this->HexFaceActor->SetProperty(this->FaceProperty);
// Handle looks like a sphere.
this->HandleRepresentation = NULL;
this->HandleRepresentations = NULL;
vtkSphereHandleRepresentation * hRep = vtkSphereHandleRepresentation::New();
this->SetHandleRepresentation(hRep);
hRep->Delete();
this->CurrentHandleIdx = -1;
this->LastResizeAxisIdx = -1;
this->ChairHandleIdx = -1;
// Point placer to dictate placement of the chair point inside the
// parallelopiped.
this->ChairPointPlacer = vtkClosedSurfacePointPlacer::New();
this->InitialChairDepth = 0.25;
this->MinimumThickness = 0.05;
this->AbsoluteMinimumThickness = 0.05;
this->PlaceFactor = 1.0;
// Define the point coordinates and initial placement of the widget
double bounds[6] = { -0.5, 0.5, -0.5, 0.5, -0.5, 0.5 };
this->PlaceWidget(bounds);
}
//----------------------------------------------------------------------------
vtkParallelopipedRepresentation::~vtkParallelopipedRepresentation()
{
this->HexActor->Delete();
this->HexMapper->Delete();
this->HexPolyData->Delete();
this->Points->Delete();
this->HexFaceActor->Delete();
this->HexFaceMapper->Delete();
this->HexFacePolyData->Delete();
this->SetHandleRepresentation(NULL);
this->FaceProperty->Delete();
this->SelectedFaceProperty->Delete();
this->OutlineProperty->Delete();
this->SelectedOutlineProperty->Delete();
this->SetHandleProperty ( NULL );
this->SetSelectedHandleProperty ( NULL );
this->SetHoveredHandleProperty ( NULL );
this->ChairPointPlacer->Delete();
delete this->Topology;
}
//----------------------------------------------------------------------------
vtkHandleRepresentation* vtkParallelopipedRepresentation
::GetHandleRepresentation( int handleIndex )
{
return (handleIndex > 7) ? NULL : this->HandleRepresentations[handleIndex];
}
//----------------------------------------------------------------------
// You can swap the handle representation to one that you like.
void vtkParallelopipedRepresentation
::SetHandleRepresentation(vtkHandleRepresentation *handle)
{
if ( handle == this->HandleRepresentation )
{
return;
}
vtkSetObjectBodyMacro( HandleRepresentation,
vtkHandleRepresentation, handle );
if (this->HandleRepresentation)
{
// Allocate the 8 handles if they haven't been allocated.
if (!this->HandleRepresentations)
{
this->HandleRepresentations = new vtkHandleRepresentation* [8];
for (int i=0; i<8; this->HandleRepresentations[i++] = NULL)
{
;
}
}
}
else
{
// Free the 8 handles if they haven't been freed.
if (this->HandleRepresentations)
{
for (int i=0; i<8; this->HandleRepresentations[i++]->Delete())
{
;
}
delete [] this->HandleRepresentations;
this->HandleRepresentations = NULL;
}
}
for (int i=0; i<8; i++)
{
// We will remove the old handle, in anticipation of the new user-
// provided handle type that we are going to set a few lines later.
if (this->HandleRepresentations && this->HandleRepresentations[i])
{
this->HandleRepresentations[i]->Delete();
this->HandleRepresentations[i] = NULL;
}
// Copy the new user-provided handle.
if (this->HandleRepresentation)
{
this->HandleRepresentations[i] = this->HandleRepresentation->NewInstance();
this->HandleRepresentations[i]->ShallowCopy(this->HandleRepresentation);
}
}
}
//----------------------------------------------------------------------
// Remove any existing chairs in the parallelopiped.
void vtkParallelopipedRepresentation::RemoveExistingChairs()
{
// If we have a chair. A chair has 9 faces as opposed to a parallelopiped
// which has 6 faces.
if (this->HexPolyData->GetPolys()->GetNumberOfCells() == 9)
{
// Go back to the topology of a parallelopiped.
vtkCellArray *parallelopipedcells = vtkCellArray::New();
this->Topology->PopulateTopology( 0, parallelopipedcells );
this->HexPolyData->SetPolys(parallelopipedcells);
this->HexPolyData->BuildCells();
parallelopipedcells->Delete();
// Bring the node that had the chair back to the 4th corner of the
// parallelopiped. We will use vector addition by finding the 4th point of
// a parallelogram from the other 3 points.
vtkIdType neighborPtIds[3], npts = 0, *cellPtIds = NULL;
this->Topology->GetNeighbors( this->ChairHandleIdx, neighborPtIds );
// First find 4 points that form a parallelogram and contain the chaired
// handle. The pointIds shall be stored in "nodes"
vtkParallelopipedTopology::CellType nodes(3);
nodes[0] = this->ChairHandleIdx;
nodes[1] = neighborPtIds[0];
nodes[2] = neighborPtIds[1];
vtkSmartPointer< vtkCellArray > cells = vtkSmartPointer<vtkCellArray>::New();
this->Topology->FindCellsContainingNodes( 0, cells, nodes );
cells->InitTraversal();
cells->GetNextCell(npts, cellPtIds);
// Find the 4th pointId.
int j = 0;
while (cellPtIds[j] == nodes[0]
|| cellPtIds[j] == nodes[1]
|| cellPtIds[j] == nodes[2]) ++j;
nodes.push_back(cellPtIds[j]);
// Now go about finding the 4th point (Index 0) in the parallelogram..
// 0 ------ 1
// | |
// 2 ------ 3
//
double p[4][3]; // for 4 points.. 3 we know, 4th to find..
this->Points->GetPoint( nodes[3], p[0] );
this->Points->GetPoint( nodes[1], p[1] );
this->Points->GetPoint( nodes[2], p[2] );
p[3][0] = p[1][0] + p[2][0] - p[0][0];
p[3][1] = p[1][1] + p[2][1] - p[0][1];
p[3][2] = p[1][2] + p[2][2] - p[0][2];
this->Points->SetPoint( nodes[0], p[3] );
this->ChairHandleIdx = -1;
}
}
//----------------------------------------------------------------------
// Node can be an integer within [0,7]. This will create a chair one one of
// the handle corners. The '0 < scale < 1' value dicates the starting
// depth of the cavity.
void vtkParallelopipedRepresentation::UpdateChairAtNode( int node )
{
vtkIdType npts = 0, *cellPtIds = NULL;
// If we have a chair somewhere else, remove it. We can have only one
// chair at a time.
if (this->CurrentHandleIdx != this->ChairHandleIdx &&
this->HexPolyData->GetPolys()->GetNumberOfCells() == 9)
{
this->RemoveExistingChairs();
}
this->ChairHandleIdx = node;
// If we already don't have a chair, create one. (a chair has 6 faces,
// unlike a parallelopiped).
if (this->HexPolyData->GetPolys()->GetNumberOfCells() != 9)
{
// chair has 14 points, but we will model this with 2 parallelopipeds.
// Hence 16 points. Look at vtkParallelopipedTopology for details.
// Scale points with respect to the node.
double origin[3], d[3];
this->Points->GetPoint( node, origin );
for (int i = 0; i < 8 ; i++)
{
this->Points->GetPoint(i, d);
d[0] = (d[0] - origin[0]) * this->InitialChairDepth + origin[0];
d[1] = (d[1] - origin[1]) * this->InitialChairDepth + origin[1];
d[2] = (d[2] - origin[2]) * this->InitialChairDepth + origin[2];
this->Points->SetPoint(i+8, d);
}
this->Points->SetPoint( node, this->Points->GetPoint(
vtkParallelopipedTopology::GetDiametricOppositeOfCorner(node) + 8));
vtkSmartPointer< vtkCellArray > cells = vtkSmartPointer<vtkCellArray>::New();
this->Topology->PopulateTopology( node + 1, cells );
this->HexPolyData->SetPolys(cells);
this->HexPolyData->BuildCells();
// Synchronize the handle representations with our recently updated
// "Points" data-structure.
this->PositionHandles();
}
else
{
// We do have a chair. Update the points in the chair by taking the
// projection of the chaired node onto the axes of the parallelopiped.
// These three PtIds are those that lie on the chair and are connected via
// a line to the "Chair node" in question. It is the position of these 3
// points that we seek to find in the next few lines.
vtkIdType neighborPtIds[3];
// This will contain the 3 faces that lie on the parallelopiped and have
// a chair carved out in them. As you know, we are about to compute the
// points at the carved out locations.
vtkSmartPointer< vtkCellArray > neighborCells = vtkSmartPointer<vtkCellArray>::New();
// Handle PointID is the diametric opposite of the chair corner on the
// higher order parallelopiped (the chair parallelopiped).
const vtkIdType chairHandleId = 8 + vtkParallelopipedTopology::
GetDiametricOppositeOfCorner(this->CurrentHandleIdx);
// Get the world position of the chair handle.
double chairPoint[3];
this->Points->GetPoint( chairHandleId, chairPoint );
vtkstd::vector< vtkParallelopipedTopology::LineType > lines;
this->Topology->GetNeighbors( node, neighborPtIds, neighborCells, lines );
neighborCells->InitTraversal();
for (int i = 0; i < 3; i++)
{
double lineEndPt[2][3];
this->Points->GetPoint( lines[i].Id[0], lineEndPt[0] );
this->Points->GetPoint( lines[i].Id[1], lineEndPt[1] );
double t, neighborPt[3]; // "x" is the point that we are trying to find.
neighborCells->GetNextCell(npts, cellPtIds);
vtkIdType planePtIds[3];
// For each point in the cell
for (int j = 0, idx = 0; j < npts && idx < 3; j++)
{
// Avoid the points that are on the chair as these are the ones we seek
// to find.
if ( cellPtIds[j] < 8 )
{
planePtIds[idx++] = cellPtIds[j];
}
}
// Construct a plane from the cell.
vtkPlane *plane = vtkPlane::New();
this->DefinePlane(plane, planePtIds[0], planePtIds[1], planePtIds[2]);
double endPoint[3] = { chairPoint[0] + lineEndPt[1][0] - lineEndPt[0][0],
chairPoint[1] + lineEndPt[1][1] - lineEndPt[0][1],
chairPoint[2] + lineEndPt[1][2] - lineEndPt[0][2] };
vtkPlane::IntersectWithLine( chairPoint, endPoint,
plane->GetNormal(), plane->GetOrigin(), t, neighborPt );
plane->Delete();
vtkDebugMacro( << "ChairPoint: (" << chairPoint[0] << "," << chairPoint[1]
<< "," << chairPoint[2] << ") lineEndPts [" << lines[i].Id[0] << "("
<< lineEndPt[0][0] << "," << lineEndPt[0][1] << "," << lineEndPt[0][2]
<< ")-" << lines[i].Id[1] << "(" << lineEndPt[1][0] << ","
<< lineEndPt[1][1] << "," << lineEndPt[1][2] << ")]"
<< " Intersection at: (" << neighborPt[0] << "," << neighborPt[1]
<< "," << neighborPt[2] << ")" );
this->Points->SetPoint( neighborPtIds[i], neighborPt );
}
// Now that we have found the 3 neighbors, we need to compute the other
// points in the chair. Note that we have 4 so far (3 neighbors + the
// chair node). There are 2 more to be found. Given that they will
// have to satisfy a parallelogram relationship, we can easily use
// vector addition to evaluate them.
for (int i = 0; i < 3; i++)
{
vtkstd::vector< vtkIdType > nodes(3);
vtkSmartPointer< vtkCellArray > cells
= vtkSmartPointer<vtkCellArray>::New();
nodes[0] = 8 + vtkParallelopipedTopology::
GetDiametricOppositeOfCorner(this->CurrentHandleIdx);
nodes[1] = neighborPtIds[i];
nodes[2] = neighborPtIds[(i+1)%3];
vtkDebugMacro( << "Looking for cells containing nodes: " << nodes[0]
<< "," << nodes[1] << "," << nodes[2] << " in topology "
<< (this->CurrentHandleIdx+1) );
this->Topology->FindCellsContainingNodes(
this->CurrentHandleIdx + 1, cells, nodes );
npts = 0; cellPtIds = NULL;
cells->InitTraversal();
cells->GetNextCell(npts, cellPtIds);
// Find the 4th pointId. The pointIds shall be stored in "nodes"
int j = 0;
while (cellPtIds[j] == nodes[0]
|| cellPtIds[j] == nodes[1]
|| cellPtIds[j] == nodes[2]) ++j;
nodes.push_back(cellPtIds[j]);
// Now go about finding the 4th point (Index 3) in the parallelogram..
// 0 ------ 1
// | |
// 2 ------ 3
//
double p[4][3]; // for 4 points.. 3 we know, 4th to find..
this->Points->GetPoint( nodes[0], p[0] );
this->Points->GetPoint( nodes[1], p[1] );
this->Points->GetPoint( nodes[2], p[2] );
p[3][0] = p[1][0] + p[2][0] - p[0][0];
p[3][1] = p[1][1] + p[2][1] - p[0][1];
p[3][2] = p[1][2] + p[2][2] - p[0][2];
vtkDebugMacro( << "Parallelogram built from (nodes and points): \n"
<< "(" << nodes[0] << ") = [" << p[0][0] << "," << p[0][1] << "," << p[0][2] << "]\n"
<< "(" << nodes[1] << ") = [" << p[1][0] << "," << p[1][1] << "," << p[1][2] << "]\n"
<< "(" << nodes[2] << ") = [" << p[2][0] << "," << p[2][1] << "," << p[2][2] << "]\n"
<< "(" << cellPtIds[j] << ") = [" << p[3][0] << "," << p[3][1] << "," << p[3][2] << "]\n");
this->Points->SetPoint( nodes[3], p[3] );
}
this->Points->SetPoint( 8 + vtkParallelopipedTopology::
GetDiametricOppositeOfCorner(this->CurrentHandleIdx),
this->Points->GetPoint(this->CurrentHandleIdx));
}
}
//----------------------------------------------------------------------
// This is where the bulk of the work is done.
int vtkParallelopipedRepresentation
::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify))
{
int oldInteractionState = this->InteractionState;
// (A) -----------------------------------------------------------
// Handle the request methods. These are mere requests and will not cause
// any change in the position of the handles or the shape of the
// parallelopiped. The representation will, within this IF block change its
// state from a request to a concrete state.
if ( this->InteractionState == vtkParallelopipedRepresentation::RequestResizeParallelopiped
|| this->InteractionState == vtkParallelopipedRepresentation::RequestResizeParallelopipedAlongAnAxis
|| this->InteractionState == vtkParallelopipedRepresentation::RequestChairMode )
{
this->CurrentHandleIdx = -1;
// We are trying to perform user interaction that might potentially
// select a handle. Check if we are really near a handle, so it
// can be selected.
// Loop over all the handles and check if one of them is selected
for(int i = 0; i< 8; i++)
{
this->HandleRepresentations[i]->ComputeInteractionState(X, Y, 0);
if (this->HandleRepresentations[i]->GetInteractionState() ==
vtkHandleRepresentation::Selecting)
{
// The selected handle.
this->CurrentHandleIdx = i;
// The shift modifier determines if the handles are going to be
// translated along an axes of the parallelopiped.
switch (this->InteractionState)
{
case vtkParallelopipedRepresentation::RequestResizeParallelopiped:
this->InteractionState = (this->CurrentHandleIdx == this->ChairHandleIdx)
? ChairMode : ResizingParallelopiped;
break;
case vtkParallelopipedRepresentation::RequestResizeParallelopipedAlongAnAxis:
this->InteractionState = (this->CurrentHandleIdx == this->ChairHandleIdx)
? ChairMode : ResizingParallelopipedAlongAnAxis;
break;
case vtkParallelopipedRepresentation::RequestChairMode:
{
// Toggle chair mode if we already have a chair here.. We are
// trying to toggle of course.. In this case remove all chairs,
if (this->CurrentHandleIdx == this->ChairHandleIdx &&
this->HexPolyData->GetPolys()->GetNumberOfCells() == 9)
{
this->RemoveExistingChairs();
this->LastEventPosition[0] = X;
this->LastEventPosition[1] = Y;
this->InteractionState = vtkParallelopipedRepresentation::Inside;
// Synchronize the handle representations with our recently updated
// "Points" data-structure.
this->PositionHandles();
return this->InteractionState;
}
// We aren't trying to toggle. Create one
// Create a chair with a default cavity depth of 0.1
this->UpdateChairAtNode( this->CurrentHandleIdx );
// We are in chair mode. Use the placer to dictate where the
// "chaired" handle can move. (It can only move within the
// parallelopiped). First set some parameters on the placer.
vtkPlaneCollection *pc = vtkPlaneCollection::New();
this->GetParallelopipedBoundingPlanes( pc );
this->ChairPointPlacer->SetBoundingPlanes( pc );
pc->Delete();
this->InteractionState = ChairMode;
break;
}
}
// Highlight the selected handle and unhighlight all others.
this->SetHandleHighlight(-1, this->HandleProperty);
this->SetHandleHighlight(
this->CurrentHandleIdx, this->SelectedHandleProperty);
break;
}
}
if (this->CurrentHandleIdx == -1)
{
// We are near none of the handles.
// Now check if we are within the parallelopiped or outside the
// parallelopiped. We will use the pointplacer to evaluate this.
vtkPlaneCollection *pc = vtkPlaneCollection::New();
this->GetParallelopipedBoundingPlanes( pc );
this->ChairPointPlacer->SetBoundingPlanes( pc );
pc->Delete();
// Use any random handle as a reference for the point placer.
double eventDisplayPos[3] = {X, Y,0.0}, dummy[4],
worldOrient[9], handleWorldPos[4];
this->HandleRepresentations[0]->GetWorldPosition(handleWorldPos);
this->InteractionState = (this->ChairPointPlacer->ComputeWorldPosition(
this->Renderer, eventDisplayPos, handleWorldPos, dummy, worldOrient )
? vtkParallelopipedRepresentation::Inside
: vtkParallelopipedRepresentation::Outside);
}
if (this->InteractionState == vtkParallelopipedRepresentation::Inside &&
oldInteractionState == vtkParallelopipedRepresentation::
RequestResizeParallelopipedAlongAnAxis)
{
this->HighlightAllFaces();
}
else
{
// UnHighlight all faces
this->UnHighlightAllFaces();
}
// Reset any cached "resize along that axis" stuff.
this->LastResizeAxisIdx = -1;
}
// (B) -----------------------------------------------------------
// Handle the resizing operations (along the axis or arbitrarily).
else if (this->InteractionState ==
vtkParallelopipedRepresentation::ResizingParallelopipedAlongAnAxis ||
this->InteractionState ==
vtkParallelopipedRepresentation::ResizingParallelopiped)
{
// Ensure that a handle has been picked.
if (this->CurrentHandleIdx != -1)
{
// Compute world positions corresponding to the current event position
// (X,Y) and the last event positions such that they lie at the same
// depth that the handle lies on.
double axis[3][3], eventWorldPos[4], handleWorldPos[4],
handleDisplayPos[4], neighborWorldPos[3][4], neighborDisplayPos[3][4];
this->HandleRepresentations[this->CurrentHandleIdx]
->GetWorldPosition(handleWorldPos);
vtkInteractorObserver::ComputeWorldToDisplay( this->Renderer,
handleWorldPos[0], handleWorldPos[1], handleWorldPos[2],
handleDisplayPos);
// Now find and get the display positions of the three neighbors of the
// current handle. We have to rescale along one of the three edges.
vtkIdType neighborIndices[3];
this->Topology->GetNeighbors( this->CurrentHandleIdx, neighborIndices,
(this->ChairHandleIdx == -1) ? 0 : this->ChairHandleIdx + 1 );
// The motion vector in display coords
const double motionVector[3] = { X - this->LastEventPosition[0],
Y - this->LastEventPosition[1],
0.0 };
double maxConfidence = VTK_DOUBLE_MIN;
// The next few lines attempt to find the axis should we scale along.
// The axis is the axis of the parallelopiped that is most aligned with
// the direction of mouse motion.
int axisIdx = this->LastResizeAxisIdx; // To be found out ..
// loop over the 3 neighbors of the current handle
for (int i = 0; i < 3; i++)
{
// Compute display position of this neighbor
this->Points->GetPoint(neighborIndices[i], neighborWorldPos[i]);
vtkInteractorObserver::ComputeWorldToDisplay( this->Renderer,
neighborWorldPos[i][0], neighborWorldPos[i][1],
neighborWorldPos[i][2], neighborDisplayPos[i]);
// Dot product of the motion vector (in display coords) with each
// of the three edges (in display coords). The maximum of the three
// will determine which axis of the parallelopiped we will rescale along
axis[i][0] = neighborDisplayPos[i][0] - handleDisplayPos[0];
axis[i][1] = neighborDisplayPos[i][1] - handleDisplayPos[1],
axis[i][2] = 0.0;
vtkMath::Normalize2D(axis[i]);
// If we did not compute the resize axis Idx already the last time,
// we were in this method, compute it now, by checking which axis
// the motion vector is most aligned with.
if (this->LastResizeAxisIdx == -1 ||
this->InteractionState ==
vtkParallelopipedRepresentation::ResizingParallelopiped)
{
const double confidence
= fabs(vtkMath::Dot2D( axis[i], motionVector ));
if (confidence > maxConfidence)
{
axisIdx = i;
maxConfidence = confidence;
}
}
}
// Now that we know the axis to translate along, find the amount we should
// translate by. The new handle position must lie somewhere along the
// line joining the currently selected handle and the neighbor that lies
// along the rescale axis. We will evaluate 't E [-inf, 1.0]', the
// parametric position along the line. This point will simply be the
// point on the aforementioned line that the current event position is
// closest to.
double directionOfProjection[3], closestPt1[3], closestPt2[3], t1, t;
this->Renderer->GetActiveCamera()->
GetDirectionOfProjection(directionOfProjection);
vtkInteractorObserver::ComputeDisplayToWorld( this->Renderer,
X, Y, handleDisplayPos[2], eventWorldPos);
double l0[3] = {eventWorldPos[0] - directionOfProjection[0],
eventWorldPos[1] - directionOfProjection[1],
eventWorldPos[2] - directionOfProjection[2] };
double l1[3] = {eventWorldPos[0] + directionOfProjection[0],
eventWorldPos[1] + directionOfProjection[1],
eventWorldPos[2] + directionOfProjection[2] };
vtkLine::DistanceBetweenLines( handleWorldPos, neighborWorldPos[axisIdx],
l0, l1,
closestPt1, closestPt2,
t, t1 );
t = (t > 1.0 ? 1.0 : t); // clamp 't'
vtkDebugMacro( << "Currently selected handle is at : (" <<
handleWorldPos[0] << "," << handleWorldPos[1] << "," << handleWorldPos[2] <<
")\n Pt2 (the selected handle will be moved along the axis represented by"
<< " itself and Pt2) is at: (" << neighborWorldPos[axisIdx][0]
<< "," << neighborWorldPos[axisIdx][1] << "," << neighborWorldPos[axisIdx][2]
<< ")\n The selected handle will be moved to parametric location t = " << t
<< "with the line being specified by the above 2 points.");
// This is the amount by which the face will move towards
// (or away from if t < 0.0) the other face. We know that the face has
// the following PointIds.
// 1) CurrentHandleIdx
// 2) Neighbor 1 of currentHandleIdx
// 3) Neighbor 2 of CurrentHandleIdx
// It will be our job in the next few lines to find the other points in
// the face and translate the face.
// "nodes" contains the 3 pointIds that we know are present on the face.
vtkstd::vector< vtkIdType > nodes(3);
nodes[0] = this->CurrentHandleIdx;
for (int i = 0, j = 1; i < 3; i++)
{
if (i != axisIdx)
{
nodes[j++] = neighborIndices[i];
}
}
// "cells" below contains the face to be translated.
vtkSmartPointer< vtkCellArray > cells = vtkSmartPointer<vtkCellArray>::New();
this->Topology->FindCellsContainingNodes(
(this->ChairHandleIdx == -1) ? 0 :
this->ChairHandleIdx + 1, cells, nodes );
vtkIdType npts = 0, *cellPtIds = NULL;
cells->InitTraversal();
cells->GetNextCell(npts, cellPtIds);
// The translation vector
double handleTranslation[3] =
{ t * neighborWorldPos[axisIdx][0] - t * handleWorldPos[0],
t * neighborWorldPos[axisIdx][1] - t * handleWorldPos[1],
t * neighborWorldPos[axisIdx][2] - t * handleWorldPos[2] };
double newHandleWorldPos[3] = { handleWorldPos[0] + handleTranslation[0],
handleWorldPos[1] + handleTranslation[1],
handleWorldPos[2] + handleTranslation[2]};
if ( t > 0.0 // We are moving towards the other handle
&& (vtkMath::Distance2BetweenPoints(
neighborWorldPos[axisIdx], newHandleWorldPos)) < (
this->AbsoluteMinimumThickness * this->AbsoluteMinimumThickness))
{
// Too close. We don't want the parallelopiped collapsing, do we ?
vtkDebugMacro( << "AbsoluteMaximumThickness = "
<< this->AbsoluteMinimumThickness << " This move will bring us "
<< sqrt(vtkMath::Distance2BetweenPoints(
neighborWorldPos[axisIdx], newHandleWorldPos)) << " far away to ("
<< newHandleWorldPos[0] << "," << newHandleWorldPos[1] << ","
<< newHandleWorldPos[2] << "). We can\'t do that." );
// Revise 't' so as to maintain minimum thickness. The bottom line is
// that although 't E [-inf, 1.0]', 't' will never hit 1.0 unless
// AbsoluteMinimumThickness is 0.0.
t = 1.0 - this->AbsoluteMinimumThickness / sqrt(
vtkMath::Distance2BetweenPoints(
neighborWorldPos[axisIdx], handleWorldPos));
// Recompute these 2 positions with our revised 't' value.
handleTranslation[0] = t * neighborWorldPos[axisIdx][0] - t * handleWorldPos[0];
handleTranslation[1] = t * neighborWorldPos[axisIdx][1] - t * handleWorldPos[1];
handleTranslation[2] = t * neighborWorldPos[axisIdx][2] - t * handleWorldPos[2];
newHandleWorldPos[0] = handleWorldPos[0] + handleTranslation[0];
newHandleWorldPos[1] = handleWorldPos[1] + handleTranslation[1];
newHandleWorldPos[2] = handleWorldPos[2] + handleTranslation[2];
if (t < 0.0)
{
// Sanity check. We should never get here in the first place.
this->LastEventPosition[0] = X;
this->LastEventPosition[1] = Y;
return this->InteractionState;
}
vtkDebugMacro( "So we are revising the value of t to " << t
<< " and newHandleWorldPos to (" << newHandleWorldPos[0] << ","
<< newHandleWorldPos[1] << "," << newHandleWorldPos[2] << ")" );
}
// If we have a chair, prevent the handle from being translated beyond
// the plane of the chair, otherwise it will cause the chair to turn
// inside out. So we will do some dot-product stuff and revise the
// "neighborWorldPos", if we have a chair.
if (this->ChairHandleIdx != -1)
{
vtkstd::vector< vtkIdType > nodes2(1);
nodes2[0] = vtkParallelopipedTopology::GetDiametricOppositeOfCorner(this->ChairHandleIdx)+8;
const vtkParallelopipedTopology::CliqueType cells2 = this->
Topology->FindCellsContainingNodes( this->ChairHandleIdx+1, nodes2 );
for (vtkParallelopipedTopology::CliqueType::const_iterator clit = cells2.begin();
clit != cells2.end(); ++clit)
{
vtkSmartPointer< vtkPlane > plane = vtkSmartPointer< vtkPlane >::New();
this->DefinePlane(plane, (*clit)[0], (*clit)[1], (*clit)[2] );
double distance = plane->EvaluateFunction(newHandleWorldPos);
// Ensure that the handle is on the right side of the chair's plane,
// and that it is at least 'MinimumThickness' away from any of the
// planes of the chair.
if (fabs(distance) < this->MinimumThickness ||
(distance * (vtkstd::find(clit->begin(), clit->end(),
this->CurrentHandleIdx+8) != clit->end() ? -1 : 1) > 0))
{
this->LastEventPosition[0] = X;
this->LastEventPosition[1] = Y;
return this->InteractionState;
}
}
}
// Highlight this face...
this->SetFaceHighlight( cells, this->SelectedFaceProperty );
// Translate this face...
for (vtkIdType i = 0; i < npts;
this->TranslatePoint( cellPtIds[i++], handleTranslation ))
{
;
}
// Cache the axis along which we resized the previous time, so we don't
// have to recompute it.
this->LastResizeAxisIdx = axisIdx;
// Update the bounding planes.
vtkPlaneCollection *pc = vtkPlaneCollection::New();
this->GetParallelopipedBoundingPlanes( pc );
this->ChairPointPlacer->SetBoundingPlanes( pc );
pc->Delete();
}
else
{
// In theory, we should never get there.
this->InteractionState = vtkParallelopipedRepresentation::Outside;
}
}
// (C) -----------------------------------------------------------
// Default method for all other states.
else if (this->InteractionState == vtkParallelopipedRepresentation::ChairMode)
{
// Ensure that a handle has been picked.
if (this->CurrentHandleIdx != -1)
{
double handleWorldPos[4];
this->HandleRepresentations[this->CurrentHandleIdx]
->GetWorldPosition(handleWorldPos);
// The new handle poistion, will lie on a plane that passes through the
// current world position and is parallel to the focal plane.
// To compute this, we will use the help of the focal plane point placer,
// and supply it with the offset of the handle's distance from the
// focal plane.
double eventDisplayPos[3] = {X, Y,0.0}, newHandlePos[4], worldOrient[9];
if (this->ChairPointPlacer->ComputeWorldPosition(
this->Renderer, eventDisplayPos, handleWorldPos,
newHandlePos, worldOrient ))
{
const double handleTranslation[3] =
{ newHandlePos[0] - handleWorldPos[0],
newHandlePos[1] - handleWorldPos[1],
newHandlePos[2] - handleWorldPos[2] };
this->TranslatePoint( this->CurrentHandleIdx, handleTranslation);
}
this->UpdateChairAtNode( this->CurrentHandleIdx );
}
else
{
// In theory, we should never get there.
this->InteractionState = vtkParallelopipedRepresentation::Outside;
}
}
// (D) -----------------------------------------------------------
// Default method for all other states.
else
{
this->InteractionState = vtkParallelopipedRepresentation::Outside;
// Loop over all the handles and check if we are near one of them.
for(int i = 0; i< 8; i++)
{
this->HandleRepresentations[i]->ComputeInteractionState(X, Y, 0);
if (this->HandleRepresentations[i]->GetInteractionState() ==
vtkHandleRepresentation::Selecting)
{
this->SetHandleHighlight( i, this->HoveredHandleProperty );
this->InteractionState = vtkParallelopipedRepresentation::Inside;
break;
}
}
if (this->InteractionState == vtkParallelopipedRepresentation::Outside)
{
// Unhighlight all handles and faces.
this->SetHandleHighlight( -1, this->HandleProperty );
this->UnHighlightAllFaces();
}
}
// Cache the last event position.
this->LastEventPosition[0] = X;
this->LastEventPosition[1] = Y;
return this->InteractionState;
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation
::TranslatePoint( int id, const double translation[3] )
{
double p[3];
this->Points->GetPoint(id, p);
p[0] += translation[0];
p[1] += translation[1];
p[2] += translation[2];
this->Points->SetPoint(id, p);
if (id < 8)
{
this->HandleRepresentations[id]->SetWorldPosition(p);
}
// Update our records.
this->PositionHandles();
}
//----------------------------------------------------------------------------
// Get the bounding planes of the object. The first 6 planes will
// be bounding planes of the parallelopiped. If in chair mode, three
// additional planes will be present. The last three planes will be those
// of the chair. The Normals of all the planes will point into the object.
//
void vtkParallelopipedRepresentation::GetBoundingPlanes( vtkPlaneCollection *pc )
{
vtkSmartPointer< vtkCellArray > cellArray = vtkSmartPointer<vtkCellArray>::New();
this->Topology->PopulateTopology( this->ChairHandleIdx + 1, cellArray );
vtkIdType npts = 0, *ptIds = NULL;
// For each planar cell in our object, we need to find the plane it lies on
for (cellArray->InitTraversal(); cellArray->GetNextCell(npts, ptIds); )
{
vtkIdType planePtIds[3];
// For each cell, get the point ids that comprise the planar cell.
for (int i = 0, idx = 0; i < npts && idx < 3; i++)
{
if (this->CurrentHandleIdx != ptIds[i])
{
planePtIds[idx++] = ptIds[i];
}
}
// Construct a plane from the cell.
vtkPlane *plane = vtkPlane::New();
this->DefinePlane(plane, planePtIds[0], planePtIds[1], planePtIds[2]);
pc->AddItem(plane);
plane->Delete();
}
}
//----------------------------------------------------------------------------
// Convenience method to get just the planes that define the parallelopiped.
// If we aren't in chair mode, this will be the same as GetBoundingPlanes().
// If we are in chair mode, this will be the first 6 planes from amongst
// those returned by "GetBoundingPlanes".
// All planes have their normals pointing inwards.
//
void vtkParallelopipedRepresentation
::GetParallelopipedBoundingPlanes( vtkPlaneCollection * pc )
{
vtkPlaneCollection * pc2 = vtkPlaneCollection::New();
this->GetBoundingPlanes( pc2 );
vtkPlane *p;
int i = 0;
for (pc2->InitTraversal(); ((p = pc2->GetNextItem()) && i < 6); ++i )
{
pc->AddItem(p);
}
pc2->Delete();
}
//----------------------------------------------------------------------------
// Convenience method to populate a plane from 3 pointIds
void vtkParallelopipedRepresentation::DefinePlane( vtkPlane *plane,
vtkIdType id1, vtkIdType id2, vtkIdType id3)
{
double p[3][3];
this->Points->GetPoint(id1, p[0]);
this->Points->GetPoint(id2, p[1]);
this->Points->GetPoint(id3, p[2]);
this->DefinePlane(plane, p);
}
//----------------------------------------------------------------------------
// Convenience method to populate a plane from 3 points.
void vtkParallelopipedRepresentation::DefinePlane( vtkPlane *plane, double p[3][3])
{
plane->SetOrigin( p[0] );
double v1[3] = { p[1][0] - p[0][0], p[1][1] - p[0][1], p[1][2] - p[0][2] };
double v2[3] = { p[2][0] - p[0][0], p[2][1] - p[0][1], p[2][2] - p[0][2] };
double normal[3];
vtkMath::Cross( v1, v2, normal );
vtkMath::Normalize(normal);
plane->SetNormal( normal );
}
//----------------------------------------------------------------------
void vtkParallelopipedRepresentation::GetActors(vtkPropCollection *pc)
{
for (int i=0; i<8; i++)
{
this->HandleRepresentations[i]->GetActors(pc);
}
this->HexActor->GetActors(pc);
this->HexFaceActor->GetActors(pc);
}
//----------------------------------------------------------------------
void vtkParallelopipedRepresentation::ReleaseGraphicsResources(vtkWindow *w)
{
this->HexActor->ReleaseGraphicsResources(w);
this->HexFaceActor->ReleaseGraphicsResources(w);
for (int i=0; i<8; i++)
{
this->HandleRepresentations[i]->ReleaseGraphicsResources(w);
}
}
//----------------------------------------------------------------------
int vtkParallelopipedRepresentation::RenderOverlay(vtkViewport *v)
{
int count = 0;
count+=this->HexActor->RenderOverlay(v);
count+=this->HexFaceActor->RenderOverlay(v);
for (int i=0; i<8; i++)
{
count+=this->HandleRepresentations[i]->RenderOverlay(v);
}
return count;
}
//----------------------------------------------------------------------------
int vtkParallelopipedRepresentation::RenderOpaqueGeometry(vtkViewport *viewport)
{
int count = 0;
this->BuildRepresentation();
count+=this->HexActor->RenderOpaqueGeometry(viewport);
count+=this->HexFaceActor->RenderOpaqueGeometry(viewport);
for (int i=0; i<8; i++)
{
count += this->HandleRepresentations[i]->RenderOpaqueGeometry(viewport);
}
return count;
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::PositionHandles()
{
for (int i = 0; i < 8; ++i)
{
this->HandleRepresentations[i]->SetWorldPosition(this->Points->GetPoint(i));
}
this->Points->GetData()->Modified();
this->HexFacePolyData->Modified();
this->HexPolyData->Modified();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::HandlesOn()
{
for (int i=0; i<8; this->HandleRepresentations[i++]->SetVisibility(1))
{
;
}
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::HandlesOff()
{
for (int i=0; i<8; this->HandleRepresentations[i++]->SetVisibility(0))
{
;
}
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::SetHandleHighlight(
int handleIdx, vtkProperty *property )
{
if ( handleIdx == -1)
{
// Do for all handles
for (int i = 0; i < 8; i++)
{
static_cast< vtkSphereHandleRepresentation * >(
this->HandleRepresentations[i])->SetProperty(property);
static_cast< vtkSphereHandleRepresentation * >(
this->HandleRepresentations[i])->SetSelectedProperty(property);
}
}
else
{
static_cast< vtkSphereHandleRepresentation * >(
this->HandleRepresentations[handleIdx])->SetProperty(property);
static_cast< vtkSphereHandleRepresentation * >(
this->HandleRepresentations[handleIdx])->SetSelectedProperty(property);
}
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation
::SetFaceHighlight( vtkCellArray * face, vtkProperty *p )
{
if (face)
{
this->HexFacePolyData->SetPolys(face);
}
this->HexFaceActor->SetProperty( p );
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::HighlightAllFaces()
{
vtkSmartPointer< vtkCellArray > cells = vtkSmartPointer<vtkCellArray>::New();
this->Topology->PopulateTopology( this->ChairHandleIdx + 1, cells );
this->SetFaceHighlight( cells, this->SelectedFaceProperty );
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::UnHighlightAllFaces()
{
this->SetFaceHighlight( NULL, this->FaceProperty );
}
//----------------------------------------------------------------------------
// Translate by a vector to be computed from the last Pick position and the
// supplied event position
void vtkParallelopipedRepresentation::Translate( int X, int Y )
{
double eventPos[2] = { X, Y };
double lastEventPos[2] =
{ this->LastEventPosition[0], this->LastEventPosition[1] };
// First compute the centroid. Its only use is to determine a reference
// plane, on which we will assume lastEventPos and eventPos lie.
double *pts =
static_cast<vtkDoubleArray *>(this->Points->GetData())->GetPointer(0);
double center[3] = {0.0, 0.0, 0.0};
for (int i=0; i<8; i++)
{
center[0] += *pts++;
center[1] += *pts++;
center[2] += *pts++;
}
center[0] /= 8.0;
center[1] /= 8.0;
center[2] /= 8.0;
// Now convert the event positions to world positions as if they lay at the
// same plane as the center.
double fp[4], lastEventWorldPos[4], eventWorldPos[4];
vtkInteractorObserver::ComputeWorldToDisplay( this->Renderer,
center[0], center[1], center[2], fp );
vtkInteractorObserver::ComputeDisplayToWorld( this->Renderer,
lastEventPos[0], lastEventPos[1], fp[2], lastEventWorldPos);
vtkInteractorObserver::ComputeDisplayToWorld( this->Renderer,
eventPos[0], eventPos[1], fp[2], eventWorldPos);
// Compute the offset from the last event position and translate.
double translation[3] = { eventWorldPos[0] - lastEventWorldPos[0],
eventWorldPos[1] - lastEventWorldPos[1],
eventWorldPos[2] - lastEventWorldPos[2] };
this->Translate( translation );
// Update our records
this->LastEventPosition[0] = X;
this->LastEventPosition[1] = Y;
}
//----------------------------------------------------------------------------
// Loop through all points and translate them
void vtkParallelopipedRepresentation::Translate(double translation[3])
{
double *pts =
static_cast<vtkDoubleArray *>(this->Points->GetData())->GetPointer(0);
for (int i=0; i<16; i++)
{
*pts++ += translation[0];
*pts++ += translation[1];
*pts++ += translation[2];
}
// Synchronize the handle representations with our recently updated
// "Points" data-structure.
this->PositionHandles();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::Scale( int vtkNotUsed(X), int Y )
{
double *pts =
static_cast<vtkDoubleArray *>(this->Points->GetData())->GetPointer(0);
double *center
= static_cast<vtkDoubleArray *>(this->Points->GetData())->GetPointer(3*14);
double sf = ( Y > this->LastEventPosition[1] ? 1.03 : 0.97 );
for (int i=0; i<16; i++, pts+=3)
{
pts[0] = sf * (pts[0] - center[0]) + center[0];
pts[1] = sf * (pts[1] - center[1]) + center[1];
pts[2] = sf * (pts[2] - center[2]) + center[2];
}
// Synchronize the handle representations with our recently updated
// "Points" data-structure.
this->PositionHandles();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::PlaceWidget(double bounds[6])
{
double corners[8][3] =
{ { bounds[0], bounds[2], bounds[4] },
{ bounds[1], bounds[2], bounds[4] },
{ bounds[1], bounds[3], bounds[4] },
{ bounds[0], bounds[3], bounds[4] },
{ bounds[0], bounds[2], bounds[5] },
{ bounds[1], bounds[2], bounds[5] },
{ bounds[1], bounds[3], bounds[5] },
{ bounds[0], bounds[3], bounds[5] } };
this->PlaceWidget(corners);
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::PlaceWidget(double corners[8][3])
{
// Scale the corners of parallelopiped according to the place factor.
// Note that the default place factor is 0.5. So if your corners
// appear half way in, don't be surprised.
//
double center[3] = {0.0, 0.0, 0.0}, newCorners[8][3];
for (int j = 0; j < 3; j++)
{
for (int i = 0; i < 8; center[j] += corners[i][j], i++)
{
;
}
center[j] /= 8.0;
for (int i = 0; i < 8; i++)
{
newCorners[i][j] = center[j] +
this->PlaceFactor*(corners[i][j]-center[j]);
}
}
for (int i = 0; i < 8; i++)
{
this->Points->SetPoint(i, newCorners[i]);
}
this->AbsoluteMinimumThickness =
this->HexPolyData->GetLength()*this->MinimumThickness;
this->ChairPointPlacer->SetMinimumDistance( 0.5 * this->AbsoluteMinimumThickness );
// Initialize the chair points too
for (int i = 8; i < 16; i++)
{
this->Points->SetPoint(i, newCorners[0]);
}
this->PositionHandles();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::GetPolyData(vtkPolyData *pd)
{
pd->SetPoints(this->HexPolyData->GetPoints());
pd->SetPolys(this->HexPolyData->GetPolys());
}
//----------------------------------------------------------------------------
double *vtkParallelopipedRepresentation::GetBounds()
{
return this->Points->GetBounds();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::BuildRepresentation()
{
this->Points->Modified();
}
//----------------------------------------------------------------------------
void vtkParallelopipedRepresentation::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Minimum Thickness: " << this->MinimumThickness << "\n";
if ( this->HandleProperty )
{
os << indent << "Handle Property: " << this->HandleProperty << "\n";
}
else
{
os << indent << "Handle Property: (none)\n";
}
if ( this->HoveredHandleProperty )
{
os << indent << "Hovered Handle Property: " << this->HoveredHandleProperty << "\n";
}
else
{
os << indent << "Hovered Handle Property: (none)\n";
}
if ( this->FaceProperty )
{
os << indent << "Face Property: " << this->FaceProperty << "\n";
}
else
{
os << indent << "Face Property: (none)\n";
}
if ( this->OutlineProperty )
{
os << indent << "Outline Property: " << this->OutlineProperty << "\n";
}
else
{
os << indent << "Outline Property: (none)\n";
}
if ( this->SelectedHandleProperty )
{
os << indent << "Selected Handle Property: " << this->SelectedHandleProperty << "\n";
}
else
{
os << indent << "Selected Handle Property: (none)\n";
}
if ( this->SelectedFaceProperty )
{
os << indent << "Selected Face Property: " << this->SelectedFaceProperty << "\n";
}
else
{
os << indent << "Selected Face Property: (none)\n";
}
if ( this->SelectedOutlineProperty )
{
os << indent << "Selected Outline Property: " << this->SelectedOutlineProperty << "\n";
}
else
{
os << indent << "Selected Outline Property: (none)\n";
}
// this->InteractionState is printed in superclass
// this is commented to avoid PrintSelf errors
}
Jump to Line
Something went wrong with that request. Please try again.