/*========================================================================= 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 #include 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 = nullptr; Distance = VTK_DOUBLE_MIN; } }; //---------------------------------------------------------------------- vtkBoundedPlanePointPlacer::vtkBoundedPlanePointPlacer() { this->ProjectionPosition = 0; this->ObliquePlane = nullptr; this->ProjectionNormal = vtkBoundedPlanePointPlacer::ZAxis; this->BoundingPlanes = nullptr; } //---------------------------------------------------------------------- vtkBoundedPlanePointPlacer::~vtkBoundedPlanePointPlacer() { this->RemoveAllBoundingPlanes(); if ( this->ObliquePlane ) { this->ObliquePlane->UnRegister(this); this->ObliquePlane = nullptr; } 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 == nullptr) { 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 = nullptr; } } //---------------------------------------------------------------------- void vtkBoundedPlanePointPlacer::SetBoundingPlanes(vtkPlanes *planes) { if (!planes) { return; } vtkPlane *plane; int numPlanes = planes->GetNumberOfPlanes(); this->RemoveAllBoundingPlanes(); for (int i=0; iGetPlane(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 = nullptr; 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"; } }