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

429 lines
12 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkBoundedPlanePointPlacer.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 "vtkBoundedPlanePointPlacer.h"
#include "vtkObjectFactory.h"
#include "vtkMath.h"
#include "vtkPlane.h"
#include "vtkPlanes.h"
#include "vtkPlaneCollection.h"
#include "vtkRenderer.h"
#include "vtkInteractorObserver.h"
#include "vtkLine.h"
#include "vtkCamera.h"
#include <algorithm>
#include <vector>
vtkStandardNewMacro(vtkBoundedPlanePointPlacer);
vtkCxxSetObjectMacro(vtkBoundedPlanePointPlacer, ObliquePlane, vtkPlane);
vtkCxxSetObjectMacro(vtkBoundedPlanePointPlacer, BoundingPlanes,vtkPlaneCollection);
//----------------------------------------------------------------------
// Place holder structure to find the two planes that would best cut
// a line with a plane. We do this freaky stuff because we cannot use
// absolute tolerances. Sometimes a point may be intersected by two planes
// when it is on a corner etc... Believe me, I found this necessary.
//
// Plane : The plane that we found had intersected the line in question
// p : The intersection point of the line and the plane.
// Distance: Distance of the point "p" from the object. Negative distances
// mean that it is outside.
struct vtkBoundedPlanePointPlacerNode
{
typedef vtkBoundedPlanePointPlacerNode Self;
mutable vtkPlane * Plane;
double Distance;
double p[3];
static bool Sort( const Self &a, const Self &b )
{ return a.Distance > b.Distance; }
bool operator==(const Self &a) const { return a.Plane == this->Plane; }
bool operator!=(const Self &a) const { return a.Plane != this->Plane; }
vtkBoundedPlanePointPlacerNode()
{ Plane = NULL; Distance = VTK_DOUBLE_MIN; }
};
//----------------------------------------------------------------------
vtkBoundedPlanePointPlacer::vtkBoundedPlanePointPlacer()
{
this->ProjectionPosition = 0;
this->ObliquePlane = NULL;
this->ProjectionNormal = vtkBoundedPlanePointPlacer::ZAxis;
this->BoundingPlanes = NULL;
}
//----------------------------------------------------------------------
vtkBoundedPlanePointPlacer::~vtkBoundedPlanePointPlacer()
{
this->RemoveAllBoundingPlanes();
if ( this->ObliquePlane )
{
this->ObliquePlane->UnRegister(this);
this->ObliquePlane = NULL;
}
if (this->BoundingPlanes)
{
this->BoundingPlanes->UnRegister(this);
}
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::SetProjectionPosition(double position)
{
if ( this->ProjectionPosition != position )
{
this->ProjectionPosition = position;
this->Modified();
}
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::AddBoundingPlane(vtkPlane *plane)
{
if (this->BoundingPlanes == NULL)
{
this->BoundingPlanes = vtkPlaneCollection::New();
this->BoundingPlanes->Register(this);
this->BoundingPlanes->Delete();
}
this->BoundingPlanes->AddItem(plane);
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::RemoveBoundingPlane(vtkPlane *plane)
{
if (this->BoundingPlanes )
{
this->BoundingPlanes->RemoveItem(plane);
}
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::RemoveAllBoundingPlanes()
{
if ( this->BoundingPlanes )
{
this->BoundingPlanes->RemoveAllItems();
this->BoundingPlanes->Delete();
this->BoundingPlanes = NULL;
}
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::SetBoundingPlanes(vtkPlanes *planes)
{
if (!planes)
{
return;
}
vtkPlane *plane;
int numPlanes = planes->GetNumberOfPlanes();
this->RemoveAllBoundingPlanes();
for (int i=0; i<numPlanes ; i++)
{
plane = vtkPlane::New();
planes->GetPlane(i, plane);
this->AddBoundingPlane(plane);
plane->Delete();
}
}
//----------------------------------------------------------------------
int vtkBoundedPlanePointPlacer::ComputeWorldPosition( vtkRenderer *ren,
double displayPos[2],
double vtkNotUsed(refWorldPos)[3],
double worldPos[3],
double worldOrient[9] )
{
return this->ComputeWorldPosition( ren, displayPos, worldPos, worldOrient );
}
//----------------------------------------------------------------------
int vtkBoundedPlanePointPlacer::ComputeWorldPosition( vtkRenderer *ren,
double displayPos[2],
double worldPos[3],
double worldOrient[9] )
{
double nearWorldPoint[4];
double farWorldPoint[4];
double tmp[3];
tmp[0] = displayPos[0];
tmp[1] = displayPos[1];
tmp[2] = 0.0; // near plane
ren->SetDisplayPoint(tmp);
ren->DisplayToWorld();
ren->GetWorldPoint(nearWorldPoint);
tmp[2] = 1.0; // far plane
ren->SetDisplayPoint(tmp);
ren->DisplayToWorld();
ren->GetWorldPoint(farWorldPoint);
double normal[3];
double origin[3];
this->GetProjectionNormal( normal );
this->GetProjectionOrigin( origin );
double position[3];
double distance;
if ( vtkPlane::IntersectWithLine( nearWorldPoint,
farWorldPoint,
normal, origin,
distance, position ) )
{
// Fill in the information now before validating it.
// This is because we should return the best information
// we can since this may be part of an UpdateWorldPosition
// call - we need to do the best at updating the position
// even if it is not valid.
this->GetCurrentOrientation( worldOrient );
worldPos[0] = position[0];
worldPos[1] = position[1];
worldPos[2] = position[2];
// Now check against the bounding planes
if ( this->BoundingPlanes )
{
vtkPlane *p;
this->BoundingPlanes->InitTraversal();
while ( (p = this->BoundingPlanes->GetNextItem()) )
{
if ( p->EvaluateFunction( position ) < this->WorldTolerance )
{
return 0;
}
}
}
return 1;
}
return 0;
}
//----------------------------------------------------------------------
int vtkBoundedPlanePointPlacer::ValidateWorldPosition( double worldPos[3],
double* vtkNotUsed(worldOrient) )
{
return this->ValidateWorldPosition( worldPos );
}
//----------------------------------------------------------------------
int vtkBoundedPlanePointPlacer::ValidateWorldPosition( double worldPos[3] )
{
// Now check against the bounding planes
if ( this->BoundingPlanes )
{
vtkPlane *p;
this->BoundingPlanes->InitTraversal();
while ( (p = this->BoundingPlanes->GetNextItem()) )
{
if ( p->EvaluateFunction( worldPos ) < this->WorldTolerance )
{
return 0;
}
}
}
return 1;
}
//----------------------------------------------------------------------
int vtkBoundedPlanePointPlacer::UpdateWorldPosition( vtkRenderer *ren,
double worldPos[3],
double worldOrient[9] )
{
double displayPoint[2];
double tmp[4];
tmp[0] = worldPos[0];
tmp[1] = worldPos[1];
tmp[2] = worldPos[2];
tmp[3] = 1.0;
ren->SetWorldPoint( tmp );
ren->WorldToDisplay();
ren->GetDisplayPoint( tmp );
displayPoint[0] = tmp[0];
displayPoint[1] = tmp[1];
return this->ComputeWorldPosition( ren, displayPoint,
worldPos, worldOrient );
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::GetCurrentOrientation( double worldOrient[9] )
{
double *x = worldOrient;
double *y = worldOrient+3;
double *z = worldOrient+6;
this->GetProjectionNormal( z );
double v[3];
if ( fabs( z[0] ) >= fabs( z[1] ) &&
fabs( z[0] ) >= fabs( z[2] ) )
{
v[0] = 0;
v[1] = 1;
v[2] = 0;
}
else
{
v[0] = 1;
v[1] = 0;
v[2] = 0;
}
vtkMath::Cross( z, v, y );
vtkMath::Cross( y, z, x );
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::GetProjectionNormal( double normal[3] )
{
switch ( this->ProjectionNormal )
{
case vtkBoundedPlanePointPlacer::XAxis:
normal[0] = 1.0;
normal[1] = 0.0;
normal[2] = 0.0;
break;
case vtkBoundedPlanePointPlacer::YAxis:
normal[0] = 0.0;
normal[1] = 1.0;
normal[2] = 0.0;
break;
case vtkBoundedPlanePointPlacer::ZAxis:
normal[0] = 0.0;
normal[1] = 0.0;
normal[2] = 1.0;
break;
case vtkBoundedPlanePointPlacer::Oblique:
this->ObliquePlane->GetNormal(normal);
break;
}
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::GetProjectionOrigin( double origin[3] )
{
switch ( this->ProjectionNormal )
{
case vtkBoundedPlanePointPlacer::XAxis:
origin[0] = this->ProjectionPosition;
origin[1] = 0.0;
origin[2] = 0.0;
break;
case vtkBoundedPlanePointPlacer::YAxis:
origin[0] = 0.0;
origin[1] = this->ProjectionPosition;
origin[2] = 0.0;
break;
case vtkBoundedPlanePointPlacer::ZAxis:
origin[0] = 0.0;
origin[1] = 0.0;
origin[2] = this->ProjectionPosition;
break;
case vtkBoundedPlanePointPlacer::Oblique:
this->ObliquePlane->GetOrigin(origin);
break;
}
}
//----------------------------------------------------------------------
// Calculate the distance of a point from the Object. Negative
// values imply that the point is outside. Positive values imply that it is
// inside. The closest point to the object is returned in closestPt.
double vtkBoundedPlanePointPlacer
::GetDistanceFromObject( double pos[3],
vtkPlaneCollection * pc,
double closestPt[3])
{
vtkPlane *minPlane = NULL;
double minD = VTK_DOUBLE_MAX;
pc->InitTraversal();
while ( vtkPlane * p = pc->GetNextItem() )
{
const double d = p->EvaluateFunction( pos );
if (d < minD)
{
minD = d;
minPlane = p;
}
}
vtkPlane::ProjectPoint( pos, minPlane->GetOrigin(),
minPlane->GetNormal(), closestPt );
return minD;
}
//----------------------------------------------------------------------
void vtkBoundedPlanePointPlacer::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
os << indent << "Projection Normal: ";
if ( this->ProjectionNormal == vtkBoundedPlanePointPlacer::XAxis )
{
os << "XAxis\n";
}
else if ( this->ProjectionNormal == vtkBoundedPlanePointPlacer::YAxis )
{
os << "YAxis\n";
}
else if ( this->ProjectionNormal == vtkBoundedPlanePointPlacer::ZAxis )
{
os << "ZAxis\n";
}
else //if ( this->ProjectionNormal == vtkBoundedPlanePointPlacer::Oblique )
{
os << "Oblique\n";
}
os << indent << "Projection Position: " << this->ProjectionPosition << "\n";
os << indent << "Bounding Planes:\n";
if ( this->BoundingPlanes )
{
this->BoundingPlanes->PrintSelf(os,indent.GetNextIndent());
}
else
{
os << " (none)\n";
}
os << indent << "Oblique plane:\n";
if ( this->ObliquePlane )
{
this->ObliquePlane->PrintSelf(os,indent.GetNextIndent());
}
else
{
os << " (none)\n";
}
}