/*========================================================================= Program: Visualization Toolkit Module: vtkInteractorStyleRubberBandPick.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 "vtkInteractorStyleRubberBandPick.h" #include "vtkAbstractPropPicker.h" #include "vtkAreaPicker.h" #include "vtkAssemblyPath.h" #include "vtkObjectFactory.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkUnsignedCharArray.h" vtkStandardNewMacro(vtkInteractorStyleRubberBandPick); #define VTKISRBP_ORIENT 0 #define VTKISRBP_SELECT 1 //------------------------------------------------------------------------------ vtkInteractorStyleRubberBandPick::vtkInteractorStyleRubberBandPick() { this->CurrentMode = VTKISRBP_ORIENT; this->StartPosition[0] = this->StartPosition[1] = 0; this->EndPosition[0] = this->EndPosition[1] = 0; this->Moving = 0; this->PixelArray = vtkUnsignedCharArray::New(); } //------------------------------------------------------------------------------ vtkInteractorStyleRubberBandPick::~vtkInteractorStyleRubberBandPick() { this->PixelArray->Delete(); } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::StartSelect() { this->CurrentMode = VTKISRBP_SELECT; } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::OnChar() { switch (this->Interactor->GetKeyCode()) { case 'r': case 'R': // r toggles the rubber band selection mode for mouse button 1 if (this->CurrentMode == VTKISRBP_ORIENT) { this->CurrentMode = VTKISRBP_SELECT; } else { this->CurrentMode = VTKISRBP_ORIENT; } break; case 'p': case 'P': { vtkRenderWindowInteractor* rwi = this->Interactor; int* eventPos = rwi->GetEventPosition(); this->FindPokedRenderer(eventPos[0], eventPos[1]); this->StartPosition[0] = eventPos[0]; this->StartPosition[1] = eventPos[1]; this->EndPosition[0] = eventPos[0]; this->EndPosition[1] = eventPos[1]; this->Pick(); break; } default: this->Superclass::OnChar(); } } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::OnLeftButtonDown() { if (this->CurrentMode != VTKISRBP_SELECT) { // if not in rubber band mode, let the parent class handle it this->Superclass::OnLeftButtonDown(); return; } if (!this->Interactor) { return; } // otherwise record the rubber band starting coordinate this->Moving = 1; vtkRenderWindow* renWin = this->Interactor->GetRenderWindow(); this->StartPosition[0] = this->Interactor->GetEventPosition()[0]; this->StartPosition[1] = this->Interactor->GetEventPosition()[1]; this->EndPosition[0] = this->StartPosition[0]; this->EndPosition[1] = this->StartPosition[1]; this->PixelArray->Initialize(); this->PixelArray->SetNumberOfComponents(4); const int* size = renWin->GetSize(); this->PixelArray->SetNumberOfTuples(size[0] * size[1]); renWin->GetRGBACharPixelData(0, 0, size[0] - 1, size[1] - 1, 1, this->PixelArray); this->FindPokedRenderer(this->StartPosition[0], this->StartPosition[1]); } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::OnMouseMove() { if (this->CurrentMode != VTKISRBP_SELECT) { // if not in rubber band mode, let the parent class handle it this->Superclass::OnMouseMove(); return; } if (!this->Interactor || !this->Moving) { return; } this->EndPosition[0] = this->Interactor->GetEventPosition()[0]; this->EndPosition[1] = this->Interactor->GetEventPosition()[1]; const int* size = this->Interactor->GetRenderWindow()->GetSize(); if (this->EndPosition[0] > (size[0] - 1)) { this->EndPosition[0] = size[0] - 1; } if (this->EndPosition[0] < 0) { this->EndPosition[0] = 0; } if (this->EndPosition[1] > (size[1] - 1)) { this->EndPosition[1] = size[1] - 1; } if (this->EndPosition[1] < 0) { this->EndPosition[1] = 0; } this->RedrawRubberBand(); } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::OnLeftButtonUp() { if (this->CurrentMode != VTKISRBP_SELECT) { // if not in rubber band mode, let the parent class handle it this->Superclass::OnLeftButtonUp(); return; } if (!this->Interactor || !this->Moving) { return; } // otherwise record the rubber band end coordinate and then fire off a pick if ((this->StartPosition[0] != this->EndPosition[0]) || (this->StartPosition[1] != this->EndPosition[1])) { this->Pick(); } this->Moving = 0; // this->CurrentMode = VTKISRBP_ORIENT; } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::RedrawRubberBand() { // update the rubber band on the screen const int* size = this->Interactor->GetRenderWindow()->GetSize(); vtkUnsignedCharArray* tmpPixelArray = vtkUnsignedCharArray::New(); tmpPixelArray->DeepCopy(this->PixelArray); unsigned char* pixels = tmpPixelArray->GetPointer(0); int min[2], max[2]; min[0] = this->StartPosition[0] <= this->EndPosition[0] ? this->StartPosition[0] : this->EndPosition[0]; if (min[0] < 0) { min[0] = 0; } if (min[0] >= size[0]) { min[0] = size[0] - 1; } min[1] = this->StartPosition[1] <= this->EndPosition[1] ? this->StartPosition[1] : this->EndPosition[1]; if (min[1] < 0) { min[1] = 0; } if (min[1] >= size[1]) { min[1] = size[1] - 1; } max[0] = this->EndPosition[0] > this->StartPosition[0] ? this->EndPosition[0] : this->StartPosition[0]; if (max[0] < 0) { max[0] = 0; } if (max[0] >= size[0]) { max[0] = size[0] - 1; } max[1] = this->EndPosition[1] > this->StartPosition[1] ? this->EndPosition[1] : this->StartPosition[1]; if (max[1] < 0) { max[1] = 0; } if (max[1] >= size[1]) { max[1] = size[1] - 1; } int i; for (i = min[0]; i <= max[0]; i++) { pixels[4 * (min[1] * size[0] + i)] = 255 ^ pixels[4 * (min[1] * size[0] + i)]; pixels[4 * (min[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 1]; pixels[4 * (min[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (min[1] * size[0] + i) + 2]; pixels[4 * (max[1] * size[0] + i)] = 255 ^ pixels[4 * (max[1] * size[0] + i)]; pixels[4 * (max[1] * size[0] + i) + 1] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 1]; pixels[4 * (max[1] * size[0] + i) + 2] = 255 ^ pixels[4 * (max[1] * size[0] + i) + 2]; } for (i = min[1] + 1; i < max[1]; i++) { pixels[4 * (i * size[0] + min[0])] = 255 ^ pixels[4 * (i * size[0] + min[0])]; pixels[4 * (i * size[0] + min[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 1]; pixels[4 * (i * size[0] + min[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + min[0]) + 2]; pixels[4 * (i * size[0] + max[0])] = 255 ^ pixels[4 * (i * size[0] + max[0])]; pixels[4 * (i * size[0] + max[0]) + 1] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 1]; pixels[4 * (i * size[0] + max[0]) + 2] = 255 ^ pixels[4 * (i * size[0] + max[0]) + 2]; } this->Interactor->GetRenderWindow()->SetRGBACharPixelData( 0, 0, size[0] - 1, size[1] - 1, pixels, 0); this->Interactor->GetRenderWindow()->Frame(); tmpPixelArray->Delete(); } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::Pick() { // find rubber band lower left, upper right and center double rbcenter[3]; const int* size = this->Interactor->GetRenderWindow()->GetSize(); int min[2], max[2]; min[0] = this->StartPosition[0] <= this->EndPosition[0] ? this->StartPosition[0] : this->EndPosition[0]; if (min[0] < 0) { min[0] = 0; } if (min[0] >= size[0]) { min[0] = size[0] - 2; } min[1] = this->StartPosition[1] <= this->EndPosition[1] ? this->StartPosition[1] : this->EndPosition[1]; if (min[1] < 0) { min[1] = 0; } if (min[1] >= size[1]) { min[1] = size[1] - 2; } max[0] = this->EndPosition[0] > this->StartPosition[0] ? this->EndPosition[0] : this->StartPosition[0]; if (max[0] < 0) { max[0] = 0; } if (max[0] >= size[0]) { max[0] = size[0] - 2; } max[1] = this->EndPosition[1] > this->StartPosition[1] ? this->EndPosition[1] : this->StartPosition[1]; if (max[1] < 0) { max[1] = 0; } if (max[1] >= size[1]) { max[1] = size[1] - 2; } rbcenter[0] = (min[0] + max[0]) / 2.0; rbcenter[1] = (min[1] + max[1]) / 2.0; rbcenter[2] = 0; if (this->State == VTKIS_NONE) { // tell the RenderWindowInteractor's picker to make it happen vtkRenderWindowInteractor* rwi = this->Interactor; vtkAssemblyPath* path = nullptr; rwi->StartPickCallback(); vtkAbstractPropPicker* picker = vtkAbstractPropPicker::SafeDownCast(rwi->GetPicker()); if (picker != nullptr) { vtkAreaPicker* areaPicker = vtkAreaPicker::SafeDownCast(picker); if (areaPicker != nullptr) { areaPicker->AreaPick(min[0], min[1], max[0], max[1], this->CurrentRenderer); } else { picker->Pick(rbcenter[0], rbcenter[1], 0.0, this->CurrentRenderer); } path = picker->GetPath(); } if (path == nullptr) { this->HighlightProp(nullptr); this->PropPicked = 0; } else { // highlight the one prop that the picker saved in the path // this->HighlightProp(path->GetFirstNode()->GetViewProp()); this->PropPicked = 1; } rwi->EndPickCallback(); } this->Interactor->Render(); } //------------------------------------------------------------------------------ void vtkInteractorStyleRubberBandPick::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); }