/*========================================================================= Program: Visualization Toolkit Module: vtkInteractorStyleAreaSelectHover.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. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkInteractorStyleAreaSelectHover.h" #include "vtkActor.h" #include "vtkAppendPolyData.h" #include "vtkAreaLayout.h" #include "vtkBalloonRepresentation.h" #include "vtkCallbackCommand.h" #include "vtkCellArray.h" #include "vtkExtractEdges.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRendererCollection.h" #include "vtkSectorSource.h" #include "vtkStdString.h" #include "vtkStringArray.h" #include "vtkVariant.h" #include "vtkWorldPointPicker.h" #include "vtkSmartPointer.h" #define VTK_CREATE(type, name) vtkSmartPointer name = vtkSmartPointer::New() vtkStandardNewMacro(vtkInteractorStyleAreaSelectHover); vtkCxxSetObjectMacro(vtkInteractorStyleAreaSelectHover, Layout, vtkAreaLayout); //------------------------------------------------------------------------------ vtkInteractorStyleAreaSelectHover::vtkInteractorStyleAreaSelectHover() { this->Picker = vtkWorldPointPicker::New(); this->Balloon = vtkBalloonRepresentation::New(); this->Balloon->SetBalloonText(""); this->Balloon->SetOffset(1, 1); this->Layout = nullptr; this->LabelField = nullptr; this->UseRectangularCoordinates = false; this->HighlightData = vtkPolyData::New(); vtkPolyDataMapper* highMap = vtkPolyDataMapper::New(); highMap->SetInputData(this->HighlightData); this->HighlightActor = vtkActor::New(); this->HighlightActor->SetMapper(highMap); this->HighlightActor->VisibilityOff(); this->HighlightActor->PickableOff(); this->HighlightActor->GetProperty()->SetLineWidth(4.0); highMap->Delete(); } //------------------------------------------------------------------------------ vtkInteractorStyleAreaSelectHover::~vtkInteractorStyleAreaSelectHover() { this->HighlightData->Delete(); this->HighlightActor->Delete(); this->Picker->Delete(); this->Balloon->Delete(); if (this->Layout) { this->Layout->Delete(); this->Layout = nullptr; } this->SetLabelField(nullptr); } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::SetInteractor(vtkRenderWindowInteractor* rwi) { // See if we already had one vtkRenderWindowInteractor* mrwi = this->GetInteractor(); vtkRenderer* ren; if (mrwi && mrwi->GetRenderWindow()) { this->FindPokedRenderer(0, 0); ren = this->CurrentRenderer; if (ren) { ren->RemoveActor(HighlightActor); } } vtkInteractorStyleRubberBand2D::SetInteractor(rwi); if (rwi && rwi->GetRenderWindow()) { this->FindPokedRenderer(0, 0); ren = this->CurrentRenderer; if (ren) { ren->AddActor(HighlightActor); } } } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Layout: " << (this->Layout ? "" : "(none)") << endl; if (this->Layout) { this->Layout->PrintSelf(os, indent.GetNextIndent()); } os << indent << "LabelField: " << (this->LabelField ? this->LabelField : "(none)") << endl; os << indent << "UseRectangularCoordinates: " << this->UseRectangularCoordinates << endl; } //------------------------------------------------------------------------------ vtkIdType vtkInteractorStyleAreaSelectHover::GetIdAtPos(int x, int y) { vtkIdType id = -1; vtkRenderer* r = this->CurrentRenderer; if (r == nullptr) { return id; } // Use the hardware picker to find a point in world coordinates. this->Picker->Pick(x, y, 0, r); double pos[3]; this->Picker->GetPickPosition(pos); if (this->Layout) { float posFloat[3]; for (int i = 0; i < 3; i++) { posFloat[i] = pos[i]; } id = this->Layout->FindVertex(posFloat); } return id; } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::GetBoundingAreaForItem(vtkIdType id, float* sinfo) { if (this->Layout) { this->Layout->GetBoundingArea(id, sinfo); } } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::OnMouseMove() { if (this->Interaction == vtkInteractorStyleRubberBand2D::SELECTING) { this->Balloon->SetVisibility(false); this->Superclass::OnMouseMove(); return; } this->Balloon->SetVisibility(true); int x = this->Interactor->GetEventPosition()[0]; int y = this->Interactor->GetEventPosition()[1]; this->FindPokedRenderer(x, y); vtkRenderer* r = this->CurrentRenderer; if (r == nullptr) { return; } if (!r->HasViewProp(this->Balloon)) { r->AddActor(this->Balloon); this->Balloon->SetRenderer(r); } // Use the hardware picker to find a point in world coordinates. float sinfo[4]; vtkIdType id = this->GetIdAtPos(x, y); if (id != -1) { this->GetBoundingAreaForItem(id, sinfo); } double loc[2] = { static_cast(x), static_cast(y) }; this->Balloon->EndWidgetInteraction(loc); if (this->Layout && this->Layout->GetOutput()) { vtkAbstractArray* absArray = this->Layout->GetOutput()->GetVertexData()->GetAbstractArray(this->LabelField); // find the information for the correct sector, // unless there isn't a sector or it is the root node if (absArray != nullptr && id > -1) { vtkStdString str; if (vtkArrayDownCast(absArray)) { str = vtkArrayDownCast(absArray)->GetValue(id); } if (vtkArrayDownCast(absArray)) { str = vtkVariant(vtkArrayDownCast(absArray)->GetTuple(id)[0]).ToString(); } this->Balloon->SetBalloonText(str); double z = 0.02; if (this->UseRectangularCoordinates) { VTK_CREATE(vtkPoints, highlightPoints); highlightPoints->SetNumberOfPoints(5); VTK_CREATE(vtkCellArray, highA); highA->InsertNextCell(5); for (int i = 0; i < 5; ++i) { highA->InsertCellPoint(i); } highlightPoints->SetPoint(0, sinfo[0], sinfo[2], z); highlightPoints->SetPoint(1, sinfo[1], sinfo[2], z); highlightPoints->SetPoint(2, sinfo[1], sinfo[3], z); highlightPoints->SetPoint(3, sinfo[0], sinfo[3], z); highlightPoints->SetPoint(4, sinfo[0], sinfo[2], z); this->HighlightData->SetPoints(highlightPoints); this->HighlightData->SetLines(highA); } else { if (sinfo[1] - sinfo[0] != 360.) { VTK_CREATE(vtkSectorSource, sector); sector->SetInnerRadius(sinfo[2]); sector->SetOuterRadius(sinfo[3]); sector->SetZCoord(z); sector->SetStartAngle(sinfo[0]); sector->SetEndAngle(sinfo[1]); int resolution = (int)((sinfo[1] - sinfo[0]) / 1); if (resolution < 1) resolution = 1; sector->SetCircumferentialResolution(resolution); sector->Update(); VTK_CREATE(vtkExtractEdges, extract); extract->SetInputConnection(sector->GetOutputPort()); VTK_CREATE(vtkAppendPolyData, append); append->AddInputConnection(extract->GetOutputPort()); append->Update(); this->HighlightData->ShallowCopy(append->GetOutput()); } else { VTK_CREATE(vtkPoints, highlightPoints); highlightPoints->SetNumberOfPoints(240); double conversion = vtkMath::Pi() / 180.; double current_angle = 0.; VTK_CREATE(vtkCellArray, highA); for (int i = 0; i < 120; ++i) { highA->InsertNextCell(2); double current_x = sinfo[2] * cos(conversion * current_angle); double current_y = sinfo[2] * sin(conversion * current_angle); highlightPoints->SetPoint(i, current_x, current_y, z); current_angle += 3.; highA->InsertCellPoint(i); highA->InsertCellPoint((i + 1) % 120); } current_angle = 0.; for (int i = 0; i < 120; ++i) { highA->InsertNextCell(2); double current_x = sinfo[3] * cos(conversion * current_angle); double current_y = sinfo[3] * sin(conversion * current_angle); highlightPoints->SetPoint(120 + i, current_x, current_y, z); current_angle += 3.; highA->InsertCellPoint(120 + i); highA->InsertCellPoint(120 + ((i + 1) % 120)); } this->HighlightData->SetPoints(highlightPoints); this->HighlightData->SetLines(highA); } } this->HighlightActor->VisibilityOn(); } else { this->Balloon->SetBalloonText(""); HighlightActor->VisibilityOff(); } this->Balloon->StartWidgetInteraction(loc); this->InvokeEvent(vtkCommand::InteractionEvent, nullptr); this->GetInteractor()->Render(); } this->Superclass::OnMouseMove(); } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::SetHighLightColor(double r, double g, double b) { this->HighlightActor->GetProperty()->SetColor(r, g, b); } //------------------------------------------------------------------------------ void vtkInteractorStyleAreaSelectHover::SetHighLightWidth(double lw) { this->HighlightActor->GetProperty()->SetLineWidth(lw); } //------------------------------------------------------------------------------ double vtkInteractorStyleAreaSelectHover::GetHighLightWidth() { return this->HighlightActor->GetProperty()->GetLineWidth(); }