// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include #include "vtkRegressionTestImage.h" #include "vtkTestUtilities.h" #include "vtkActor.h" #include "vtkCamera.h" #include "vtkCommand.h" #include "vtkHardwareSelector.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInteractorStyleRubberBandPick.h" #include "vtkNew.h" #include "vtkPolyDataMapper.h" #include "vtkProp3DCollection.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderedAreaPicker.h" #include "vtkRenderer.h" #include "vtkSelection.h" #include "vtkSelectionNode.h" #include "vtkSphereSource.h" #include class PointPickCommand : public vtkCommand { protected: std::vector PointIds; vtkRenderer* Renderer; vtkAreaPicker* Picker; vtkPolyDataMapper* Mapper; public: static PointPickCommand* New() { return new PointPickCommand; } vtkTypeMacro(PointPickCommand, vtkCommand); PointPickCommand() = default; ~PointPickCommand() override = default; void SetPointIds(vtkSelection* selection) { // Find selection node that we're interested in: const vtkIdType numNodes = selection->GetNumberOfNodes(); for (vtkIdType nodeId = 0; nodeId < numNodes; ++nodeId) { vtkSelectionNode* node = selection->GetNode(nodeId); // Check if the mapper is this instance of MoleculeMapper vtkActor* selActor = vtkActor::SafeDownCast(node->GetProperties()->Get(vtkSelectionNode::PROP())); if (selActor && (selActor->GetMapper() == this->Mapper)) { // Separate the selection ids into atoms and bonds vtkIdTypeArray* selIds = vtkArrayDownCast(node->GetSelectionList()); if (selIds) { vtkIdType numIds = selIds->GetNumberOfTuples(); for (vtkIdType i = 0; i < numIds; ++i) { vtkIdType curId = selIds->GetValue(i); this->PointIds.push_back(curId); } } } } } std::vector& GetPointIds() { return this->PointIds; } void SetMapper(vtkPolyDataMapper* m) { this->Mapper = m; } void SetRenderer(vtkRenderer* r) { this->Renderer = r; } void SetPicker(vtkAreaPicker* p) { this->Picker = p; } void Execute(vtkObject*, unsigned long, void*) override { vtkProp3DCollection* props = this->Picker->GetProp3Ds(); if (props->GetNumberOfItems() != 0) { // If anything was picked during the fast area pick, do a more detailed // pick. vtkNew selector; selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_POINTS); selector->SetRenderer(this->Renderer); selector->SetArea(static_cast(this->Renderer->GetPickX1()), static_cast(this->Renderer->GetPickY1()), static_cast(this->Renderer->GetPickX2()), static_cast(this->Renderer->GetPickY2())); // Make the actual pick and pass the result to the convenience function // defined earlier vtkSelection* result = selector->Select(); this->SetPointIds(result); this->DumpPointSelection(); result->Delete(); } } // Convenience function to print out the atom and bond ids that belong to // molMap and are contained in sel void DumpPointSelection() { // Print selection std::cerr << "\n### Selection ###\n"; std::cerr << "Points: "; for (std::vector::iterator i = this->PointIds.begin(); i != this->PointIds.end(); ++i) { std::cerr << *i << " "; } std::cerr << std::endl; } }; int TestPointSelection(int argc, char* argv[]) { // create a line and a mesh vtkNew sphere; // Set up render engine vtkNew sphereMapper; sphereMapper->SetInputConnection(sphere->GetOutputPort()); vtkNew actor; actor->SetMapper(sphereMapper); vtkNew ren; ren->AddActor(actor); vtkNew win; win->SetMultiSamples(0); win->AddRenderer(ren); vtkNew iren; iren->SetRenderWindow(win); ren->SetBackground(0.0, 0.0, 0.0); win->SetSize(450, 450); win->Render(); ren->GetActiveCamera()->Zoom(1.2); // Setup picker vtkNew pickerInt; iren->SetInteractorStyle(pickerInt); vtkNew picker; iren->SetPicker(picker); // We'll follow up the cheap RenderedAreaPick with a detailed selection // to obtain the atoms and bonds. vtkNew com; com->SetRenderer(ren); com->SetPicker(picker); com->SetMapper(sphereMapper); picker->AddObserver(vtkCommand::EndPickEvent, com); // Make pick -- lower left quarter of renderer win->Render(); picker->AreaPick(0, 0, 225, 225, ren); win->Render(); // Interact if desired int retVal = vtkRegressionTestImage(win); if (retVal == vtkRegressionTester::DO_INTERACTOR) { iren->Start(); } // Verify pick std::vector& pIds = com->GetPointIds(); if (pIds.size() < 7 || std::find(pIds.begin(), pIds.end(), 0) == pIds.end() || std::find(pIds.begin(), pIds.end(), 26) == pIds.end() || std::find(pIds.begin(), pIds.end(), 27) == pIds.end() || std::find(pIds.begin(), pIds.end(), 32) == pIds.end() || std::find(pIds.begin(), pIds.end(), 33) == pIds.end() || std::find(pIds.begin(), pIds.end(), 38) == pIds.end() || std::find(pIds.begin(), pIds.end(), 39) == pIds.end()) { std::cerr << "Incorrect atoms/bonds picked! (if any picks were performed inter" "actively this could be ignored).\n"; return EXIT_FAILURE; } return !retVal; }