/*========================================================================= 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 "vtkAssemblyNode.h" #include "vtkAssemblyPath.h" #include "vtkCellData.h" #include "vtkCellPicker.h" #include "vtkDataArray.h" #include "vtkIdList.h" #include "vtkInteractorObserver.h" #include "vtkMapper.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataCollection.h" #include "vtkProp.h" #include "vtkPropCollection.h" #include "vtkRenderer.h" #include class vtkPolygonalSurfacePointPlacerInternals { public: typedef std::vector 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; }