/*========================================================================= Program: Visualization Toolkit Module: vtkScenePicker.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 "vtkScenePicker.h" #include "vtkCommand.h" #include "vtkDataObject.h" #include "vtkHardwareSelector.h" #include "vtkObjectFactory.h" #include "vtkProp.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" class vtkScenePickerSelectionRenderCommand : public vtkCommand { public: vtkScenePicker* m_Picker; static vtkScenePickerSelectionRenderCommand* New() { return new vtkScenePickerSelectionRenderCommand; } void Execute(vtkObject* vtkNotUsed(o), unsigned long event, void*) override { if (event == vtkCommand::StartInteractionEvent) { this->InteractiveRender = true; } else if (event == vtkCommand::EndInteractionEvent) { this->InteractiveRender = false; } else if (event == vtkCommand::EndEvent) { if (!this->InteractiveRender) { m_Picker->PickRender(); } this->m_Picker->SetRenderer(this->m_Picker->Renderer); } } protected: vtkScenePickerSelectionRenderCommand() : InteractiveRender(false) { } ~vtkScenePickerSelectionRenderCommand() override = default; bool InteractiveRender; }; vtkStandardNewMacro(vtkScenePicker); //------------------------------------------------------------------------------ vtkScenePicker::vtkScenePicker() { this->EnableVertexPicking = 1; this->Renderer = nullptr; this->Interactor = nullptr; this->Selector = vtkHardwareSelector::New(); this->NeedToUpdate = false; this->VertId = -1; this->CellId = -1; this->Prop = nullptr; this->SelectionRenderCommand = vtkScenePickerSelectionRenderCommand::New(); this->SelectionRenderCommand->m_Picker = this; } //------------------------------------------------------------------------------ vtkScenePicker::~vtkScenePicker() { this->SetRenderer(nullptr); this->Selector->Delete(); this->SelectionRenderCommand->Delete(); } //------------------------------------------------------------------------------ void vtkScenePicker::SetRenderer(vtkRenderer* r) { vtkRenderWindowInteractor* rwi = nullptr; if (r && r->GetRenderWindow()) { rwi = r->GetRenderWindow()->GetInteractor(); } this->SetInteractor(rwi); if (this->Renderer == r) { return; } if (r && !r->GetRenderWindow()) { vtkErrorMacro(<< "Renderer: " << this->Renderer << " does not have its render window set."); return; } if (this->Renderer) { this->Renderer->GetRenderWindow()->RemoveObserver(this->SelectionRenderCommand); } vtkSetObjectBodyMacro(Renderer, vtkRenderer, r); if (this->Renderer) { this->Renderer->GetRenderWindow()->AddObserver( vtkCommand::EndEvent, this->SelectionRenderCommand, 0.01); } this->Selector->SetRenderer(this->Renderer); } //------------------------------------------------------------------------------ void vtkScenePicker::SetInteractor(vtkRenderWindowInteractor* rwi) { if (this->Interactor == rwi) { return; } if (this->Interactor) { this->Interactor->RemoveObserver(this->SelectionRenderCommand); } vtkSetObjectBodyMacro(Interactor, vtkRenderWindowInteractor, rwi); if (this->Interactor) { this->Interactor->AddObserver( vtkCommand::StartInteractionEvent, this->SelectionRenderCommand, 0.01); this->Interactor->AddObserver( vtkCommand::EndInteractionEvent, this->SelectionRenderCommand, 0.01); } } //------------------------------------------------------------------------------ // Do a selection render.. for caching object selection stuff. // This is used for Object selection . We have to perform // "select" and "mouse over" and "mouse out" as the mouse moves around the // scene (or the mouse is clicked in the case of "select"). I do not want // to do a conventional pick for this function because it's too darn slow. // The Selector will be used here to pick-render the entire // screen, store on a buffer the colored cells and read back as // the mouse moves around the moused pick. This extra render from the // Selector will be done only if the camera isn't in motion, // otherwise motion would be too frickin slow. // void vtkScenePicker::PickRender() { if (!this->Renderer || !this->Renderer->GetRenderWindow()) { return; } double vp[4]; this->Renderer->GetViewport(vp); int size[2] = { this->Renderer->GetRenderWindow()->GetSize()[0], this->Renderer->GetRenderWindow()->GetSize()[1] }; int rx1 = static_cast(vp[0] * (size[0] - 1)); int ry1 = static_cast(vp[1] * (size[1] - 1)); int rx2 = static_cast(vp[2] * (size[0] - 1)); int ry2 = static_cast(vp[3] * (size[1] - 1)); this->PickRender(rx1, ry1, rx2, ry2); } //------------------------------------------------------------------------------ // Do a selection render.. for caching object selection stuff. void vtkScenePicker::PickRender(int x0, int y0, int x1, int y1) { this->Renderer->GetRenderWindow()->RemoveObserver(this->SelectionRenderCommand); if (this->EnableVertexPicking) { this->Selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_POINTS); } else { this->Selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_CELLS); } cout << "Area: " << x0 << ", " << y0 << ", " << x1 << ", " << y1 << endl; this->Selector->SetArea(x0, y0, x1, y1); if (!this->Selector->CaptureBuffers()) { vtkErrorMacro("Failed to capture buffers."); } this->NeedToUpdate = true; this->PickRenderTime.Modified(); this->Renderer->GetRenderWindow()->AddObserver( vtkCommand::EndEvent, this->SelectionRenderCommand, 0.01); } //------------------------------------------------------------------------------ vtkIdType vtkScenePicker::GetCellId(int displayPos[2]) { if (this->EnableVertexPicking) { return -1; } this->Update(displayPos); return this->CellId; } //------------------------------------------------------------------------------ vtkProp* vtkScenePicker::GetViewProp(int displayPos[2]) { this->Update(displayPos); return this->Prop; } //------------------------------------------------------------------------------ vtkIdType vtkScenePicker::GetVertexId(int displayPos[2]) { if (!this->EnableVertexPicking) { return -1; } this->Update(displayPos); return this->CellId; } //------------------------------------------------------------------------------ void vtkScenePicker::Update(int displayPos[2]) { if (this->PickRenderTime <= this->GetMTime()) { this->PickRender(); } if (this->NeedToUpdate || this->LastQueriedDisplayPos[0] != displayPos[0] || this->LastQueriedDisplayPos[1] != displayPos[1]) { this->Prop = nullptr; unsigned int dpos[2] = { 0, 0 }; if (displayPos[0] >= 0 && displayPos[1] >= 0) { dpos[0] = static_cast(displayPos[0]); dpos[1] = static_cast(displayPos[1]); vtkHardwareSelector::PixelInformation info = this->Selector->GetPixelInformation(dpos); this->CellId = info.AttributeID; this->Prop = info.Prop; } this->LastQueriedDisplayPos[0] = displayPos[0]; this->LastQueriedDisplayPos[1] = displayPos[1]; this->NeedToUpdate = false; } } //------------------------------------------------------------------------------ void vtkScenePicker::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Renderer: " << this->Renderer << endl; os << indent << "EnableVertexPicking: " << this->EnableVertexPicking << endl; }