/*========================================================================= Program: Visualization Toolkit Module: vtkParallelCoordinatesView.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 2009 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkParallelCoordinatesView.h" #include "vtkActor2D.h" #include "vtkAlgorithmOutput.h" #include "vtkBalloonRepresentation.h" #include "vtkCellArray.h" #include "vtkCellArrayIterator.h" #include "vtkCommand.h" #include "vtkDataSetAttributes.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" #include "vtkObjectFactory.h" #include "vtkOutlineSource.h" #include "vtkParallelCoordinatesHistogramRepresentation.h" #include "vtkParallelCoordinatesInteractorStyle.h" #include "vtkParallelCoordinatesRepresentation.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper2D.h" #include "vtkProperty2D.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRendererCollection.h" #include "vtkSCurveSpline.h" #include "vtkSelection.h" #include "vtkSelectionNode.h" #include "vtkTable.h" #include "vtkTextProperty.h" #include "vtkViewTheme.h" #include #include vtkStandardNewMacro(vtkParallelCoordinatesView); //------------------------------------------------------------------------------ vtkParallelCoordinatesView::vtkParallelCoordinatesView() { vtkParallelCoordinatesInteractorStyle* istyle = vtkParallelCoordinatesInteractorStyle::New(); this->SetInteractorStyle(istyle); istyle->Delete(); this->ReuseSingleRepresentationOn(); istyle->AddObserver(vtkCommand::StartInteractionEvent, this->GetObserver()); istyle->AddObserver(vtkCommand::InteractionEvent, this->GetObserver()); istyle->AddObserver(vtkCommand::EndInteractionEvent, this->GetObserver()); istyle->AddObserver(vtkCommand::UpdateEvent, this->GetObserver()); this->BrushData = vtkSmartPointer::New(); this->BrushMapper = vtkSmartPointer::New(); this->BrushActor = vtkSmartPointer::New(); vtkSmartPointer dummycoord = vtkSmartPointer::New(); dummycoord->SetCoordinateSystemToNormalizedViewport(); this->BrushMapper->SetInputData(this->BrushData); this->BrushMapper->SetTransformCoordinate(dummycoord); this->BrushActor->SetMapper(this->BrushMapper); this->BrushActor->GetProperty()->SetColor(.1, 1.0, 1.0); this->InspectMode = VTK_INSPECT_MANIPULATE_AXES; this->BrushMode = VTK_BRUSH_LASSO; this->BrushOperator = VTK_BRUSHOPERATOR_ADD; this->MaximumNumberOfBrushPoints = -1; this->NumberOfBrushPoints = 0; this->SetMaximumNumberOfBrushPoints(100); this->ClearBrushPoints(); this->FirstFunctionBrushLineDrawn = 0; this->CurrentBrushClass = 0; this->AxisHighlightPosition = VTK_HIGHLIGHT_CENTER; this->SelectedAxisPosition = -1; this->HighlightSource = vtkSmartPointer::New(); this->HighlightMapper = vtkSmartPointer::New(); this->HighlightActor = vtkSmartPointer::New(); this->HighlightSource->SetBounds(-1, -1, -1, -1, -1, -1); this->HighlightMapper->SetInputConnection(this->HighlightSource->GetOutputPort()); this->HighlightMapper->SetTransformCoordinate(dummycoord); this->HighlightActor->SetMapper(this->HighlightMapper); this->HighlightActor->GetProperty()->SetColor(.1, 1.0, .1); this->HighlightActor->VisibilityOff(); // vtkSmartPointer theme = vtkSmartPointer::New(); // theme->SetBackgroundColor(0,0,0); // theme->SetBackgroundColor2(0,0,0); // this->ApplyViewTheme(theme); } //------------------------------------------------------------------------------ vtkParallelCoordinatesView::~vtkParallelCoordinatesView() = default; void vtkParallelCoordinatesView::PrepareForRendering() { vtkDebugMacro(<< "*** PrepareForRendering called"); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); if (rep) { vtkRenderer* ren = this->GetRenderer(); this->Superclass::PrepareForRendering(); if (!ren->HasViewProp(this->HighlightActor)) { ren->AddActor(this->HighlightActor); } if (!ren->HasViewProp(this->BrushActor)) { ren->AddActor(this->BrushActor); } // this is a hack to make sure that the balloon hover text is sitting on top if (ren->HasViewProp(this->Balloon)) { this->Renderer->RemoveViewProp(this->Balloon); this->Renderer->AddViewProp(this->Balloon); } } } //------------------------------------------------------------------------------ void vtkParallelCoordinatesView::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << "MaximumNumberOfBrushPoints: " << this->MaximumNumberOfBrushPoints << endl; os << "BrushOperator: " << this->BrushOperator << endl; os << "BrushMode: " << this->BrushMode << endl; os << "InspectMode: " << this->InspectMode << endl; os << "CurrentBrushClass: " << this->CurrentBrushClass << endl; } //------------------------------------------------------------------------------ // The frustum selection code is borrowed from vtkRenderView. void vtkParallelCoordinatesView::ProcessEvents( vtkObject* caller, unsigned long eventId, void* callData) { // if (caller == this->GetInteractor() || caller == this->GetInteractorStyle()) if (caller == this->GetInteractorStyle()) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); if (style && rep) { int state = style->GetState(); if (eventId == vtkCommand::UpdateEvent) { rep->ResetAxes(); } else { switch (state) { case vtkParallelCoordinatesInteractorStyle::INTERACT_HOVER: this->Hover(eventId); break; case vtkParallelCoordinatesInteractorStyle::INTERACT_INSPECT: if (this->InspectMode == VTK_INSPECT_MANIPULATE_AXES) { this->ManipulateAxes(eventId); } else if (this->InspectMode == VTK_INSPECT_SELECT_DATA) { this->SelectData(eventId); } break; case vtkParallelCoordinatesInteractorStyle::INTERACT_ZOOM: this->Zoom(eventId); break; case vtkParallelCoordinatesInteractorStyle::INTERACT_PAN: this->Pan(eventId); break; } } this->Render(); } } this->Superclass::ProcessEvents(caller, eventId, callData); } vtkDataRepresentation* vtkParallelCoordinatesView::CreateDefaultRepresentation( vtkAlgorithmOutput* conn) { vtkParallelCoordinatesHistogramRepresentation* rep = vtkParallelCoordinatesHistogramRepresentation::New(); rep->SetInputConnection(conn); vtkDataObject* data = conn->GetProducer()->GetOutputDataObject(0); vtkTable* td = vtkTable::SafeDownCast(data); if (!td) { rep->SetInputArrayToProcess( 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS, vtkDataSetAttributes::SCALARS); } else { int ncols = td->GetNumberOfColumns(); for (int i = 0; i < ncols; i++) { vtkAbstractArray* a = td->GetColumn(i); rep->SetInputArrayToProcess(i, 0, 0, vtkDataObject::FIELD_ASSOCIATION_ROWS, a->GetName()); } } return rep; } int vtkParallelCoordinatesView::SetAxisHighlightPosition( vtkParallelCoordinatesRepresentation* rep, int position) { int numAxes = rep->GetNumberOfAxes(); if (numAxes <= 0) return -1; double p1[2], p2[2]; rep->GetPositionAndSize(p1, p2); double xpos = rep->GetXCoordinateOfPosition(position); if (xpos < 0 || position < 0 || position >= numAxes) { this->HighlightSource->SetBounds(-1, -1, -1, -1, -1, -1); this->HighlightActor->VisibilityOff(); return -1; } else { double xmargin = .3 * p2[0] / static_cast(numAxes); double ymargin = .05 * p2[1]; if (this->AxisHighlightPosition == VTK_HIGHLIGHT_CENTER) { this->HighlightSource->SetBounds( xpos - xmargin, xpos + xmargin, p1[1] + ymargin, p1[1] + p2[1] - ymargin, 0, 0); } else if (this->AxisHighlightPosition == VTK_HIGHLIGHT_MIN) { this->HighlightSource->SetBounds( xpos - xmargin, xpos + xmargin, p1[1] - ymargin, p1[1] + ymargin, 0, 0); } else if (this->AxisHighlightPosition == VTK_HIGHLIGHT_MAX) { this->HighlightSource->SetBounds( xpos - xmargin, xpos + xmargin, p1[1] + p2[1] - ymargin, p1[1] + p2[1] + ymargin, 0, 0); } this->HighlightSource->Update(); this->HighlightActor->VisibilityOn(); } return position; } int vtkParallelCoordinatesView::SetAxisHighlightPosition( vtkParallelCoordinatesRepresentation* rep, double position) { int nearestPosition = rep->GetPositionNearXCoordinate(position); return this->SetAxisHighlightPosition(rep, nearestPosition); } void vtkParallelCoordinatesView::SetBrushMode(int mode) { if (mode < 0 || mode >= VTK_BRUSH_MODECOUNT) { return; } else { this->BrushMode = mode; // if we made it into function mode but left early, clear the lines if (this->FirstFunctionBrushLineDrawn && this->BrushMode != VTK_BRUSH_FUNCTION) { this->FirstFunctionBrushLineDrawn = 0; this->ClearBrushPoints(); this->Render(); } } } void vtkParallelCoordinatesView::SetBrushOperator(int op) { if (op < 0 || op >= VTK_BRUSHOPERATOR_MODECOUNT) { return; } else { this->BrushOperator = op; } } void vtkParallelCoordinatesView::SetInspectMode(int mode) { if (mode < 0 || mode >= VTK_INSPECT_MODECOUNT) { return; } else { this->InspectMode = mode; if (this->InspectMode != VTK_INSPECT_MANIPULATE_AXES) { this->HighlightActor->VisibilityOff(); } } } void vtkParallelCoordinatesView::SetMaximumNumberOfBrushPoints(int num) { if (num >= 2 && num != this->MaximumNumberOfBrushPoints) { this->MaximumNumberOfBrushPoints = num; vtkSmartPointer pts = vtkSmartPointer::New(); pts->SetNumberOfPoints(4 * this->MaximumNumberOfBrushPoints); for (int i = 0; i < 4 * this->MaximumNumberOfBrushPoints; i++) pts->InsertPoint(i, -1, -1, 0); vtkSmartPointer lines = vtkSmartPointer::New(); lines->AllocateEstimate(4, this->MaximumNumberOfBrushPoints); // first line is for a manually drawn curve, for selecting lines // second line is for the spline used for angular brushing // third and fourth lines are for the splines used for function brushing for (int i = 0; i < 4; i++) { lines->InsertNextCell(this->MaximumNumberOfBrushPoints); for (int j = 0; j < this->MaximumNumberOfBrushPoints; j++) lines->InsertCellPoint(0); } this->BrushData->SetPoints(pts); this->BrushData->SetLines(lines); } } void vtkParallelCoordinatesView::ClearBrushPoints() { this->NumberOfBrushPoints = 0; vtkIdType npts = this->BrushData->GetPoints()->GetNumberOfPoints(); for (vtkIdType i = 0; i < npts; i++) this->BrushData->GetPoints()->SetPoint(i, -1, -1, 0); // clear them for all of the lines vtkNew cell; auto cellIter = vtk::TakeSmartPointer(this->BrushData->GetLines()->NewIterator()); for (cellIter->GoToFirstCell(); !cellIter->IsDoneWithTraversal(); cellIter->GoToNextCell()) { const vtkIdType cellNum = cellIter->GetCurrentCellId(); cellIter->GetCurrentCell(cell); for (vtkIdType j = 0; j < cell->GetNumberOfIds(); j++) { cell->SetId(j, cellNum * this->MaximumNumberOfBrushPoints); } cellIter->ReplaceCurrentCell(cell); } this->BrushData->Modified(); } //------------------------------------------------------------------------------ int vtkParallelCoordinatesView::AddLassoBrushPoint(double* p) { if (this->NumberOfBrushPoints >= this->MaximumNumberOfBrushPoints) return 0; vtkIdType ptid = this->NumberOfBrushPoints; this->BrushData->GetPoints()->SetPoint(ptid, p[0], p[1], 0); const vtkIdType npts = this->BrushData->GetLines()->GetCellSize(0); std::vector ptids(static_cast(npts)); for (vtkIdType i = ptid; i < npts; i++) { ptids[static_cast(i)] = ptid; } this->BrushData->GetLines()->ReplaceCellAtId(0, npts, ptids.data()); this->NumberOfBrushPoints++; this->BrushData->Modified(); return 1; } //------------------------------------------------------------------------------ int vtkParallelCoordinatesView::SetAngleBrushLine(double* p1, double* p2) { this->SetBrushLine(1, p1, p2); return 1; } //------------------------------------------------------------------------------ int vtkParallelCoordinatesView::SetFunctionBrushLine1(double* p1, double* p2) { this->SetBrushLine(2, p1, p2); return 1; } //------------------------------------------------------------------------------ int vtkParallelCoordinatesView::SetFunctionBrushLine2(double* p1, double* p2) { this->SetBrushLine(3, p1, p2); return 1; } //------------------------------------------------------------------------------ int vtkParallelCoordinatesView::SetBrushLine(int line, double* p1, double* p2) { double p1x = p1[0], p1y = p1[1]; double p2x = p2[0], p2y = p2[1]; vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); int numAxes = rep->GetNumberOfAxes(); double* xs = new double[numAxes]; rep->GetXCoordinatesOfPositions(xs); if (p1x == p2x) { delete[] xs; return 0; } // swap, if necessary...I don't think the splines like being out of order if (p1x > p2x) { double tmp; tmp = p1x; p1x = p2x; p2x = tmp; tmp = p1y; p1y = p2y; p2y = tmp; } // find the axis to the left of p1 int left = numAxes - 1; for (int i = 0; i < numAxes; i++) { if (p1x > xs[i]) { left = i; } else { break; } } int right = left + 1; // sanity check if (right >= numAxes || left < 0) { delete[] xs; return 0; } // find the points that line (p1-p2) intersects on the left/right axes double m = (double)(p2y - p1y) / (double)(p2x - p1x); double lefty = p1y - m * (p1x - xs[left]); double righty = p1y - m * (p1x - xs[right]); p1x = xs[left]; p2x = xs[right]; p1y = lefty; p2y = righty; // p1y = std::max(std::min(lefty,this->YMax),this->YMin); // p2y = std::max(std::min(righty,this->YMax),this->YMin); // sanity check if (p1x >= p2x) { delete[] xs; return 0; } int pointOffset = line * this->MaximumNumberOfBrushPoints; double dx = (double)(p2x - p1x) / (this->MaximumNumberOfBrushPoints - 1); if (!rep->GetUseCurves()) { double dy = (double)(p2y - p1y) / (this->MaximumNumberOfBrushPoints - 1); for (int i = 0; i < this->MaximumNumberOfBrushPoints; i++) { this->BrushData->GetPoints()->SetPoint(pointOffset + i, p1x + i * dx, p1y + i * dy, 0); } } else { vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetParametricRange(p1x, p2x); spline->AddPoint(p1x, p1y); spline->AddPoint(p2x, p2y); for (int i = 0; i < this->MaximumNumberOfBrushPoints; i++) { this->BrushData->GetPoints()->SetPoint( pointOffset + i, p1x + (double)i * dx, spline->Evaluate(p1x + (double)i * dx), 0); } } vtkNew cell; this->BrushData->GetLines()->GetCellAtId(line, cell); for (vtkIdType j = 0; j < cell->GetNumberOfIds(); j++) { cell->SetId(j, pointOffset + j); } this->BrushData->GetLines()->ReplaceCellAtId(line, cell); this->BrushData->Modified(); delete[] xs; return 1; } //------------------------------------------------------------------------------ void vtkParallelCoordinatesView::GetBrushLine(int line, vtkIdType& npts, vtkIdType const*& ptids) { int cellNum = 0; for (this->BrushData->GetLines()->InitTraversal(); this->BrushData->GetLines()->GetNextCell(npts, ptids); cellNum++) { if (cellNum == line) { return; } } } void vtkParallelCoordinatesView::Hover(unsigned long eventId) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); double p1[2], p2[2]; if (!rep->GetPositionAndSize(p1, p2)) return; double cursorPosition[2] = { 0, 0 }; style->GetCursorCurrentPosition(this->GetRenderer(), cursorPosition); // deal with hovering if (this->InspectMode == VTK_INSPECT_MANIPULATE_AXES && eventId == vtkCommand::InteractionEvent) { // if we're close to the representation if (cursorPosition[0] >= 0.0 && cursorPosition[0] <= 1.0 && cursorPosition[1] >= 0.0 && cursorPosition[1] <= 1.0 && cursorPosition[0] > p1[0] - .05 * p2[0] && cursorPosition[0] < p1[0] + 1.05 * p2[0]) { this->SelectedAxisPosition = rep->GetPositionNearXCoordinate(cursorPosition[0]); double xpos = rep->GetXCoordinateOfPosition(this->SelectedAxisPosition); if (fabs(xpos - cursorPosition[0]) > .05) { this->SelectedAxisPosition = -1; } else if (cursorPosition[1] < p1[1] + .05 * p2[1]) { this->AxisHighlightPosition = VTK_HIGHLIGHT_MIN; } else if (cursorPosition[1] > p1[1] + .95 * p2[1]) { this->AxisHighlightPosition = VTK_HIGHLIGHT_MAX; } else { this->AxisHighlightPosition = VTK_HIGHLIGHT_CENTER; } this->SetAxisHighlightPosition(rep, this->SelectedAxisPosition); } else { this->SelectedAxisPosition = -1; this->SetAxisHighlightPosition(rep, this->SelectedAxisPosition); } } } void vtkParallelCoordinatesView::ManipulateAxes(unsigned long eventId) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); double cursorPosition[2], cursorLastPosition[2], cursorStartPosition[2]; style->GetCursorCurrentPosition(this->GetRenderer(), cursorPosition); style->GetCursorLastPosition(this->GetRenderer(), cursorLastPosition); style->GetCursorStartPosition(this->GetRenderer(), cursorStartPosition); double dx = cursorPosition[0] - cursorLastPosition[0]; double dy = cursorPosition[1] - cursorLastPosition[1]; if (eventId == vtkCommand::StartInteractionEvent) { } else if (eventId == vtkCommand::InteractionEvent) { if (this->SelectedAxisPosition >= 0) { if (AxisHighlightPosition == VTK_HIGHLIGHT_CENTER) { double xpos = rep->GetXCoordinateOfPosition(this->SelectedAxisPosition); this->SelectedAxisPosition = rep->SetXCoordinateOfPosition(this->SelectedAxisPosition, xpos + dx); this->SetAxisHighlightPosition(rep, this->SelectedAxisPosition); } else { double range[] = { 0.0, 0.0 }; rep->GetRangeAtPosition(this->SelectedAxisPosition, range); if (AxisHighlightPosition == VTK_HIGHLIGHT_MAX) { range[1] += dy * (range[1] - range[0]); } else if (AxisHighlightPosition == VTK_HIGHLIGHT_MIN) { range[0] += dy * (range[1] - range[0]); } rep->SetRangeAtPosition(this->SelectedAxisPosition, range); } } } else if (eventId == vtkCommand::EndInteractionEvent) { this->SelectedAxisPosition = -1; } } void vtkParallelCoordinatesView::SelectData(unsigned long eventId) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); double cursorPosition[2], cursorStartPosition[2]; style->GetCursorCurrentPosition(this->GetRenderer(), cursorPosition); style->GetCursorStartPosition(this->GetRenderer(), cursorStartPosition); // in lasso mode, the user sketches a curve. Lines that are // near that curve are selected. if (this->BrushMode == VTK_BRUSH_LASSO) { if (eventId == vtkCommand::StartInteractionEvent) { this->AddLassoBrushPoint(cursorPosition); } else if (eventId == vtkCommand::InteractionEvent) { this->AddLassoBrushPoint(cursorPosition); } else if (eventId == vtkCommand::EndInteractionEvent) { const vtkIdType* ptids; vtkIdType npts; this->BrushData->GetLines()->GetCellAtId(0, npts, ptids); vtkSmartPointer pts = vtkSmartPointer::New(); for (int i = 0; i < npts; i++) { pts->InsertNextPoint(this->BrushData->GetPoints()->GetPoint(ptids[i])); } rep->LassoSelect(this->CurrentBrushClass, this->BrushOperator, pts); /* vtkSmartPointer locs = vtkSmartPointer::New(); locs->SetNumberOfComponents(2); locs->SetNumberOfTuples(this->NumberOfBrushPoints); for (int i=0; iNumberOfBrushPoints; i++) { locs->SetTuple(i,this->BrushData->GetPoints()->GetPoint(ptids[i])); } // generate a selection based on the lasso points vtkSmartPointer sel = vtkSmartPointer::New(); vtkSmartPointer node = vtkSmartPointer::New(); node->SetSelectionOperator(this->BrushOperator); node->SetSelectionIndex(this->CurrentBrushClass); node->SetContentType(vtkSelectionNode::LOCATIONS); node->SetFieldType(vtkSelectionNode::ROW); node->SetSelectionList(locs); sel->AddNode(node); rep->Select(this,sel); */ this->ClearBrushPoints(); } } // in angle brush mode, the user clicks one point to start the // line. the cursor position is the second endpoint of the line. else if (this->BrushMode == VTK_BRUSH_ANGLE) { if (eventId == vtkCommand::StartInteractionEvent || eventId == vtkCommand::InteractionEvent) { this->SetAngleBrushLine(cursorStartPosition, cursorPosition); } else if (eventId == vtkCommand::EndInteractionEvent) { const vtkIdType* ptids = nullptr; vtkIdType npts = 0; this->GetBrushLine(1, npts, ptids); double p1[3] = { 0, 0, 0 }; double p2[3] = { 0, 0, 0 }; this->BrushData->GetPoints()->GetPoint(ptids[0], p1); this->BrushData->GetPoints()->GetPoint(ptids[npts - 1], p2); rep->AngleSelect(this->CurrentBrushClass, this->BrushOperator, p1, p2); /* vtkSmartPointer locs = vtkSmartPointer::New(); locs->SetNumberOfComponents(2); locs->SetNumberOfTuples(2); locs->SetTuple(0,p1); locs->SetTuple(1,p2); // generate a selection based on the angle brush points vtkSmartPointer sel = vtkSmartPointer::New(); vtkSmartPointer node = vtkSmartPointer::New(); node->SetSelectionOperator(this->BrushOperator); node->SetSelectionIndex(this->CurrentBrushClass); node->SetContentType(vtkParallelCoordinatesSelectionNode::ANGLE_LOCATIONS); node->SetFieldType(vtkSelectionNode::ROW); node->SetSelectionList(locs); sel->AddNode(node); rep->Select(this,sel); */ this->ClearBrushPoints(); } } // same as angle mode, but do two of them. else if (this->BrushMode == VTK_BRUSH_FUNCTION) { if (eventId == vtkCommand::StartInteractionEvent || eventId == vtkCommand::InteractionEvent) { if (!this->FirstFunctionBrushLineDrawn) { this->SetFunctionBrushLine1(cursorStartPosition, cursorPosition); } else { this->SetFunctionBrushLine2(cursorStartPosition, cursorPosition); } } else if (eventId == vtkCommand::EndInteractionEvent) { // if the first line isn't finished, keep going with the second. if (!this->FirstFunctionBrushLineDrawn) { this->FirstFunctionBrushLineDrawn = 1; } // the first line is finished, so do the selection else { const vtkIdType* ptids = nullptr; vtkIdType npts = 0; double p1[3] = { 0, 0, 0 }; double p2[3] = { 0, 0, 0 }; this->GetBrushLine(2, npts, ptids); this->BrushData->GetPoints()->GetPoint(ptids[0], p1); this->BrushData->GetPoints()->GetPoint(ptids[npts - 1], p2); double q1[3] = { 0, 0, 0 }; double q2[3] = { 0, 0, 0 }; this->GetBrushLine(3, npts, ptids); this->BrushData->GetPoints()->GetPoint(ptids[0], q1); this->BrushData->GetPoints()->GetPoint(ptids[npts - 1], q2); rep->FunctionSelect(this->CurrentBrushClass, this->BrushOperator, p1, p2, q1, q2); /* vtkSmartPointer locs = vtkSmartPointer::New(); locs->SetNumberOfComponents(2); locs->SetNumberOfTuples(4); locs->SetTuple(0,p1); locs->SetTuple(1,p2); locs->SetTuple(2,q1); locs->SetTuple(3,q2); // generate a selection based on the angle brush points vtkSmartPointer sel = vtkSmartPointer::New(); vtkSmartPointer node = vtkSmartPointer::New(); node->SetSelectionOperator(this->BrushOperator); node->SetSelectionIndex(this->CurrentBrushClass); node->SetContentType(vtkParallelCoordinatesSelectionNode::FUNCTION_LOCATIONS); node->SetFieldType(vtkSelectionNode::ROW); node->SetSelectionList(locs); sel->AddNode(node); rep->Select(this,sel); */ this->FirstFunctionBrushLineDrawn = 0; this->ClearBrushPoints(); } } } else if (this->BrushMode == VTK_BRUSH_AXISTHRESHOLD) { } } void vtkParallelCoordinatesView::Zoom(unsigned long eventId) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); double p1[2], size[2], p2[2]; rep->GetPositionAndSize(p1, size); p2[0] = p1[0] + size[0]; p2[1] = p1[1] + size[1]; double cursorPosition[2], cursorLastPosition[2], cursorStartPosition[2]; style->GetCursorCurrentPosition(this->GetRenderer(), cursorPosition); style->GetCursorLastPosition(this->GetRenderer(), cursorLastPosition); style->GetCursorStartPosition(this->GetRenderer(), cursorStartPosition); double v1[2] = { cursorStartPosition[0] - p1[0], cursorStartPosition[1] - p1[1] }; double v2[2] = { cursorStartPosition[0] - p2[0], cursorStartPosition[1] - p2[1] }; double dy = -(cursorPosition[1] - cursorLastPosition[1]); if (eventId == vtkCommand::StartInteractionEvent) { } else if (eventId == vtkCommand::InteractionEvent) { double p1new[2] = { p1[0] + dy * v1[0], p1[1] + dy * v1[1] }; double p2new[2] = { p2[0] + dy * v2[0], // - p1new[0], p2[1] + dy * v2[1] }; // - p1new[1]}; double sizenew[] = { p2new[0] - p1new[0], p2new[1] - p1new[1] }; rep->SetPositionAndSize(p1new, sizenew); this->SetAxisHighlightPosition(rep, this->SelectedAxisPosition); } else if (eventId == vtkCommand::EndInteractionEvent) { } } void vtkParallelCoordinatesView::Pan(unsigned long eventId) { vtkParallelCoordinatesInteractorStyle* style = vtkParallelCoordinatesInteractorStyle::SafeDownCast(this->GetInteractorStyle()); vtkParallelCoordinatesRepresentation* rep = vtkParallelCoordinatesRepresentation::SafeDownCast(this->GetRepresentation()); double p1[2], size[2], p2[2]; rep->GetPositionAndSize(p1, size); p2[0] = p1[0] + size[0]; p2[1] = p1[1] + size[1]; double cursorPosition[2], cursorLastPosition[2], cursorStartPosition[2]; style->GetCursorCurrentPosition(this->GetRenderer(), cursorPosition); style->GetCursorLastPosition(this->GetRenderer(), cursorLastPosition); style->GetCursorStartPosition(this->GetRenderer(), cursorStartPosition); double dx = cursorPosition[0] - cursorLastPosition[0]; double dy = cursorPosition[1] - cursorLastPosition[1]; if (eventId == vtkCommand::StartInteractionEvent) { } else if (eventId == vtkCommand::InteractionEvent) { double p1new[2] = { p1[0] + dx, p1[1] + dy }; double p2new[2] = { p2[0] + dx, p2[1] + dy }; double sizenew[] = { p2new[0] - p1new[0], p2new[1] - p1new[1] }; rep->SetPositionAndSize(p1new, sizenew); this->SetAxisHighlightPosition(rep, this->SelectedAxisPosition); } else if (eventId == vtkCommand::EndInteractionEvent) { } } void vtkParallelCoordinatesView::ApplyViewTheme(vtkViewTheme* theme) { this->Superclass::ApplyViewTheme(theme); this->Balloon->GetFrameProperty()->SetColor(theme->GetBackgroundColor()); // CellColor()); this->Balloon->GetTextProperty()->SetColor(theme->GetCellColor()); // BackgroundColor()); }