/*========================================================================= Program: Visualization Toolkit Module: vtkPolygonalSurfacePointPlacer.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 "vtkPolygonalSurfacePointPlacer.h" #include "vtkObjectFactory.h" #include "vtkRenderer.h" #include "vtkProp.h" #include "vtkPropCollection.h" #include "vtkPolyDataCollection.h" #include "vtkCellPicker.h" #include "vtkAssemblyPath.h" #include "vtkAssemblyNode.h" #include "vtkInteractorObserver.h" #include "vtkMapper.h" #include "vtkPolyData.h" #include "vtkMath.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkIdList.h" #include class vtkPolygonalSurfacePointPlacerInternals { public: typedef std::vector< vtkPolygonalSurfacePointPlacerNode * > NodesContainerType; NodesContainerType Nodes; ~vtkPolygonalSurfacePointPlacerInternals() { for (unsigned int i = 0; i < this->Nodes.size(); i++) { delete this->Nodes[i]; } this->Nodes.clear(); } vtkPolygonalSurfacePointPlacerNode *GetNodeAtSurfaceWorldPosition( double worldPos[3] ) { const double tolerance = 0.0005; for (unsigned int i = 0; i < this->Nodes.size(); i++) { if (vtkMath::Distance2BetweenPoints( this->Nodes[i]->SurfaceWorldPosition, worldPos ) < tolerance) { return this->Nodes[i]; } } return nullptr; } vtkPolygonalSurfacePointPlacerNode *GetNodeAtWorldPosition( double worldPos[3] ) { const double tolerance = 0.0005; for (unsigned int i = 0; i < this->Nodes.size(); i++) { if (vtkMath::Distance2BetweenPoints( this->Nodes[i]->WorldPosition, worldPos ) < tolerance) { return this->Nodes[i]; } } return nullptr; } vtkPolygonalSurfacePointPlacerNode *InsertNodeAtCurrentPickPosition( vtkCellPicker *picker, const double distanceOffset, int snapToClosestPoint ) { double worldPos[3]; picker->GetPickPosition(worldPos); // Get a node at this position if one exists and overwrite it // with the current pick position. If one doesn't exist, add // a new node. vtkPolygonalSurfacePointPlacerNode * node = this->GetNodeAtSurfaceWorldPosition(worldPos); if (!node) { node = new vtkPolygonalSurfacePointPlacerNode; this->Nodes.push_back(node); } vtkMapper *mapper = vtkMapper::SafeDownCast(picker->GetMapper()); if (!mapper) { return nullptr; } // Get the underlying dataset vtkPolyData *pd = vtkPolyData::SafeDownCast(mapper->GetInput()); if (!pd) { return nullptr; } node->CellId = picker->GetCellId(); picker->GetPCoords(node->ParametricCoords); // translate to the closest point on that cell, if requested if (snapToClosestPoint) { vtkIdList *ids = vtkIdList::New(); pd->GetCellPoints( picker->GetCellId(), ids ); double p[3], minDistance = VTK_DOUBLE_MAX; for (vtkIdType i = 0; i < ids->GetNumberOfIds(); ++i) { pd->GetPoints()->GetPoint(ids->GetId(i), p); const double dist2 = vtkMath::Distance2BetweenPoints( worldPos, pd->GetPoints()->GetPoint(ids->GetId(i))); if (dist2 < minDistance) { minDistance = dist2; worldPos[0] = p[0]; worldPos[1] = p[1]; worldPos[2] = p[2]; } } ids->Delete(); } node->SurfaceWorldPosition[0] = worldPos[0]; node->SurfaceWorldPosition[1] = worldPos[1]; node->SurfaceWorldPosition[2] = worldPos[2]; node->PolyData = pd; double cellNormal[3]; if (distanceOffset != 0.0) { pd->GetCellData()->GetNormals()->GetTuple( node->CellId, cellNormal ); // Polyline can be drawn on polydata at a height offset. for (unsigned int i =0; i < 3; i++) { node->WorldPosition[i] = node->SurfaceWorldPosition[i] + cellNormal[i] * distanceOffset; } } else { for (unsigned int i =0; i < 3; i++) { node->WorldPosition[i] = node->SurfaceWorldPosition[i]; } } return node; } vtkPolygonalSurfacePointPlacerNode *InsertNodeAtCurrentPickPosition( vtkPolyData *pd, double worldPos[3], vtkIdType cellId, vtkIdType pointId, const double vtkNotUsed(distanceOffset), int vtkNotUsed(snapToClosestPoint) ) { // Get a node at this position if one exists and overwrite it // with the current pick position. If one doesn't exist, add // a new node. vtkPolygonalSurfacePointPlacerNode * node = this->GetNodeAtSurfaceWorldPosition(worldPos); if (!node) { node = new vtkPolygonalSurfacePointPlacerNode; this->Nodes.push_back(node); } node->CellId = cellId; node->PointId = pointId; node->SurfaceWorldPosition[0] = worldPos[0]; node->SurfaceWorldPosition[1] = worldPos[1]; node->SurfaceWorldPosition[2] = worldPos[2]; node->PolyData = pd; for (unsigned int i =0; i < 3; i++) { node->WorldPosition[i] = node->SurfaceWorldPosition[i]; } return node; } //ashish }; vtkStandardNewMacro(vtkPolygonalSurfacePointPlacer); //---------------------------------------------------------------------- vtkPolygonalSurfacePointPlacer::vtkPolygonalSurfacePointPlacer() { this->Polys = vtkPolyDataCollection::New(); this->CellPicker = vtkCellPicker::New(); this->CellPicker->PickFromListOn(); this->CellPicker->SetTolerance(0.005); // need some fluff this->Internals = new vtkPolygonalSurfacePointPlacerInternals; this->DistanceOffset = 0.0; this->SnapToClosestPoint = 0; } //---------------------------------------------------------------------- vtkPolygonalSurfacePointPlacer::~vtkPolygonalSurfacePointPlacer() { this->CellPicker->Delete(); this->Polys->Delete(); delete this->Internals; } //---------------------------------------------------------------------- void vtkPolygonalSurfacePointPlacer::AddProp(vtkProp *prop) { this->SurfaceProps->AddItem(prop); this->CellPicker->AddPickList(prop); } //---------------------------------------------------------------------- void vtkPolygonalSurfacePointPlacer::RemoveViewProp(vtkProp *prop) { this->Superclass::RemoveViewProp( prop ); this->CellPicker->DeletePickList( prop ); } //---------------------------------------------------------------------- void vtkPolygonalSurfacePointPlacer::RemoveAllProps() { this->Superclass::RemoveAllProps(); this->CellPicker->InitializePickList(); } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer::ComputeWorldPosition( vtkRenderer *ren, double displayPos[2], double *vtkNotUsed(refWorldPos), double worldPos[3], double worldOrient[9] ) { return this->ComputeWorldPosition(ren, displayPos, worldPos, worldOrient); } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer::ComputeWorldPosition( vtkRenderer *ren, double displayPos[2], double worldPos[3], double vtkNotUsed(worldOrient)[9] ) { if ( this->CellPicker->Pick(displayPos[0], displayPos[1], 0.0, ren) ) { vtkMapper *mapper = vtkMapper::SafeDownCast(this->CellPicker->GetMapper()); if (!mapper) { return 0; } // Get the underlying dataset vtkPolyData *pd = vtkPolyData::SafeDownCast(mapper->GetInput()); if (!pd) { return 0; } if (vtkAssemblyPath *path = this->CellPicker->GetPath()) { // We are checking if the prop present in the path is present // in the list supplied to us.. If it is, that prop will be picked. // If not, no prop will be picked. bool found = false; vtkAssemblyNode *node = nullptr; vtkCollectionSimpleIterator sit; this->SurfaceProps->InitTraversal(sit); while (vtkProp *p = this->SurfaceProps->GetNextProp(sit)) { vtkCollectionSimpleIterator psit; path->InitTraversal(psit); for ( int i = 0; i < path->GetNumberOfItems() && !found ; ++i ) { node = path->GetNextNode(psit); found = ( node->GetViewProp() == p ); } if (found) { vtkPolygonalSurfacePointPlacer::Node *contourNode = this->Internals->InsertNodeAtCurrentPickPosition( this->CellPicker, this->DistanceOffset, this->SnapToClosestPoint); if (contourNode) { worldPos[0] = contourNode->WorldPosition[0]; worldPos[1] = contourNode->WorldPosition[1]; worldPos[2] = contourNode->WorldPosition[2]; return 1; } } } } } return 0; } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer::ValidateWorldPosition( double worldPos[3], double *vtkNotUsed(worldOrient) ) { return this->ValidateWorldPosition( worldPos ); } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer::ValidateWorldPosition( double vtkNotUsed(worldPos)[3] ) { return 1; } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer::ValidateDisplayPosition( vtkRenderer *, double vtkNotUsed(displayPos)[2] ) { // We could check here to ensure that the display point picks one of the // terrain props, but the contour representation always calls // ComputeWorldPosition followed by // ValidateDisplayPosition/ValidateWorldPosition when it needs to // update a node... // // So that would be wasting CPU cycles to perform // the same check twice.. Just return 1 here. return 1; } //---------------------------------------------------------------------- vtkPolygonalSurfacePointPlacer::Node *vtkPolygonalSurfacePointPlacer ::GetNodeAtWorldPosition( double worldPos[3] ) { return this->Internals->GetNodeAtWorldPosition(worldPos); } //---------------------------------------------------------------------- int vtkPolygonalSurfacePointPlacer:: UpdateNodeWorldPosition( double worldPos[3], vtkIdType nodePointId ) { if( this->Polys->GetNumberOfItems() != 0 ) { vtkPolyData *pd = vtkPolyData::SafeDownCast( this->Polys->GetItemAsObject(0)); this->Internals->InsertNodeAtCurrentPickPosition( pd, worldPos,-1,nodePointId,this->DistanceOffset,this->SnapToClosestPoint); return 1; } else { vtkErrorMacro("PolyDataCollection has no items."); return 0; } } //---------------------------------------------------------------------- void vtkPolygonalSurfacePointPlacer::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); os << indent << "Cell Picker: " << this->CellPicker << endl; if (this->CellPicker) { this->CellPicker->PrintSelf(os, indent.GetNextIndent()); } os << indent << "Surface Props: " << this->SurfaceProps << endl; if (this->SurfaceProps) { this->SurfaceProps->PrintSelf(os, indent.GetNextIndent()); } os << indent << "Surface polygons: " << this->Polys << endl; if (this->Polys) { this->Polys->PrintSelf(os, indent.GetNextIndent()); } os << indent << "Distance Offset: " << this->DistanceOffset << "\n"; os << indent << "SnapToClosestPoint: " << this->SnapToClosestPoint << endl; }