/*========================================================================= Program: Visualization Toolkit Module: vtkCenteredSliderRepresentation.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 "vtkCenteredSliderRepresentation.h" #include "vtkActor2D.h" #include "vtkCellArray.h" #include "vtkCommand.h" #include "vtkEvent.h" #include "vtkInteractorObserver.h" #include "vtkLine.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper2D.h" #include "vtkProperty2D.h" #include "vtkRenderer.h" #include "vtkSmartPointer.h" #include "vtkTextActor.h" #include "vtkTextMapper.h" #include "vtkTextProperty.h" #include "vtkTransform.h" #include "vtkTransformPolyDataFilter.h" #include "vtkUnsignedCharArray.h" #include "vtkWindow.h" vtkStandardNewMacro(vtkCenteredSliderRepresentation); //------------------------------------------------------------------------------ vtkCenteredSliderRepresentation::vtkCenteredSliderRepresentation() { // The coordinates defining the slider this->Point1Coordinate = vtkCoordinate::New(); this->Point1Coordinate->SetCoordinateSystemToNormalizedViewport(); this->Point1Coordinate->SetValue(0.95, 0.8, 0.0); this->Point2Coordinate = vtkCoordinate::New(); this->Point2Coordinate->SetCoordinateSystemToNormalizedViewport(); this->Point2Coordinate->SetValue(0.99, 0.98, 0.0); // Default configuration this->ButtonSize = 0.08; this->TubeSize = 0.85; // includes buttons this->ArcCount = 31; this->ArcStart = 1.0 - this->TubeSize + this->ButtonSize; this->ArcEnd = 1.0 - this->ButtonSize; // The points and the transformation for the points. this->XForm = vtkTransform::New(); this->Points = vtkPoints::New(); this->Points->SetNumberOfPoints(2 * this->ArcCount + 12); this->TubeCells = nullptr; this->Tube = nullptr; this->BuildTube(); this->TubeXForm = vtkTransformPolyDataFilter::New(); this->TubeXForm->SetInputData(this->Tube); this->TubeXForm->SetTransform(this->XForm); this->TubeMapper = vtkPolyDataMapper2D::New(); this->TubeMapper->SetInputConnection(this->TubeXForm->GetOutputPort()); this->TubeProperty = vtkProperty2D::New(); this->TubeProperty->SetOpacity(0.6); this->TubeActor = vtkActor2D::New(); this->TubeActor->SetMapper(this->TubeMapper); this->TubeActor->SetProperty(this->TubeProperty); this->SelectedProperty = vtkProperty2D::New(); this->SelectedProperty->SetOpacity(1.0); // The slider this->SliderCells = vtkCellArray::New(); this->SliderCells->InsertNextCell(4); this->SliderCells->InsertCellPoint(this->ArcCount * 2 + 8); this->SliderCells->InsertCellPoint(this->ArcCount * 2 + 9); this->SliderCells->InsertCellPoint(this->ArcCount * 2 + 10); this->SliderCells->InsertCellPoint(this->ArcCount * 2 + 11); this->Slider = vtkPolyData::New(); this->Slider->SetPoints(this->Points); this->Slider->SetPolys(this->SliderCells); this->SliderXForm = vtkTransformPolyDataFilter::New(); this->SliderXForm->SetInputData(this->Slider); this->SliderXForm->SetTransform(XForm); this->SliderMapper = vtkPolyDataMapper2D::New(); this->SliderMapper->SetInputConnection(this->SliderXForm->GetOutputPort()); this->SliderProperty = vtkProperty2D::New(); this->SliderProperty->SetColor(1, 1, 1); this->SliderActor = vtkActor2D::New(); this->SliderActor->SetMapper(this->SliderMapper); this->SliderActor->SetProperty(this->SliderProperty); this->LabelProperty = vtkTextProperty::New(); this->LabelProperty->SetFontFamilyToArial(); this->LabelProperty->SetJustificationToCentered(); this->LabelActor = vtkTextActor::New(); this->LabelActor->SetTextProperty(this->LabelProperty); this->LabelActor->SetInput(""); this->LabelActor->GetPositionCoordinate()->SetCoordinateSystemToViewport(); this->Value = 0; this->PickedT = 0.5; this->HighlightState = 0; } void vtkCenteredSliderRepresentation::BuildTube() { // The tube (the slider moves along the tube) // the top cap if (this->TubeCells) { this->TubeCells->Delete(); this->TubeCells = nullptr; } this->TubeCells = vtkCellArray::New(); this->TubeCells->InsertNextCell(5); this->TubeCells->InsertCellPoint(0); this->TubeCells->InsertCellPoint(1); this->TubeCells->InsertCellPoint(this->ArcCount + 4 + 1); this->TubeCells->InsertCellPoint(this->ArcCount + 4); this->TubeCells->InsertCellPoint(0); // the bottom cap this->TubeCells->InsertNextCell(5); this->TubeCells->InsertCellPoint(this->ArcCount + 2); this->TubeCells->InsertCellPoint(this->ArcCount + 3); this->TubeCells->InsertCellPoint(2 * this->ArcCount + 4 + 3); this->TubeCells->InsertCellPoint(2 * this->ArcCount + 4 + 2); this->TubeCells->InsertCellPoint(this->ArcCount + 2); for (int i = 0; i < this->ArcCount; i += 2) { this->TubeCells->InsertNextCell(4); this->TubeCells->InsertCellPoint(i + 1); this->TubeCells->InsertCellPoint(i + 2); this->TubeCells->InsertCellPoint(this->ArcCount + i + 6); this->TubeCells->InsertCellPoint(this->ArcCount + i + 5); } vtkSmartPointer colors = vtkSmartPointer::New(); colors->SetNumberOfComponents(4); colors->SetNumberOfTuples(this->ArcCount * 2 + 12); if (this->Tube) { this->Tube->Delete(); this->Tube = nullptr; } this->Tube = vtkPolyData::New(); this->Tube->SetPoints(this->Points); this->Tube->GetPointData()->SetScalars(colors); this->Tube->SetPolys(this->TubeCells); unsigned char col[4]; col[0] = 255; col[1] = 255; col[2] = 255; col[3] = 200; // build tube points this->Points->SetPoint(0, 0.0, 1.0, 0.0); this->Points->SetPoint(1, 0.0, this->ArcEnd, 0.0); this->Points->SetPoint(this->ArcCount + 2, 0.0, this->ArcStart, 0.0); this->Points->SetPoint(this->ArcCount + 3, 0.0, 1.0 - this->TubeSize, 0.0); colors->SetTypedTuple(0, col); colors->SetTypedTuple(1, col); colors->SetTypedTuple(this->ArcCount + 2, col); colors->SetTypedTuple(this->ArcCount + 3, col); this->Points->SetPoint(this->ArcCount + 4, 1.0, 1.0, 0.0); this->Points->SetPoint(this->ArcCount + 5, 1.0, this->ArcEnd, 0.0); this->Points->SetPoint(2 * this->ArcCount + 6, 1.0, this->ArcStart, 0.0); this->Points->SetPoint(2 * this->ArcCount + 7, 1.0, 1.0 - this->TubeSize, 0.0); colors->SetTypedTuple(this->ArcCount + 4, col); colors->SetTypedTuple(this->ArcCount + 5, col); colors->SetTypedTuple(2 * this->ArcCount + 6, col); colors->SetTypedTuple(2 * this->ArcCount + 7, col); // and the arc double midPoint = this->ArcCount / 2.0; double halfArcLength = (this->ArcEnd - this->ArcStart) / 2.0; for (int i = 0; i < this->ArcCount; ++i) { double factor = fabs((i - midPoint) / midPoint); factor = pow(factor, 1.4); double sign = 1; if (i < midPoint) { sign = -1; } this->Points->SetPoint( i + 2, 0.3, (1.0 - this->TubeSize / 2.0) - halfArcLength * factor * sign, 0.0); this->Points->SetPoint(i + this->ArcCount + 6, 0.7, (1.0 - this->TubeSize / 2.0) - halfArcLength * factor * sign, 0.0); col[3] = static_cast(255 * factor); colors->SetTypedTuple(i + 2, col); colors->SetTypedTuple(i + this->ArcCount + 6, col); } // last four points are the slider this->Points->SetPoint( this->ArcCount * 2 + 8, 0.0, (this->ArcStart + this->ArcEnd) / 2.0 + 0.025, 0.0); this->Points->SetPoint( this->ArcCount * 2 + 9, 0.0, (this->ArcStart + this->ArcEnd) / 2.0 - 0.025, 0.0); this->Points->SetPoint( this->ArcCount * 2 + 10, 1.0, (this->ArcStart + this->ArcEnd) / 2.0 - 0.025, 0.0); this->Points->SetPoint( this->ArcCount * 2 + 11, 1.0, (this->ArcStart + this->ArcEnd) / 2.0 + 0.025, 0.0); col[0] = 255; col[1] = 255; col[2] = 255; col[3] = 255; colors->SetTypedTuple(this->ArcCount * 2 + 8, col); colors->SetTypedTuple(this->ArcCount * 2 + 9, col); colors->SetTypedTuple(this->ArcCount * 2 + 10, col); colors->SetTypedTuple(this->ArcCount * 2 + 11, col); } //------------------------------------------------------------------------------ vtkCenteredSliderRepresentation::~vtkCenteredSliderRepresentation() { this->Point1Coordinate->Delete(); this->Point2Coordinate->Delete(); this->XForm->Delete(); this->Points->Delete(); this->SliderCells->Delete(); this->Slider->Delete(); this->SliderXForm->Delete(); this->SliderMapper->Delete(); this->SliderActor->Delete(); this->SliderProperty->Delete(); this->Tube->Delete(); this->TubeCells->Delete(); this->TubeXForm->Delete(); this->TubeMapper->Delete(); this->TubeActor->Delete(); this->TubeProperty->Delete(); this->SelectedProperty->Delete(); this->LabelProperty->Delete(); this->LabelActor->Delete(); } //------------------------------------------------------------------------------ vtkCoordinate* vtkCenteredSliderRepresentation::GetPoint1Coordinate() { return this->Point1Coordinate; } void vtkCenteredSliderRepresentation::StartWidgetInteraction(double eventPos[2]) { this->ComputeInteractionState(static_cast(eventPos[0]), static_cast(eventPos[1])); } //------------------------------------------------------------------------------ int vtkCenteredSliderRepresentation::ComputeInteractionState(int x, int y, int /*modify*/) { // where is the pick int* p1 = this->Point1Coordinate->GetComputedViewportValue(this->Renderer); int* p2 = this->Point2Coordinate->GetComputedViewportValue(this->Renderer); // convert the eventPos into parametric coordinates double pcoord[2]; if (!(p2[0] - p1[0]) || !(p2[1] - p1[1])) { this->InteractionState = vtkSliderRepresentation::Outside; return this->InteractionState; } pcoord[0] = (static_cast(x) - p1[0]) / (p2[0] - p1[0]); pcoord[1] = (static_cast(y) - p1[1]) / (p2[1] - p1[1]); if (pcoord[0] < 0 || pcoord[0] > 1.0) { this->InteractionState = vtkSliderRepresentation::Outside; return this->InteractionState; } // if it is on the slider... if (fabs(pcoord[1] - (1.0 - 0.5 * this->TubeSize)) < 0.1) { this->InteractionState = vtkSliderRepresentation::Slider; return this->InteractionState; } // if on the tube if (pcoord[1] >= this->ArcStart && pcoord[1] <= this->ArcEnd) { this->InteractionState = vtkSliderRepresentation::Tube; this->ComputePickPosition(x, y); return this->InteractionState; } // on the bottom aka left cap if (pcoord[1] >= 1.0 - this->TubeSize && pcoord[1] <= 1.0 - this->TubeSize + this->ArcStart) { this->InteractionState = vtkSliderRepresentation::LeftCap; return this->InteractionState; } // on the top aka right cap if (pcoord[1] >= this->ArcEnd && pcoord[1] <= 1.0) { this->InteractionState = vtkSliderRepresentation::RightCap; return this->InteractionState; } this->InteractionState = vtkSliderRepresentation::Outside; return this->InteractionState; } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::WidgetInteraction(double eventPos[2]) { double t = this->ComputePickPosition(eventPos[0], eventPos[1]); this->SetValue(this->MinimumValue + t * (this->MaximumValue - this->MinimumValue)); this->BuildRepresentation(); } //------------------------------------------------------------------------------ vtkCoordinate* vtkCenteredSliderRepresentation::GetPoint2Coordinate() { return this->Point2Coordinate; } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::PlaceWidget(double* vtkNotUsed(bds[6])) { // Position the handles at the end of the lines this->BuildRepresentation(); } //------------------------------------------------------------------------------ double vtkCenteredSliderRepresentation ::ComputePickPosition(double /* x */, double y) { // where is the pick int* p1 = this->Point1Coordinate->GetComputedViewportValue(this->Renderer); int* p2 = this->Point2Coordinate->GetComputedViewportValue(this->Renderer); // convert the eventPos into parametric coordinates this->PickedT = (y - p1[1]) / (p2[1] - p1[1]); this->PickedT = (this->PickedT - this->ArcStart) / (this->ArcEnd - this->ArcStart); this->PickedT = (this->PickedT < 0 ? 0.0 : (this->PickedT > 1.0 ? 1.0 : this->PickedT)); return this->PickedT; } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::Highlight(int highlight) { if (highlight) { this->SliderActor->SetProperty(this->SelectedProperty); } else { this->SliderActor->SetProperty(this->SliderProperty); } this->HighlightState = highlight; } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::BuildRepresentation() { if (this->GetMTime() <= this->BuildTime && (!this->Renderer || !this->Renderer->GetVTKWindow() || this->Renderer->GetVTKWindow()->GetMTime() <= this->BuildTime)) { return; } const int* size = this->Renderer->GetSize(); if (0 == size[0] || 0 == size[1]) { // Renderer has no size yet: wait until the next // BuildRepresentation... return; } this->XForm->Identity(); // scale and position and rotate the polydata int* p1 = this->Point1Coordinate->GetComputedViewportValue(this->Renderer); int* p2 = this->Point2Coordinate->GetComputedViewportValue(this->Renderer); double xsize = p2[0] - p1[0]; double ysize = p2[1] - p1[1]; this->XForm->Translate(p1[0], p1[1], 0.0); this->XForm->Scale(xsize, ysize, 1.0); // adjust the slider position double t = (this->Value - this->MinimumValue) / (this->MaximumValue - this->MinimumValue); double pos = this->ArcStart + t * (this->ArcEnd - this->ArcStart); this->Points->SetPoint(this->ArcCount * 2 + 8, 0.0, pos - 0.025, 0.0); this->Points->SetPoint(this->ArcCount * 2 + 9, 0.0, pos + 0.025, 0.0); this->Points->SetPoint(this->ArcCount * 2 + 10, 1.0, pos + 0.025, 0.0); this->Points->SetPoint(this->ArcCount * 2 + 11, 1.0, pos - 0.025, 0.0); this->LabelActor->SetPosition(p1[0] + xsize * 0.5, p1[1]); this->LabelProperty->SetFontSize(static_cast(xsize * 0.8)); this->BuildTime.Modified(); } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::GetActors(vtkPropCollection* pc) { pc->AddItem(this->TubeActor); pc->AddItem(this->SliderActor); pc->AddItem(this->LabelActor); } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::ReleaseGraphicsResources(vtkWindow* w) { this->TubeActor->ReleaseGraphicsResources(w); this->LabelActor->ReleaseGraphicsResources(w); this->SliderActor->ReleaseGraphicsResources(w); } //------------------------------------------------------------------------------ int vtkCenteredSliderRepresentation::RenderOpaqueGeometry(vtkViewport* viewport) { this->BuildRepresentation(); int count = this->TubeActor->RenderOpaqueGeometry(viewport); count += this->SliderActor->RenderOpaqueGeometry(viewport); if (this->HighlightState && strlen(this->LabelActor->GetInput())) { count += this->LabelActor->RenderOpaqueGeometry(viewport); } return count; } //------------------------------------------------------------------------------ int vtkCenteredSliderRepresentation::RenderOverlay(vtkViewport* viewport) { this->BuildRepresentation(); int count = this->TubeActor->RenderOverlay(viewport); count += this->SliderActor->RenderOverlay(viewport); if (this->HighlightState && strlen(this->LabelActor->GetInput())) { count += this->LabelActor->RenderOverlay(viewport); } return count; } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::PrintSelf(ostream& os, vtkIndent indent) { // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h this->Superclass::PrintSelf(os, indent); os << indent << "Point1 Coordinate: " << this->Point1Coordinate << "\n"; this->Point1Coordinate->PrintSelf(os, indent.GetNextIndent()); os << indent << "Point2 Coordinate: " << this->Point2Coordinate << "\n"; this->Point2Coordinate->PrintSelf(os, indent.GetNextIndent()); if (this->SliderProperty) { os << indent << "Slider Property:\n"; this->SliderProperty->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Slider Property: (none)\n"; } if (this->SelectedProperty) { os << indent << "SelectedProperty:\n"; this->SelectedProperty->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "SelectedProperty: (none)\n"; } if (this->TubeProperty) { os << indent << "TubeProperty:\n"; this->TubeProperty->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "TubeProperty: (none)\n"; } if (this->SelectedProperty) { os << indent << "SelectedProperty:\n"; this->SelectedProperty->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "SelectedProperty: (none)\n"; } if (this->LabelProperty) { os << indent << "LabelProperty:\n"; this->LabelProperty->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "LabelProperty: (none)\n"; } } //------------------------------------------------------------------------------ void vtkCenteredSliderRepresentation::SetTitleText(const char* label) { this->LabelActor->SetInput(label); if (this->LabelActor->GetMTime() > this->GetMTime()) { this->Modified(); } } //------------------------------------------------------------------------------ const char* vtkCenteredSliderRepresentation::GetTitleText() { return this->LabelActor->GetInput(); }