/*========================================================================= Program: Visualization Toolkit Module: vtkRectilinearWipeRepresentation.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 "vtkRectilinearWipeRepresentation.h" #include "vtkActor2D.h" #include "vtkCellArray.h" #include "vtkCoordinate.h" #include "vtkDoubleArray.h" #include "vtkImageActor.h" #include "vtkImageData.h" #include "vtkImageRectilinearWipe.h" #include "vtkInteractorObserver.h" #include "vtkLine.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPoints.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper2D.h" #include "vtkProperty2D.h" #include "vtkRenderer.h" vtkStandardNewMacro(vtkRectilinearWipeRepresentation); vtkCxxSetObjectMacro(vtkRectilinearWipeRepresentation, RectilinearWipe, vtkImageRectilinearWipe); vtkCxxSetObjectMacro(vtkRectilinearWipeRepresentation, ImageActor, vtkImageActor); //------------------------------------------------------------------------------ vtkRectilinearWipeRepresentation::vtkRectilinearWipeRepresentation() { this->RectilinearWipe = nullptr; this->ImageActor = nullptr; this->InteractionState = vtkRectilinearWipeRepresentation::Outside; this->Tolerance = 5; // pick tolerance in pixels this->Property = vtkProperty2D::New(); this->Property->SetColor(1, 0, 0); this->Points = vtkPoints::New(); this->Points->SetDataTypeToDouble(); this->Points->SetNumberOfPoints(9); this->ActiveParts = -1; // indicates that the widget is uninitialized this->Lines = vtkCellArray::New(); this->Lines->AllocateEstimate(8, 2); this->Wipe = vtkPolyData::New(); this->Wipe->SetPoints(this->Points); this->Wipe->SetLines(this->Lines); vtkCoordinate* coordinate = vtkCoordinate::New(); coordinate->SetCoordinateSystemToWorld(); this->WipeMapper = vtkPolyDataMapper2D::New(); this->WipeMapper->SetInputData(this->Wipe); this->WipeMapper->SetTransformCoordinate(coordinate); coordinate->Delete(); this->WipeActor = vtkActor2D::New(); this->WipeActor->SetMapper(this->WipeMapper); this->WipeActor->SetProperty(this->Property); } //------------------------------------------------------------------------------ vtkRectilinearWipeRepresentation::~vtkRectilinearWipeRepresentation() { if (this->RectilinearWipe) { this->RectilinearWipe->Delete(); } if (this->ImageActor) { this->ImageActor->Delete(); } this->Points->Delete(); this->Lines->Delete(); this->Wipe->Delete(); this->WipeMapper->Delete(); this->WipeActor->Delete(); this->Property->Delete(); } //------------------------------------------------------------------------------ int vtkRectilinearWipeRepresentation::ComputeInteractionState(int X, int Y, int vtkNotUsed(modify)) { this->InteractionState = vtkRectilinearWipeRepresentation::Outside; // Check if the widget is initialized, ie BuildRepresentation has been // invoked at least once if (this->ActiveParts != -1) { // Start by grabbing the five points that define the horizontal and vertical // panes, plus the center point double* pts = static_cast(this->Points->GetData())->GetPointer(0); double* p4 = pts + 3 * 4; double* p5 = pts + 3 * 5; double* p6 = pts + 3 * 6; double* p7 = pts + 3 * 7; double* p8 = pts + 3 * 8; vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, p4[0], p4[1], p4[2], this->DP4); vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, p5[0], p5[1], p5[2], this->DP5); vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, p6[0], p6[1], p6[2], this->DP6); vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, p7[0], p7[1], p7[2], this->DP7); vtkInteractorObserver::ComputeWorldToDisplay(this->Renderer, p8[0], p8[1], p8[2], this->DP8); // Compare the distance between the current event position and the widget double xyz[3], t, closest[3]; xyz[0] = X; xyz[1] = Y; xyz[2] = this->DP4[2] = this->DP5[2] = this->DP6[2] = this->DP7[2] = this->DP8[2] = 0.0; double tol = this->Tolerance * this->Tolerance; if ((this->ActiveParts & 16) && vtkMath::Distance2BetweenPoints(xyz, this->DP8) <= tol) { this->InteractionState = vtkRectilinearWipeRepresentation::MovingCenter; } else if ((this->ActiveParts & 1) && vtkLine::DistanceToLine(xyz, this->DP8, this->DP4, t, closest) <= tol) { this->InteractionState = vtkRectilinearWipeRepresentation::MovingVPane; } else if ((this->ActiveParts & 2) && vtkLine::DistanceToLine(xyz, this->DP8, this->DP5, t, closest) <= tol) { this->InteractionState = vtkRectilinearWipeRepresentation::MovingHPane; } else if ((this->ActiveParts & 4) && vtkLine::DistanceToLine(xyz, this->DP8, this->DP6, t, closest) <= tol) { this->InteractionState = vtkRectilinearWipeRepresentation::MovingVPane; } else if ((this->ActiveParts & 8) && vtkLine::DistanceToLine(xyz, this->DP8, this->DP7, t, closest) <= tol) { this->InteractionState = vtkRectilinearWipeRepresentation::MovingHPane; } } return this->InteractionState; } //------------------------------------------------------------------------------ // Record the current event position, and the rectilinear wipe position. void vtkRectilinearWipeRepresentation::StartWidgetInteraction(double startEventPos[2]) { this->StartEventPosition[0] = startEventPos[0]; this->StartEventPosition[1] = startEventPos[1]; if (!this->RectilinearWipe) { return; } int pos[2]; this->RectilinearWipe->GetPosition(pos); this->StartWipePosition[0] = static_cast(pos[0]); this->StartWipePosition[1] = static_cast(pos[1]); } //------------------------------------------------------------------------------ // Based on the displacement vector (computed in display coordinates) and // the cursor state (which corresponds to which part of the widget has been // selected), the widget points are modified. // First construct a local coordinate system based on the display coordinates // of the widget. void vtkRectilinearWipeRepresentation::WidgetInteraction(double newEventPos[2]) { int i; double v75[3], v46[3]; for (i = 0; i < 3; i++) { v75[i] = this->DP5[i] - this->DP7[i]; v46[i] = this->DP6[i] - this->DP4[i]; } double l75 = vtkMath::Normalize(v75); double l46 = vtkMath::Normalize(v46); double xPixels = this->Dims[this->I] * (v75[0] * (newEventPos[0] - this->StartEventPosition[0]) + v75[1] * (newEventPos[1] - this->StartEventPosition[1])) / l75; double yPixels = this->Dims[this->J] * (v46[0] * (newEventPos[0] - this->StartEventPosition[0]) + v46[1] * (newEventPos[1] - this->StartEventPosition[1])) / l46; int newPosition[2]; newPosition[0] = static_cast(this->StartWipePosition[0]); newPosition[1] = static_cast(this->StartWipePosition[1]); switch (this->InteractionState) { case MovingVPane: newPosition[0] += static_cast(xPixels + 0.5); break; case MovingHPane: newPosition[1] += static_cast(yPixels + 0.5); break; case MovingCenter: newPosition[0] += static_cast(xPixels + 0.5); newPosition[1] += static_cast(yPixels + 0.5); } newPosition[0] = (newPosition[0] < 0 ? 0 : newPosition[0]); newPosition[0] = (newPosition[0] >= this->Dims[this->I] ? this->Dims[this->I] - 1 : newPosition[0]); newPosition[1] = (newPosition[1] < 0 ? 0 : newPosition[1]); newPosition[1] = (newPosition[1] >= this->Dims[this->J] ? this->Dims[this->J] - 1 : newPosition[1]); this->RectilinearWipe->SetPosition(newPosition); // Rebuild the widget based on the change this->BuildRepresentation(); } //------------------------------------------------------------------------------ void vtkRectilinearWipeRepresentation::BuildRepresentation() { if (!this->RectilinearWipe || !this->ImageActor) { vtkWarningMacro(<< "Must define both image rectilinear wipe and image actor"); return; } // get the necessary image information double bounds[6], o[3], sp[3]; int pos[2]; vtkImageData* image = this->ImageActor->GetInput(); image->GetBounds(bounds); image->GetDimensions(this->Dims); image->GetOrigin(o); image->GetSpacing(sp); this->RectilinearWipe->GetPosition(pos); // define the geometry double s, t; double t0 = bounds[1] - bounds[0]; double t1 = bounds[3] - bounds[2]; double t2 = bounds[5] - bounds[4]; int orthoAxis = (t0 < t1 ? (t0 < t2 ? 0 : 2) : (t1 < t2 ? 1 : 2)); double p0[3], p1[3], p2[3], p3[3]; if (orthoAxis == 0) // x-axis { this->I = 1; this->J = 2; s = static_cast(pos[0] + 0.5) / (this->Dims[1] - 1); t = static_cast(pos[1] + 0.5) / (this->Dims[2] - 1); p0[0] = bounds[0]; p0[1] = bounds[2]; p0[2] = bounds[4]; p1[0] = bounds[0]; p1[1] = bounds[3]; p1[2] = bounds[4]; p2[0] = bounds[0]; p2[1] = bounds[3]; p2[2] = bounds[5]; p3[0] = bounds[0]; p3[1] = bounds[2]; p3[2] = bounds[5]; this->Points->SetPoint(8, bounds[0], p0[1] + s * (p1[1] - p0[1]), p1[2] + t * (p2[2] - p1[2])); } else if (orthoAxis == 1) // y-axis { this->I = 0; this->J = 2; s = static_cast(pos[0] + 0.5) / (this->Dims[0] - 1); t = static_cast(pos[1] + 0.5) / (this->Dims[2] - 1); p0[0] = bounds[0]; p0[1] = bounds[2]; p0[2] = bounds[4]; p1[0] = bounds[1]; p1[1] = bounds[2]; p1[2] = bounds[4]; p2[0] = bounds[1]; p2[1] = bounds[2]; p2[2] = bounds[5]; p3[0] = bounds[0]; p3[1] = bounds[2]; p3[2] = bounds[5]; this->Points->SetPoint(8, p0[0] + s * (p1[0] - p0[0]), bounds[2], p1[2] + t * (p2[2] - p1[2])); } else // if( orthoAxis == 2 ) //z-axis { this->I = 0; this->J = 1; s = static_cast(pos[0] + 0.5) / (this->Dims[0] - 1); t = static_cast(pos[1] + 0.5) / (this->Dims[1] - 1); p0[0] = bounds[0]; p0[1] = bounds[2]; p0[2] = bounds[4]; p1[0] = bounds[1]; p1[1] = bounds[2]; p1[2] = bounds[4]; p2[0] = bounds[1]; p2[1] = bounds[3]; p2[2] = bounds[4]; p3[0] = bounds[0]; p3[1] = bounds[3]; p3[2] = bounds[4]; this->Points->SetPoint(8, p0[0] + s * (p1[0] - p0[0]), p1[1] + t * (p2[1] - p1[1]), bounds[4]); } // corners this->Points->SetPoint(0, p0); this->Points->SetPoint(1, p1); this->Points->SetPoint(2, p2); this->Points->SetPoint(3, p3); // mid-edge this->Points->SetPoint( 4, p0[0] + s * (p1[0] - p0[0]), p0[1] + s * (p1[1] - p0[1]), p0[2] + s * (p1[2] - p0[2])); this->Points->SetPoint( 5, p1[0] + t * (p2[0] - p1[0]), p1[1] + t * (p2[1] - p1[1]), p1[2] + t * (p2[2] - p1[2])); this->Points->SetPoint( 6, p3[0] + s * (p2[0] - p3[0]), p3[1] + s * (p2[1] - p3[1]), p3[2] + s * (p2[2] - p3[2])); this->Points->SetPoint( 7, p0[0] + t * (p3[0] - p0[0]), p0[1] + t * (p3[1] - p0[1]), p0[2] + t * (p3[2] - p0[2])); this->Points->Modified(); // Define the lines this->Lines->Reset(); this->Lines->InsertNextCell(5); this->Lines->InsertCellPoint(0); this->Lines->InsertCellPoint(1); this->Lines->InsertCellPoint(2); this->Lines->InsertCellPoint(3); this->Lines->InsertCellPoint(0); int wipe = this->RectilinearWipe->GetWipe(); this->ActiveParts = 0; if (wipe == VTK_WIPE_QUAD) { this->ActiveParts |= 1; // activate center to bottom edge this->ActiveParts |= 2; // activate center to right edge this->ActiveParts |= 4; // activate center to top edge this->ActiveParts |= 8; // activate center to left edge this->ActiveParts |= 16; // activate center point this->Lines->InsertNextCell(2); this->Lines->InsertCellPoint(4); this->Lines->InsertCellPoint(6); this->Lines->InsertNextCell(2); this->Lines->InsertCellPoint(5); this->Lines->InsertCellPoint(7); } else if (wipe == VTK_WIPE_VERTICAL) { this->ActiveParts |= 2; this->ActiveParts |= 8; this->Lines->InsertNextCell(2); this->Lines->InsertCellPoint(5); this->Lines->InsertCellPoint(7); } else if (wipe == VTK_WIPE_HORIZONTAL) { this->ActiveParts |= 1; this->ActiveParts |= 4; this->Lines->InsertNextCell(2); this->Lines->InsertCellPoint(4); this->Lines->InsertCellPoint(6); } else if (wipe == VTK_WIPE_LOWER_LEFT) { this->ActiveParts |= 1; this->ActiveParts |= 8; this->ActiveParts |= 16; this->Lines->InsertNextCell(3); this->Lines->InsertCellPoint(4); this->Lines->InsertCellPoint(8); this->Lines->InsertCellPoint(7); } else if (wipe == VTK_WIPE_LOWER_RIGHT) { this->ActiveParts |= 1; this->ActiveParts |= 2; this->ActiveParts |= 16; this->Lines->InsertNextCell(3); this->Lines->InsertCellPoint(4); this->Lines->InsertCellPoint(8); this->Lines->InsertCellPoint(5); } else if (wipe == VTK_WIPE_UPPER_LEFT) { this->ActiveParts |= 4; this->ActiveParts |= 8; this->ActiveParts |= 16; this->Lines->InsertNextCell(3); this->Lines->InsertCellPoint(7); this->Lines->InsertCellPoint(8); this->Lines->InsertCellPoint(6); } else // if ( wipe == VTK_WIPE_UPPER_RIGHT ) { this->ActiveParts |= 2; this->ActiveParts |= 4; this->ActiveParts |= 16; this->Lines->InsertNextCell(3); this->Lines->InsertCellPoint(6); this->Lines->InsertCellPoint(8); this->Lines->InsertCellPoint(5); } } //------------------------------------------------------------------------------ void vtkRectilinearWipeRepresentation::GetActors2D(vtkPropCollection* pc) { this->WipeActor->GetActors2D(pc); } //------------------------------------------------------------------------------ void vtkRectilinearWipeRepresentation::ReleaseGraphicsResources(vtkWindow* win) { this->WipeActor->ReleaseGraphicsResources(win); } //------------------------------------------------------------------------------ int vtkRectilinearWipeRepresentation::RenderOverlay(vtkViewport* viewport) { return this->WipeActor->RenderOverlay(viewport); } //------------------------------------------------------------------------------ int vtkRectilinearWipeRepresentation::RenderOpaqueGeometry(vtkViewport* viewport) { return this->WipeActor->RenderOpaqueGeometry(viewport); } //------------------------------------------------------------------------------ int vtkRectilinearWipeRepresentation::RenderTranslucentPolygonalGeometry(vtkViewport* viewport) { return this->WipeActor->RenderTranslucentPolygonalGeometry(viewport); } //------------------------------------------------------------------------------ vtkTypeBool vtkRectilinearWipeRepresentation::HasTranslucentPolygonalGeometry() { return this->WipeActor->HasTranslucentPolygonalGeometry(); } //------------------------------------------------------------------------------ void vtkRectilinearWipeRepresentation::PrintSelf(ostream& os, vtkIndent indent) { // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h this->Superclass::PrintSelf(os, indent); if (this->ImageActor) { os << indent << "Image Actor: " << this->ImageActor << "\n"; } else { os << indent << "Image Actor: (none)\n"; } if (this->RectilinearWipe) { os << indent << "RectilinearWipe: " << this->RectilinearWipe << "\n"; } else { os << indent << "Image RectilinearWipe: (none)\n"; } if (this->Property) { os << indent << "Property:\n"; this->Property->PrintSelf(os, indent.GetNextIndent()); } else { os << indent << "Property: (none)\n"; } os << indent << "Tolerance: " << this->Tolerance << "\n"; }