/*========================================================================= Program: Visualization Toolkit Module: vtkCamera.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 "vtkCamera.h" #include "vtkCallbackCommand.h" #include "vtkInformation.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPerspectiveTransform.h" #include "vtkRenderer.h" #include "vtkTimeStamp.h" #include "vtkTransform.h" #include #include //------------------------------------------------------------------------------ // Needed when we don't use the vtkStandardNewMacro. vtkObjectFactoryNewMacro(vtkCamera); vtkCxxSetObjectMacro(vtkCamera, Information, vtkInformation); vtkCxxSetObjectMacro(vtkCamera, EyeTransformMatrix, vtkMatrix4x4); vtkCxxSetObjectMacro(vtkCamera, ModelTransformMatrix, vtkMatrix4x4); vtkCxxSetObjectMacro(vtkCamera, ExplicitProjectionTransformMatrix, vtkMatrix4x4); //------------------------------------------------------------------------------ class vtkCameraCallbackCommand : public vtkCommand { public: static vtkCameraCallbackCommand* New() { return new vtkCameraCallbackCommand; } vtkCamera* Self; void Execute(vtkObject*, unsigned long, void*) override { if (this->Self) { this->Self->Modified(); this->Self->ComputeViewTransform(); this->Self->ComputeDistance(); this->Self->ComputeCameraLightTransform(); } } protected: vtkCameraCallbackCommand() { this->Self = nullptr; } ~vtkCameraCallbackCommand() override = default; }; //------------------------------------------------------------------------------ // Construct camera instance with its focal point at the origin, // and position=(0,0,1). The view up is along the y-axis, // view angle is 30 degrees, and the clipping range is (.1,1000). vtkCamera::vtkCamera() { this->FocalPoint[0] = 0.0; this->FocalPoint[1] = 0.0; this->FocalPoint[2] = 0.0; this->Position[0] = 0.0; this->Position[1] = 0.0; this->Position[2] = 1.0; this->ViewUp[0] = 0.0; this->ViewUp[1] = 1.0; this->ViewUp[2] = 0.0; this->DirectionOfProjection[0] = 0.0; this->DirectionOfProjection[1] = 0.0; this->DirectionOfProjection[2] = 0.0; this->ViewAngle = 30.0; this->UseHorizontalViewAngle = 0; this->UseOffAxisProjection = 0; this->ScreenBottomLeft[0] = -0.5; this->ScreenBottomLeft[1] = -0.5; this->ScreenBottomLeft[2] = -0.5; this->ScreenBottomRight[0] = 0.5; this->ScreenBottomRight[1] = -0.5; this->ScreenBottomRight[2] = -0.5; this->ScreenTopRight[0] = 0.5; this->ScreenTopRight[1] = 0.5; this->ScreenTopRight[2] = -0.5; this->EyeSeparation = 0.06; this->WorldToScreenMatrix = vtkMatrix4x4::New(); this->WorldToScreenMatrix->Identity(); this->EyeTransformMatrix = vtkMatrix4x4::New(); this->EyeTransformMatrix->Identity(); this->ModelTransformMatrix = vtkMatrix4x4::New(); this->ModelTransformMatrix->Identity(); this->ClippingRange[0] = 0.01; this->ClippingRange[1] = 1000.01; this->Thickness = 1000.0; this->ParallelProjection = 0; this->ParallelScale = 1.0; this->EyeAngle = 2.0; this->Stereo = 0; this->LeftEye = 1; this->WindowCenter[0] = 0.0; this->WindowCenter[1] = 0.0; this->ViewShear[0] = 0.0; this->ViewShear[1] = 0.0; this->ViewShear[2] = 1.0; this->FocalDisk = 1.0; this->FocalDistance = 0.0; this->Transform = vtkPerspectiveTransform::New(); this->ViewTransform = vtkTransform::New(); this->ProjectionTransform = vtkPerspectiveTransform::New(); this->CameraLightTransform = vtkTransform::New(); this->ModelViewTransform = vtkTransform::New(); this->ExplicitProjectionTransformMatrix = nullptr; this->UseExplicitProjectionTransformMatrix = false; this->UserTransform = nullptr; this->UserViewTransform = nullptr; this->UserViewTransformCallbackCommand = nullptr; // initialize the ViewTransform this->ComputeViewTransform(); this->ComputeDistance(); this->ComputeCameraLightTransform(); this->FreezeFocalPoint = false; this->UseScissor = false; this->Information = vtkInformation::New(); this->Information->Register(this); this->Information->Delete(); this->ExplicitAspectRatio = 1.0; this->UseExplicitAspectRatio = false; this->FocalPointScale = 1.0; this->FocalPointShift[0] = 0.0; this->FocalPointShift[1] = 0.0; this->FocalPointShift[2] = 0.0; this->NearPlaneScale = 1.0; this->NearPlaneShift[0] = 0.0; this->NearPlaneShift[1] = 0.0; this->NearPlaneShift[2] = 0.0; this->ShiftScaleThreshold = 2.0; } //------------------------------------------------------------------------------ vtkCamera::~vtkCamera() { this->WorldToScreenMatrix->Delete(); this->WorldToScreenMatrix = nullptr; this->EyeTransformMatrix->Delete(); this->EyeTransformMatrix = nullptr; this->ModelTransformMatrix->Delete(); this->ModelTransformMatrix = nullptr; this->Transform->Delete(); this->ViewTransform->Delete(); this->ProjectionTransform->Delete(); this->CameraLightTransform->Delete(); this->ModelViewTransform->Delete(); if (this->ExplicitProjectionTransformMatrix) { this->ExplicitProjectionTransformMatrix->UnRegister(this); this->ExplicitProjectionTransformMatrix = nullptr; } if (this->UserTransform) { this->UserTransform->UnRegister(this); this->UserTransform = nullptr; } if (this->UserViewTransform) { this->UserViewTransform->RemoveObserver(this->UserViewTransformCallbackCommand); this->UserViewTransform->UnRegister(this); this->UserViewTransform = nullptr; } if (this->UserViewTransformCallbackCommand) { this->UserViewTransformCallbackCommand->Delete(); } this->SetInformation(nullptr); } //------------------------------------------------------------------------------ void vtkCamera::SetScissorRect(vtkRecti scissorRect) { this->ScissorRect = scissorRect; } //------------------------------------------------------------------------------ void vtkCamera::GetScissorRect(vtkRecti& scissorRect) { scissorRect = this->ScissorRect; } //------------------------------------------------------------------------------ // The first set of methods deal exclusively with the ViewTransform, which // is the only transform which is set up entirely in the camera. The // perspective transform must be set up by the Renderer because the // Camera doesn't know the Renderer's aspect ratio. //------------------------------------------------------------------------------ void vtkCamera::SetPosition(double x, double y, double z) { if (x == this->Position[0] && y == this->Position[1] && z == this->Position[2]) { return; } this->Position[0] = x; this->Position[1] = y; this->Position[2] = z; vtkDebugMacro(<< " Position set to ( " << this->Position[0] << ", " << this->Position[1] << ", " << this->Position[2] << ")"); this->ComputeViewTransform(); // recompute the focal distance this->ComputeDistance(); this->ComputeCameraLightTransform(); this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::SetUserTransform(vtkHomogeneousTransform* transform) { if (transform == this->UserTransform) { return; } if (this->UserTransform) { this->UserTransform->Delete(); this->UserTransform = nullptr; } if (transform) { this->UserTransform = transform; this->UserTransform->Register(this); } this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::SetUserViewTransform(vtkHomogeneousTransform* transform) { if (transform == this->UserViewTransform) { return; } if (this->UserViewTransform) { this->UserViewTransform->RemoveObserver(this->UserViewTransformCallbackCommand); this->UserViewTransform->Delete(); this->UserViewTransform = nullptr; } if (transform) { this->UserViewTransform = transform; this->UserViewTransform->Register(this); if (!this->UserViewTransformCallbackCommand) { this->UserViewTransformCallbackCommand = vtkCameraCallbackCommand::New(); this->UserViewTransformCallbackCommand->Self = this; } this->UserViewTransform->AddObserver( vtkCommand::ModifiedEvent, this->UserViewTransformCallbackCommand); } this->Modified(); this->ComputeViewTransform(); this->ComputeDistance(); this->ComputeCameraLightTransform(); } //------------------------------------------------------------------------------ void vtkCamera::SetFocalPoint(double x, double y, double z) { if (x == this->FocalPoint[0] && y == this->FocalPoint[1] && z == this->FocalPoint[2]) { return; } this->FocalPoint[0] = x; this->FocalPoint[1] = y; this->FocalPoint[2] = z; vtkDebugMacro(<< " FocalPoint set to ( " << this->FocalPoint[0] << ", " << this->FocalPoint[1] << ", " << this->FocalPoint[2] << ")"); this->ComputeViewTransform(); // recompute the focal distance this->ComputeDistance(); this->ComputeCameraLightTransform(); this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::SetViewUp(double x, double y, double z) { // normalize ViewUp, but do _not_ orthogonalize it by default double norm = sqrt(x * x + y * y + z * z); if (norm != 0) { x /= norm; y /= norm; z /= norm; } else { x = 0; y = 1; z = 0; } if (x == this->ViewUp[0] && y == this->ViewUp[1] && z == this->ViewUp[2]) { return; } this->ViewUp[0] = x; this->ViewUp[1] = y; this->ViewUp[2] = z; vtkDebugMacro(<< " ViewUp set to ( " << this->ViewUp[0] << ", " << this->ViewUp[1] << ", " << this->ViewUp[2] << ")"); this->ComputeViewTransform(); this->ComputeCameraLightTransform(); this->Modified(); } //------------------------------------------------------------------------------ // The ViewTransform depends on only three ivars: the Position, the // FocalPoint, and the ViewUp vector. All the other methods are there // simply for the sake of the users' convenience. void vtkCamera::ComputeViewTransform() { // main view through the camera this->Transform->Identity(); if (this->UserViewTransform) { this->Transform->Concatenate(this->UserViewTransform); } this->Transform->SetupCamera(this->Position, this->FocalPoint, this->ViewUp); this->ViewTransform->Identity(); this->ViewTransform->Concatenate(this->Transform->GetMatrix()); } //------------------------------------------------------------------------------ void vtkCamera::ComputeCameraLightTransform() { vtkTransform* t; double d; // assumes a valid view transform and valid camera distance t = this->CameraLightTransform; t->Identity(); t->SetMatrix(this->ViewTransform->GetMatrix()); t->Inverse(); d = this->Distance; t->Scale(d, d, d); t->Translate(0.0, 0.0, -1.0); } //------------------------------------------------------------------------------ void vtkCamera::ComputeWorldToScreenMatrix() { // Avoid recalculating screen orientation if we don't need to. if (this->WorldToScreenMatrixMTime.GetMTime() < this->GetMTime()) { double xAxis[3]; double yAxis[3]; double zAxis[3]; for (int i = 0; i < 3; ++i) { xAxis[i] = this->ScreenBottomRight[i] - this->ScreenBottomLeft[i]; yAxis[i] = this->ScreenTopRight[i] - this->ScreenBottomRight[i]; } vtkMath::Normalize(xAxis); vtkMath::Normalize(yAxis); vtkMath::Cross(xAxis, yAxis, zAxis); vtkMath::Normalize(zAxis); // Setting individual elements of the matrix. // Make it column major and then invert it to make sure the translation is correct // This is using column major (vectors are copied into the column) // \Note: while the initial element assignments are made in column-major // ordering, the matrix will be inverted, resulting in a row-major // matrix that provides the transformation from World to Screen space. this->WorldToScreenMatrix->SetElement(0, 0, xAxis[0]); this->WorldToScreenMatrix->SetElement(1, 0, xAxis[1]); this->WorldToScreenMatrix->SetElement(2, 0, xAxis[2]); this->WorldToScreenMatrix->SetElement(0, 1, yAxis[0]); this->WorldToScreenMatrix->SetElement(1, 1, yAxis[1]); this->WorldToScreenMatrix->SetElement(2, 1, yAxis[2]); this->WorldToScreenMatrix->SetElement(0, 2, zAxis[0]); this->WorldToScreenMatrix->SetElement(1, 2, zAxis[1]); this->WorldToScreenMatrix->SetElement(2, 2, zAxis[2]); this->WorldToScreenMatrix->SetElement(0, 3, this->ScreenBottomLeft[0]); this->WorldToScreenMatrix->SetElement(1, 3, this->ScreenBottomLeft[1]); this->WorldToScreenMatrix->SetElement(2, 3, this->ScreenBottomLeft[2]); this->WorldToScreenMatrix->SetElement(3, 3, 1.0); // The reason for doing this as an Invert as the goal here is to put // the translation through the rotation that we've just assigned ie. // the translation has to be put into screen space too. this->WorldToScreenMatrix->Invert(); this->WorldToScreenMatrixMTime.Modified(); } } //------------------------------------------------------------------------------ void vtkCamera::ComputeOffAxisProjectionFrustum() { this->ComputeWorldToScreenMatrix(); // \NOTE: Variable names reflect naming convention used in // "High Resolution Virtual Reality", in Proc. // SIGGRAPH '92, Computer Graphics, pages 195-202, 1992. // OffAxis calculations. // vtkMatrix::MultiplyPoint expect homogeneous coordinate. double E[4] = { 0.0, 0.0, 0.0, 1.0 }; double L[4] = { this->ScreenBottomLeft[0], this->ScreenBottomLeft[1], this->ScreenBottomLeft[2], 1.0 }; double H[4] = { this->ScreenTopRight[0], this->ScreenTopRight[1], this->ScreenTopRight[2], 1.0 }; double eyeSeparationCorrectionFactor = 10.0; double shiftDistance = this->EyeSeparation / (2.0 * eyeSeparationCorrectionFactor); if (this->Distance < 1.0) { shiftDistance *= this->Distance; } if (this->LeftEye) { E[0] -= shiftDistance; } else { E[0] += shiftDistance; } // First transform the eye to new position. this->EyeTransformMatrix->MultiplyPoint(E, E); // Now transform the eye and screen corner points into the screen // coordinate system. this->WorldToScreenMatrix->MultiplyPoint(E, E); this->WorldToScreenMatrix->MultiplyPoint(H, H); this->WorldToScreenMatrix->MultiplyPoint(L, L); double matrix[4][4]; double width = H[0] - L[0]; double height = H[1] - L[1]; // Back and front are not traditional near and far. // Front (aka near) double F = E[2] - (this->Distance + this->Thickness); // E[2] - 10000.0;//this->ClippingRange[1]; // Back (aka far) double nearDistanceCorrectionFactor = 1000.0; double B = E[2] - (this->Distance / nearDistanceCorrectionFactor); // E[2] - .1;//this->ClippingRange[0]; double depth = B - F; matrix[0][0] = (2 * E[2]) / width; matrix[1][0] = 0; matrix[2][0] = 0; matrix[3][0] = 0; matrix[0][1] = 0; matrix[1][1] = (2 * E[2]) / height; matrix[2][1] = 0; matrix[3][1] = 0; matrix[0][2] = (H[0] + L[0] - 2 * E[0]) / width; matrix[1][2] = (H[1] + L[1] - 2 * E[1]) / height; matrix[2][2] = (B + F - 2 * E[2]) / depth; matrix[3][2] = -1; matrix[0][3] = (-E[2] * (H[0] + L[0])) / width; matrix[1][3] = (-E[2] * (H[1] + L[1])) / height; matrix[2][3] = B - E[2] - (B * (B + F - 2 * E[2]) / depth); matrix[3][3] = E[2]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { this->ProjectionTransform->GetMatrix()->SetElement(i, j, matrix[i][j]); } } // Now move the world into display space. vtkMatrix4x4::Multiply4x4(this->ProjectionTransform->GetMatrix(), this->WorldToScreenMatrix, this->ProjectionTransform->GetMatrix()); } //------------------------------------------------------------------------------ void vtkCamera::ComputeModelViewMatrix() { if (this->ModelViewTransform->GetMTime() < this->ModelTransformMatrix->GetMTime() || this->ModelViewTransform->GetMTime() < this->ViewTransform->GetMTime()) { vtkMatrix4x4::Multiply4x4(this->ViewTransform->GetMatrix(), this->ModelTransformMatrix, this->ModelViewTransform->GetMatrix()); } } //------------------------------------------------------------------------------ void vtkCamera::OrthogonalizeViewUp() { // the orthogonalized ViewUp is just the second row of the view matrix vtkMatrix4x4* matrix = this->ViewTransform->GetMatrix(); this->ViewUp[0] = matrix->GetElement(1, 0); this->ViewUp[1] = matrix->GetElement(1, 1); this->ViewUp[2] = matrix->GetElement(1, 2); this->Modified(); } //------------------------------------------------------------------------------ // Set the distance of the focal point from the camera. The focal point is // modified accordingly. This should be positive. void vtkCamera::SetDistance(double d) { if (this->Distance == d) { return; } this->Distance = d; // Distance should be greater than .0002 if (this->Distance < 0.0002) { this->Distance = 0.0002; vtkDebugMacro(<< " Distance is set to minimum."); } // we want to keep the camera pointing in the same direction double* vec = this->DirectionOfProjection; // recalculate FocalPoint this->FocalPoint[0] = this->Position[0] + vec[0] * this->Distance; this->FocalPoint[1] = this->Position[1] + vec[1] * this->Distance; this->FocalPoint[2] = this->Position[2] + vec[2] * this->Distance; vtkDebugMacro(<< " Distance set to ( " << this->Distance << ")"); this->ComputeViewTransform(); this->ComputeCameraLightTransform(); this->Modified(); } //------------------------------------------------------------------------------ // This method must be called when the focal point or camera position changes void vtkCamera::ComputeDistance() { double dx = this->FocalPoint[0] - this->Position[0]; double dy = this->FocalPoint[1] - this->Position[1]; double dz = this->FocalPoint[2] - this->Position[2]; this->Distance = sqrt(dx * dx + dy * dy + dz * dz); if (this->Distance < 1e-20) { this->Distance = 1e-20; vtkDebugMacro(<< " Distance is set to minimum."); double* vec = this->DirectionOfProjection; // recalculate FocalPoint this->FocalPoint[0] = this->Position[0] + vec[0] * this->Distance; this->FocalPoint[1] = this->Position[1] + vec[1] * this->Distance; this->FocalPoint[2] = this->Position[2] + vec[2] * this->Distance; } this->DirectionOfProjection[0] = dx / this->Distance; this->DirectionOfProjection[1] = dy / this->Distance; this->DirectionOfProjection[2] = dz / this->Distance; this->ComputeViewPlaneNormal(); } //------------------------------------------------------------------------------ // Move the position of the camera along the view plane normal. Moving // towards the focal point (e.g., > 1) is a dolly-in, moving away // from the focal point (e.g., < 1) is a dolly-out. void vtkCamera::Dolly(double amount) { if (amount <= 0.0) { return; } // dolly moves the camera towards the focus double d = this->Distance / amount; this->SetPosition(this->FocalPoint[0] - d * this->DirectionOfProjection[0], this->FocalPoint[1] - d * this->DirectionOfProjection[1], this->FocalPoint[2] - d * this->DirectionOfProjection[2]); } //------------------------------------------------------------------------------ // Set the roll angle of the camera about the direction of projection void vtkCamera::SetRoll(double roll) { // roll is a rotation of camera view up about the direction of projection vtkDebugMacro(<< " Setting Roll to " << roll << ""); // subtract the current roll roll -= this->GetRoll(); if (fabs(roll) < 0.00001) { return; } this->Roll(roll); } //------------------------------------------------------------------------------ // Returns the roll of the camera. double vtkCamera::GetRoll() { double orientation[3]; this->ViewTransform->GetOrientation(orientation); return orientation[2]; } //------------------------------------------------------------------------------ // Rotate the camera around the view plane normal. void vtkCamera::Roll(double angle) { double newViewUp[3]; this->Transform->Identity(); // rotate ViewUp about the Direction of Projection this->Transform->RotateWXYZ(angle, this->DirectionOfProjection); // okay, okay, TransformPoint shouldn't be used on vectors -- but // the transform is rotation with no translation so this works fine. this->Transform->TransformPoint(this->ViewUp, newViewUp); this->SetViewUp(newViewUp); } //------------------------------------------------------------------------------ // Rotate the focal point about the view up vector centered at the camera's // position. void vtkCamera::Yaw(double angle) { double newFocalPoint[3]; double* pos = this->Position; this->Transform->Identity(); // translate the camera to the origin, // rotate about axis, // translate back again this->Transform->Translate(+pos[0], +pos[1], +pos[2]); this->Transform->RotateWXYZ(angle, this->ViewUp); this->Transform->Translate(-pos[0], -pos[1], -pos[2]); // now transform focal point this->Transform->TransformPoint(this->FocalPoint, newFocalPoint); this->SetFocalPoint(newFocalPoint); } //------------------------------------------------------------------------------ // Rotate the focal point about the cross product of the view up vector // and the negative of the , centered at the camera's position. void vtkCamera::Pitch(double angle) { double axis[3], newFocalPoint[3], savedViewUp[3]; double* pos = this->Position; this->Transform->Identity(); // the axis is the first row of the view transform matrix axis[0] = this->ViewTransform->GetMatrix()->GetElement(0, 0); axis[1] = this->ViewTransform->GetMatrix()->GetElement(0, 1); axis[2] = this->ViewTransform->GetMatrix()->GetElement(0, 2); // temporarily set the view up with the transformation applied // to avoid bad cross product computations during SetFocalPoint call this->GetViewUp(savedViewUp); this->Transform->RotateWXYZ(angle, axis); this->Transform->TransformPoint(this->ViewUp, this->ViewUp); this->Transform->Identity(); // translate the camera to the origin, // rotate about axis, // translate back again this->Transform->Translate(+pos[0], +pos[1], +pos[2]); this->Transform->RotateWXYZ(angle, axis); this->Transform->Translate(-pos[0], -pos[1], -pos[2]); // now transform focal point this->Transform->TransformPoint(this->FocalPoint, newFocalPoint); this->SetFocalPoint(newFocalPoint); // restore the previous ViewUp vector this->ViewUp[0] = savedViewUp[0]; this->ViewUp[1] = savedViewUp[1]; this->ViewUp[2] = savedViewUp[2]; // this is needed since the last time Modified was called (in SetFocalPoint), // the ViewUp was not same as savedViewUp. Since we're changing its value // here, we need to fire Modified event. We don't call `SetViewUp` since we // don't want the computation of the view transform to happen again. this->Modified(); } //------------------------------------------------------------------------------ // Rotate the camera about the view up vector centered at the focal point. void vtkCamera::Azimuth(double angle) { double newPosition[3]; double* fp = this->FocalPoint; this->Transform->Identity(); // translate the focal point to the origin, // rotate about view up, // translate back again this->Transform->Translate(+fp[0], +fp[1], +fp[2]); this->Transform->RotateWXYZ(angle, this->ViewUp); this->Transform->Translate(-fp[0], -fp[1], -fp[2]); // apply the transform to the position this->Transform->TransformPoint(this->Position, newPosition); this->SetPosition(newPosition); } //------------------------------------------------------------------------------ // Rotate the camera about the cross product of the negative of the // direction of projection and the view up vector centered on the focal point. void vtkCamera::Elevation(double angle) { double axis[3], newPosition[3], savedViewUp[3]; double* fp = this->FocalPoint; this->Transform->Identity(); // snatch the axis from the view transform matrix axis[0] = -this->ViewTransform->GetMatrix()->GetElement(0, 0); axis[1] = -this->ViewTransform->GetMatrix()->GetElement(0, 1); axis[2] = -this->ViewTransform->GetMatrix()->GetElement(0, 2); // temporarily set the view up with the transformation applied // to avoid bad cross product computations during SetPosition call this->GetViewUp(savedViewUp); this->Transform->RotateWXYZ(angle, axis); this->Transform->TransformPoint(this->ViewUp, this->ViewUp); this->Transform->Identity(); // translate the focal point to the origin, // rotate about axis, // translate back again this->Transform->Translate(+fp[0], +fp[1], +fp[2]); this->Transform->RotateWXYZ(angle, axis); this->Transform->Translate(-fp[0], -fp[1], -fp[2]); // now transform position this->Transform->TransformPoint(this->Position, newPosition); this->SetPosition(newPosition); // restore the previous ViewUp vector this->ViewUp[0] = savedViewUp[0]; this->ViewUp[1] = savedViewUp[1]; this->ViewUp[2] = savedViewUp[2]; // this is needed since the last time Modified was called (in SetPosition), // the ViewUp was not same as savedViewUp. Since we're changing its value // here, we need to fire Modified event. We don't call `SetViewUp` since we // don't want the computation of the view transform to happen again. this->Modified(); } //------------------------------------------------------------------------------ // Apply Transform to camera void vtkCamera::ApplyTransform(vtkTransform* t) { double posOld[4], posNew[4], fpOld[4], fpNew[4], vuOld[4], vuNew[4]; this->GetPosition(posOld); this->GetFocalPoint(fpOld); this->GetViewUp(vuOld); posOld[3] = 1.0; fpOld[3] = 1.0; vuOld[3] = 1.0; vuOld[0] += posOld[0]; vuOld[1] += posOld[1]; vuOld[2] += posOld[2]; t->MultiplyPoint(posOld, posNew); t->MultiplyPoint(fpOld, fpNew); t->MultiplyPoint(vuOld, vuNew); vuNew[0] -= posNew[0]; vuNew[1] -= posNew[1]; vuNew[2] -= posNew[2]; this->SetPosition(posNew); this->SetFocalPoint(fpNew); this->SetViewUp(vuNew); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // The following methods set up the information that the Renderer needs // to set up the perspective transform. The transformation matrix is // created using the GetPerspectiveTransformMatrix method. //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void vtkCamera::SetParallelProjection(vtkTypeBool flag) { if (this->ParallelProjection != flag) { this->ParallelProjection = flag; this->Modified(); this->ViewingRaysModified(); } } //------------------------------------------------------------------------------ void vtkCamera::SetViewAngle(double angle) { double min = 0.00000001; double max = 179.0; if (this->ViewAngle != angle) { this->ViewAngle = (angle < min ? min : (angle > max ? max : angle)); this->Modified(); this->ViewingRaysModified(); } } //------------------------------------------------------------------------------ void vtkCamera::SetUseHorizontalViewAngle(vtkTypeBool flag) { if (flag == this->UseHorizontalViewAngle) { return; } this->UseHorizontalViewAngle = flag; this->Modified(); this->ViewingRaysModified(); } //------------------------------------------------------------------------------ void vtkCamera::SetParallelScale(double scale) { if (this->ParallelScale != scale) { this->ParallelScale = scale; this->Modified(); this->ViewingRaysModified(); } } //------------------------------------------------------------------------------ // Change the ViewAngle (for perspective) or the ParallelScale (for parallel) // so that more or less of a scene occupies the viewport. A value > 1 is a // zoom-in. A value < 1 is a zoom-out. void vtkCamera::Zoom(double amount) { if (amount <= 0.0) { return; } if (this->ParallelProjection) { this->SetParallelScale(this->ParallelScale / amount); } else { this->SetViewAngle(this->ViewAngle / amount); } } //------------------------------------------------------------------------------ void vtkCamera::SetClippingRange(double nearz, double farz) { double thickness; // check the order if (nearz > farz) { vtkDebugMacro(<< " Front and back clipping range reversed"); double temp = nearz; nearz = farz; farz = temp; } thickness = farz - nearz; // thickness should be greater than 1e-20 if (thickness < 1e-20) { thickness = 1e-20; vtkDebugMacro(<< " ClippingRange thickness is set to minimum."); // set back plane farz = nearz + thickness; } if (nearz == this->ClippingRange[0] && farz == this->ClippingRange[1] && this->Thickness == thickness) { return; } this->ClippingRange[0] = nearz; this->ClippingRange[1] = farz; this->Thickness = thickness; vtkDebugMacro(<< " ClippingRange set to ( " << this->ClippingRange[0] << ", " << this->ClippingRange[1] << ")"); this->Modified(); } //------------------------------------------------------------------------------ // Set the distance between clipping planes. // This method adjusts the back clipping plane to the specified thickness // behind the front clipping plane void vtkCamera::SetThickness(double s) { if (this->Thickness == s) { return; } this->Thickness = s; // thickness should be greater than 1e-20 if (this->Thickness < 1e-20) { this->Thickness = 1e-20; vtkDebugMacro(<< " ClippingRange thickness is set to minimum."); } // set back plane this->ClippingRange[1] = this->ClippingRange[0] + this->Thickness; vtkDebugMacro(<< " ClippingRange set to ( " << this->ClippingRange[0] << ", " << this->ClippingRange[1] << ")"); this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::SetWindowCenter(double x, double y) { if (this->WindowCenter[0] != x || this->WindowCenter[1] != y) { this->Modified(); this->ViewingRaysModified(); this->WindowCenter[0] = x; this->WindowCenter[1] = y; } } //------------------------------------------------------------------------------ void vtkCamera::SetObliqueAngles(double alpha, double beta) { alpha = vtkMath::RadiansFromDegrees(alpha); beta = vtkMath::RadiansFromDegrees(beta); double cotbeta = cos(beta) / sin(beta); double dxdz = cos(alpha) * cotbeta; double dydz = sin(alpha) * cotbeta; this->SetViewShear(dxdz, dydz, 1.0); } //------------------------------------------------------------------------------ // Set the shear transform of the viewing frustum. Parameters are // dx/dz, dy/dz, and center. center is a factor that describes where // to shear around. The distance dshear from the camera where // no shear occurs is given by (dshear = center * FocalDistance). // void vtkCamera::SetViewShear(double dxdz, double dydz, double center) { if (dxdz != this->ViewShear[0] || dydz != this->ViewShear[1] || center != this->ViewShear[2]) { this->Modified(); this->ViewingRaysModified(); this->ViewShear[0] = dxdz; this->ViewShear[1] = dydz; this->ViewShear[2] = center; this->ComputeViewPlaneNormal(); } } //------------------------------------------------------------------------------ void vtkCamera::SetViewShear(double d[3]) { this->SetViewShear(d[0], d[1], d[2]); } //------------------------------------------------------------------------------ // Compute the projection transform matrix. This is used in converting // between view and world coordinates. void vtkCamera::ComputeProjectionTransform(double aspect, double nearz, double farz) { this->ProjectionTransform->Identity(); // apply user defined transform last if there is one if (this->UserTransform) { this->ProjectionTransform->Concatenate(this->UserTransform->GetMatrix()); } if (this->UseExplicitProjectionTransformMatrix) { assert(this->ExplicitProjectionTransformMatrix != nullptr); this->ProjectionTransform->Concatenate(this->ExplicitProjectionTransformMatrix); return; } if (this->UseExplicitAspectRatio) { aspect = this->ExplicitAspectRatio; } // adjust Z-buffer range this->ProjectionTransform->AdjustZBuffer(-1, +1, nearz, farz); if (this->ParallelProjection) { // set up a rectangular parallelipiped double width = this->ParallelScale * aspect; double height = this->ParallelScale; double xmin = (this->WindowCenter[0] - 1.0) * width; double xmax = (this->WindowCenter[0] + 1.0) * width; double ymin = (this->WindowCenter[1] - 1.0) * height; double ymax = (this->WindowCenter[1] + 1.0) * height; this->ProjectionTransform->Ortho( xmin, xmax, ymin, ymax, this->ClippingRange[0], this->ClippingRange[1]); } else if (this->UseOffAxisProjection) { this->ComputeOffAxisProjectionFrustum(); } else { // set up a perspective frustum double tmp = tan(vtkMath::RadiansFromDegrees(this->ViewAngle) / 2.); double width; double height; if (this->UseHorizontalViewAngle) { width = this->ClippingRange[0] * tmp; height = this->ClippingRange[0] * tmp / aspect; } else { width = this->ClippingRange[0] * tmp * aspect; height = this->ClippingRange[0] * tmp; } double xmin = (this->WindowCenter[0] - 1.0) * width; double xmax = (this->WindowCenter[0] + 1.0) * width; double ymin = (this->WindowCenter[1] - 1.0) * height; double ymax = (this->WindowCenter[1] + 1.0) * height; this->ProjectionTransform->Frustum( xmin, xmax, ymin, ymax, this->ClippingRange[0], this->ClippingRange[1]); } if (this->Stereo && !this->UseOffAxisProjection) { // set up a shear for stereo views if (this->LeftEye) { this->ProjectionTransform->Stereo(-this->EyeAngle / 2, this->Distance); } else { this->ProjectionTransform->Stereo(+this->EyeAngle / 2, this->Distance); } } if (this->ViewShear[0] != 0.0 || this->ViewShear[1] != 0.0) { this->ProjectionTransform->Shear( this->ViewShear[0], this->ViewShear[1], this->ViewShear[2] * this->Distance); } } //------------------------------------------------------------------------------ // Return the projection transform matrix. See ComputeProjectionTransform. vtkMatrix4x4* vtkCamera::GetProjectionTransformMatrix(vtkRenderer* ren) { double aspect[2]; int lowerLeft[2]; int usize, vsize; vtkMatrix4x4* matrix = vtkMatrix4x4::New(); ren->GetTiledSizeAndOrigin(&usize, &vsize, lowerLeft, lowerLeft + 1); // some renderer subclasses may have more complicated computations for the // aspect ratio. So take that into account by computing the difference // between our simple aspect ratio and what the actual renderer is reporting. ren->ComputeAspect(); ren->GetAspect(aspect); double aspect2[2]; ren->vtkViewport::ComputeAspect(); ren->vtkViewport::GetAspect(aspect2); double aspectModification = aspect[0] * aspect2[1] / (aspect[1] * aspect2[0]); if (usize && vsize) { matrix->DeepCopy(this->GetProjectionTransformMatrix(aspectModification * usize / vsize, -1, 1)); matrix->Transpose(); } return matrix; } //------------------------------------------------------------------------------ // Return the projection transform matrix. See ComputeProjectionTransform. vtkMatrix4x4* vtkCamera::GetProjectionTransformMatrix(double aspect, double nearz, double farz) { this->ComputeProjectionTransform(aspect, nearz, farz); // return the transform return this->ProjectionTransform->GetMatrix(); } //------------------------------------------------------------------------------ // Return the projection transform object. See ComputeProjectionTransform. vtkPerspectiveTransform* vtkCamera::GetProjectionTransformObject( double aspect, double nearz, double farz) { this->ComputeProjectionTransform(aspect, nearz, farz); // return the transform return this->ProjectionTransform; } //------------------------------------------------------------------------------ // Return the projection transform matrix. See ComputeProjectionTransform. vtkMatrix4x4* vtkCamera::GetCompositeProjectionTransformMatrix( double aspect, double nearz, double farz) { // turn off stereo, the CompositeProjectionTransformMatrix is used for // picking, not for rendering. int stereo = this->Stereo; this->Stereo = 0; this->Transform->Identity(); this->Transform->Concatenate(this->GetProjectionTransformMatrix(aspect, nearz, farz)); this->Transform->Concatenate(this->GetViewTransformMatrix()); this->Stereo = stereo; // return the transform return this->Transform->GetMatrix(); } //------------------------------------------------------------------------------ // Return the attached light transform matrix. vtkMatrix4x4* vtkCamera::GetCameraLightTransformMatrix() { // return the transform return this->CameraLightTransform->GetMatrix(); } //------------------------------------------------------------------------------ void vtkCamera::ComputeViewPlaneNormal() { if (this->ViewShear[0] != 0.0 || this->ViewShear[1] != 0.0) { // set the VPN in camera coordinates this->ViewPlaneNormal[0] = this->ViewShear[0]; this->ViewPlaneNormal[1] = this->ViewShear[1]; this->ViewPlaneNormal[2] = 1.0; // transform the VPN to world coordinates using inverse of view transform this->ViewTransform->GetLinearInverse()->TransformNormal( this->ViewPlaneNormal, this->ViewPlaneNormal); } else { // VPN is -DOP this->ViewPlaneNormal[0] = -this->DirectionOfProjection[0]; this->ViewPlaneNormal[1] = -this->DirectionOfProjection[1]; this->ViewPlaneNormal[2] = -this->DirectionOfProjection[2]; } } //------------------------------------------------------------------------------ // Return the 6 planes (Ax + By + Cz + D = 0) that bound // the view frustum. void vtkCamera::GetFrustumPlanes(double aspect, double planes[24]) { int i; double f, normals[6][4], matrix[4][4]; // set up the normals for (i = 0; i < 6; i++) { normals[i][0] = 0.0; normals[i][1] = 0.0; normals[i][2] = 0.0; normals[i][3] = 1.0; // if i is even set to 1, if odd set to -1 normals[i][i / 2] = 1 - (i % 2) * 2; } if (this->UseExplicitAspectRatio) { aspect = this->ExplicitAspectRatio; } // get the composite perspective matrix vtkMatrix4x4::DeepCopy(*matrix, this->GetCompositeProjectionTransformMatrix(aspect, -1, +1)); // transpose the matrix for use with normals vtkMatrix4x4::Transpose(*matrix, *matrix); // transform the normals to world coordinates for (i = 0; i < 6; i++) { vtkMatrix4x4::MultiplyPoint(*matrix, normals[i], normals[i]); f = 1.0 / sqrt(normals[i][0] * normals[i][0] + normals[i][1] * normals[i][1] + normals[i][2] * normals[i][2]); planes[4 * i + 0] = normals[i][0] * f; planes[4 * i + 1] = normals[i][1] * f; planes[4 * i + 2] = normals[i][2] * f; planes[4 * i + 3] = normals[i][3] * f; } } void vtkCamera::UpdateIdealShiftScale(double aspect) { double matrix[4][4]; double imatrix[4][4]; if (this->UseExplicitAspectRatio) { aspect = this->ExplicitAspectRatio; } // get the composite perspective matrix vtkMatrix4x4::DeepCopy(*matrix, this->GetCompositeProjectionTransformMatrix(aspect, -1, +1)); vtkMatrix4x4::Invert(*matrix, *imatrix); double tmp[4]; tmp[0] = 0; tmp[1] = 0; tmp[2] = -1; tmp[3] = 1; vtkMatrix4x4::MultiplyPoint(*imatrix, tmp, tmp); double shift[3]; shift[0] = tmp[0] / tmp[3]; shift[1] = tmp[1] / tmp[3]; shift[2] = tmp[2] / tmp[3]; tmp[0] = 1; tmp[1] = 1; tmp[2] = -1; tmp[3] = 1; vtkMatrix4x4::MultiplyPoint(*imatrix, tmp, tmp); tmp[0] /= tmp[3]; tmp[1] /= tmp[3]; tmp[2] /= tmp[3]; double scale = sqrt(vtkMath::Distance2BetweenPoints(tmp, shift)); // now snap if (fabs(log10(scale / this->NearPlaneScale)) > this->ShiftScaleThreshold) { this->NearPlaneScale = scale; } // our metric for shifting depends on scale double dist2 = vtkMath::Distance2BetweenPoints(this->NearPlaneShift, shift); if (dist2 && log10(sqrt(dist2) / this->NearPlaneScale) > this->ShiftScaleThreshold) { this->NearPlaneShift[0] = shift[0]; this->NearPlaneShift[1] = shift[1]; this->NearPlaneShift[2] = shift[2]; } // now the focal point calcs tmp[0] = this->FocalPoint[0]; tmp[1] = this->FocalPoint[1]; tmp[2] = this->FocalPoint[2]; tmp[3] = 1.0; vtkMatrix4x4::MultiplyPoint(*matrix, tmp, tmp); tmp[0] = 0.0; tmp[1] = 0.0; tmp[2] /= tmp[3]; double fpdepth = tmp[2]; tmp[3] = 1.0; vtkMatrix4x4::MultiplyPoint(*imatrix, tmp, tmp); shift[0] = tmp[0] / tmp[3]; shift[1] = tmp[1] / tmp[3]; shift[2] = tmp[2] / tmp[3]; tmp[0] = 1; tmp[1] = 1; tmp[2] = fpdepth; tmp[3] = 1; vtkMatrix4x4::MultiplyPoint(*imatrix, tmp, tmp); tmp[0] /= tmp[3]; tmp[1] /= tmp[3]; tmp[2] /= tmp[3]; scale = sqrt(vtkMath::Distance2BetweenPoints(tmp, shift)); // now snap if (fabs(log10(scale / this->FocalPointScale)) > this->ShiftScaleThreshold) { this->FocalPointScale = scale; } // our metric for shifting depends on scale dist2 = vtkMath::Distance2BetweenPoints(this->FocalPointShift, shift); if (dist2 && log10(sqrt(dist2) / this->FocalPointScale) > this->ShiftScaleThreshold) { this->FocalPointShift[0] = shift[0]; this->FocalPointShift[1] = shift[1]; this->FocalPointShift[2] = shift[2]; } } //------------------------------------------------------------------------------ vtkMTimeType vtkCamera::GetViewingRaysMTime() { return this->ViewingRaysMTime.GetMTime(); } //------------------------------------------------------------------------------ void vtkCamera::ViewingRaysModified() { this->ViewingRaysMTime.Modified(); } //------------------------------------------------------------------------------ // Description: // Copy the properties of `source' into `this'. // Copy pointers of matrices. // \pre source_exists!=0 // \pre not_this: source!=this void vtkCamera::ShallowCopy(vtkCamera* source) { assert("pre: source_exists" && source != nullptr); assert("pre: not_this" && source != this); this->PartialCopy(source); // Shallow copy of matrices: if (this->UserTransform != nullptr) { this->UserTransform->Delete(); } this->UserTransform = source->UserTransform; if (this->UserTransform != nullptr) { this->UserTransform->Register(this); } if (this->UserViewTransform != nullptr) { this->UserViewTransform->Delete(); } this->UserViewTransform = source->UserViewTransform; if (this->UserViewTransform != nullptr) { this->UserViewTransform->Register(this); } if (this->ViewTransform != nullptr) { this->ViewTransform->Delete(); } this->ViewTransform = source->ViewTransform; if (this->ViewTransform != nullptr) { this->ViewTransform->Register(this); } if (this->ProjectionTransform != nullptr) { this->ProjectionTransform->Delete(); } this->ProjectionTransform = source->ProjectionTransform; if (this->ProjectionTransform != nullptr) { this->ProjectionTransform->Register(this); } if (this->Transform != nullptr) { this->Transform->Delete(); } this->Transform = source->Transform; if (this->Transform != nullptr) { this->Transform->Register(this); } if (this->CameraLightTransform != nullptr) { this->CameraLightTransform->Delete(); } this->CameraLightTransform = source->CameraLightTransform; if (this->CameraLightTransform != nullptr) { this->CameraLightTransform->Register(this); } if (this->EyeTransformMatrix != nullptr) { this->EyeTransformMatrix->Delete(); } this->EyeTransformMatrix = source->EyeTransformMatrix; if (this->EyeTransformMatrix != nullptr) { this->EyeTransformMatrix->Register(this); } if (this->WorldToScreenMatrix != nullptr) { this->WorldToScreenMatrix->Delete(); } this->WorldToScreenMatrix = source->WorldToScreenMatrix; if (this->WorldToScreenMatrix != nullptr) { this->WorldToScreenMatrix->Register(this); } if (this->ModelTransformMatrix != nullptr) { this->ModelTransformMatrix->Delete(); } this->ModelTransformMatrix = source->ModelTransformMatrix; if (this->ModelTransformMatrix != nullptr) { this->ModelTransformMatrix->Register(this); } if (this->ModelViewTransform != nullptr) { this->ModelViewTransform->Delete(); } this->ModelViewTransform = source->ModelViewTransform; if (this->ModelViewTransform != nullptr) { this->ModelViewTransform->Register(this); } } //------------------------------------------------------------------------------ // Description: // Copy the properties of `source' into `this'. // Copy the contents of the matrices. // \pre source_exists!=0 // \pre not_this: source!=this void vtkCamera::DeepCopy(vtkCamera* source) { assert("pre: source_exists" && source != nullptr); assert("pre: not_this" && source != this); this->PartialCopy(source); // Deep copy the matrices: if (source->UserTransform == nullptr) { if (this->UserTransform != nullptr) { this->UserTransform->UnRegister(this); this->UserTransform = nullptr; } } else { if (this->UserTransform == nullptr) { this->UserTransform = static_cast(source->UserTransform->MakeTransform()); } this->UserTransform->DeepCopy(source->UserTransform); } if (source->UserViewTransform == nullptr) { if (this->UserViewTransform != nullptr) { this->UserViewTransform->UnRegister(this); this->UserViewTransform = nullptr; } } else { if (this->UserViewTransform == nullptr) { this->UserViewTransform = static_cast(source->UserViewTransform->MakeTransform()); } this->UserViewTransform->DeepCopy(source->UserViewTransform); } if (source->ViewTransform == nullptr) { if (this->ViewTransform != nullptr) { this->ViewTransform->UnRegister(this); this->ViewTransform = nullptr; } } else { if (this->ViewTransform == nullptr) { this->ViewTransform = static_cast(source->ViewTransform->MakeTransform()); } this->ViewTransform->DeepCopy(source->ViewTransform); } if (source->ProjectionTransform == nullptr) { if (this->ProjectionTransform != nullptr) { this->ProjectionTransform->UnRegister(this); this->ProjectionTransform = nullptr; } } else { if (this->ProjectionTransform == nullptr) { this->ProjectionTransform = static_cast(source->ProjectionTransform->MakeTransform()); } this->ProjectionTransform->DeepCopy(source->ProjectionTransform); } if (source->Transform == nullptr) { if (this->Transform != nullptr) { this->Transform->UnRegister(this); this->Transform = nullptr; } } else { if (this->Transform == nullptr) { this->Transform = static_cast(source->Transform->MakeTransform()); } this->Transform->DeepCopy(source->Transform); } if (source->CameraLightTransform == nullptr) { if (this->CameraLightTransform != nullptr) { this->CameraLightTransform->UnRegister(this); this->CameraLightTransform = nullptr; } } else { if (this->CameraLightTransform == nullptr) { this->CameraLightTransform = static_cast(source->CameraLightTransform->MakeTransform()); } this->CameraLightTransform->DeepCopy(source->CameraLightTransform); } if (source->ModelViewTransform == nullptr) { if (this->ModelViewTransform != nullptr) { this->ModelViewTransform->UnRegister(this); this->ModelViewTransform = nullptr; } } else { if (this->ModelViewTransform == nullptr) { this->ModelViewTransform = static_cast(source->ModelViewTransform->MakeTransform()); } this->ModelViewTransform->DeepCopy(source->ModelViewTransform); } if (source->ModelTransformMatrix == nullptr) { if (this->ModelTransformMatrix != nullptr) { this->ModelTransformMatrix->UnRegister(this); this->ModelTransformMatrix = nullptr; } } else { if (this->ModelTransformMatrix == nullptr) { this->ModelTransformMatrix = static_cast(source->ModelTransformMatrix->NewInstance()); } this->ModelTransformMatrix->DeepCopy(source->ModelTransformMatrix); } if (source->EyeTransformMatrix == nullptr) { if (this->EyeTransformMatrix != nullptr) { this->EyeTransformMatrix->UnRegister(this); this->EyeTransformMatrix = nullptr; } } else { if (this->EyeTransformMatrix == nullptr) { this->EyeTransformMatrix = static_cast(source->EyeTransformMatrix->NewInstance()); } this->EyeTransformMatrix->DeepCopy(source->EyeTransformMatrix); } if (source->WorldToScreenMatrix == nullptr) { if (this->WorldToScreenMatrix != nullptr) { this->WorldToScreenMatrix->UnRegister(this); this->WorldToScreenMatrix = nullptr; } } else { if (this->WorldToScreenMatrix == nullptr) { this->WorldToScreenMatrix = static_cast(source->WorldToScreenMatrix->NewInstance()); } this->WorldToScreenMatrix->DeepCopy(source->WorldToScreenMatrix); } } //------------------------------------------------------------------------------ // Description: // Copy the ivars. Do nothing for the matrices. // Called by ShallowCopy() and DeepCopy() // \pre source_exists!=0 // \pre not_this: source!=this void vtkCamera::PartialCopy(vtkCamera* source) { assert("pre: source_exists" && source != nullptr); assert("pre: not_this" && source != this); int i; i = 0; while (i < 2) { this->WindowCenter[i] = source->WindowCenter[i]; this->ObliqueAngles[i] = source->ObliqueAngles[i]; this->ClippingRange[i] = source->ClippingRange[i]; ++i; } i = 0; while (i < 3) { this->FocalPoint[i] = source->FocalPoint[i]; this->Position[i] = source->Position[i]; this->ViewUp[i] = source->ViewUp[i]; this->DirectionOfProjection[i] = source->DirectionOfProjection[i]; this->ViewPlaneNormal[i] = source->ViewPlaneNormal[i]; this->ViewShear[i] = source->ViewShear[i]; this->ScreenBottomLeft[i] = source->ScreenBottomLeft[i]; this->ScreenBottomRight[i] = source->ScreenBottomRight[i]; this->ScreenTopRight[i] = source->ScreenTopRight[i]; ++i; } this->ViewAngle = source->ViewAngle; this->EyeAngle = source->EyeAngle; this->ParallelProjection = source->ParallelProjection; this->ParallelScale = source->ParallelScale; this->Stereo = source->Stereo; this->LeftEye = source->LeftEye; this->Thickness = source->Thickness; this->Distance = source->Distance; this->UseHorizontalViewAngle = source->UseHorizontalViewAngle; this->UseOffAxisProjection = source->UseOffAxisProjection; this->FocalDisk = source->FocalDisk; this->FocalDistance = source->FocalDistance; this->EyeSeparation = source->EyeSeparation; this->WorldToScreenMatrixMTime = source->WorldToScreenMatrixMTime; this->ViewingRaysMTime = source->ViewingRaysMTime; } //------------------------------------------------------------------------------ void vtkCamera::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "ClippingRange: (" << this->ClippingRange[0] << ", " << this->ClippingRange[1] << ")\n"; os << indent << "DirectionOfProjection: (" << this->DirectionOfProjection[0] << ", " << this->DirectionOfProjection[1] << ", " << this->DirectionOfProjection[2] << ")\n"; os << indent << "Distance: " << this->Distance << "\n"; os << indent << "EyeAngle: " << this->EyeAngle << "\n"; os << indent << "FocalDisk: " << this->FocalDisk << "\n"; os << indent << "FocalDistance: " << this->FocalDistance << "\n"; os << indent << "FocalPoint: (" << this->FocalPoint[0] << ", " << this->FocalPoint[1] << ", " << this->FocalPoint[2] << ")\n"; os << indent << "ViewShear: (" << this->ViewShear[0] << ", " << this->ViewShear[1] << ", " << this->ViewShear[2] << ")\n"; os << indent << "ParallelProjection: " << (this->ParallelProjection ? "On\n" : "Off\n"); os << indent << "ParallelScale: " << this->ParallelScale << "\n"; os << indent << "Position: (" << this->Position[0] << ", " << this->Position[1] << ", " << this->Position[2] << ")\n"; os << indent << "Stereo: " << (this->Stereo ? "On\n" : "Off\n"); os << indent << "Left Eye: " << this->LeftEye << endl; os << indent << "Thickness: " << this->Thickness << "\n"; os << indent << "ViewAngle: " << this->ViewAngle << "\n"; os << indent << "UseHorizontalViewAngle: " << this->UseHorizontalViewAngle << "\n"; os << indent << "UserTransform: "; if (this->UserTransform) { os << this->UserTransform << "\n"; } else { os << "(none)\n"; } if (this->UserViewTransform) { os << this->UserViewTransform << "\n"; } else { os << "(none)\n"; } os << indent << "FreezeFocalPoint: "; if (this->FreezeFocalPoint) { os << this->FreezeFocalPoint << "\n"; } else { os << "(none)\n"; } os << indent << "ViewPlaneNormal: (" << this->ViewPlaneNormal[0] << ", " << this->ViewPlaneNormal[1] << ", " << this->ViewPlaneNormal[2] << ")\n"; os << indent << "ViewUp: (" << this->ViewUp[0] << ", " << this->ViewUp[1] << ", " << this->ViewUp[2] << ")\n"; os << indent << "WindowCenter: (" << this->WindowCenter[0] << ", " << this->WindowCenter[1] << ")\n"; os << indent << "UseOffAxisProjection: (" << this->UseOffAxisProjection << ")\n"; os << indent << "ScreenBottomLeft: (" << this->ScreenBottomLeft[0] << ", " << this->ScreenBottomLeft[1] << ", " << this->ScreenBottomLeft[2] << ")\n"; os << indent << "ScreenBottomRight: (" << this->ScreenBottomRight[0] << ", " << this->ScreenBottomRight[1] << ", " << this->ScreenBottomRight[2] << ")\n"; os << indent << "ScreenTopRight: (" << this->ScreenTopRight[0] << ", " << this->ScreenTopRight[1] << ", " << this->ScreenTopRight[2] << ")\n"; os << indent << "EyeSeparation: (" << this->EyeSeparation << ")\n"; os << indent << "WorldToScreenMatrix: (" << this->WorldToScreenMatrix << "\n"; this->WorldToScreenMatrix->PrintSelf(os, indent.GetNextIndent()); os << indent << ")\n"; os << indent << "EyeTransformMatrix: (" << this->EyeTransformMatrix << "\n"; this->EyeTransformMatrix->PrintSelf(os, indent.GetNextIndent()); os << indent << ")\n"; os << indent << "ModelTransformMatrix: (" << this->ModelTransformMatrix << "\n"; this->ModelTransformMatrix->PrintSelf(os, indent.GetNextIndent()); os << indent << ")\n"; os << indent << "ProjectionTransform: (" << this->ProjectionTransform << "\n"; this->ProjectionTransform->PrintSelf(os, indent.GetNextIndent()); os << indent << ")\n"; } //------------------------------------------------------------------------------ void vtkCamera::SetEyePosition(double eyePosition[3]) { if (!eyePosition) { vtkErrorMacro(<< "ERROR: Invalid or nullptr eye position\n"); return; } this->EyeTransformMatrix->SetElement(0, 3, eyePosition[0]); this->EyeTransformMatrix->SetElement(1, 3, eyePosition[1]); this->EyeTransformMatrix->SetElement(2, 3, eyePosition[2]); this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::GetEyePosition(double eyePosition[3]) { if (!eyePosition) { vtkErrorMacro(<< "ERROR: Invalid or nullptr eye position\n"); return; } eyePosition[0] = this->EyeTransformMatrix->GetElement(0, 3); eyePosition[1] = this->EyeTransformMatrix->GetElement(1, 3); eyePosition[2] = this->EyeTransformMatrix->GetElement(2, 3); } //------------------------------------------------------------------------------ void vtkCamera::GetEyePlaneNormal(double normal[3]) { if (!normal) { vtkErrorMacro(<< "ERROR: Invalid or nullptr normal\n"); return; } // Homogeneous normal. double localNormal[4]; // Get the normal from the screen orientation. localNormal[0] = this->WorldToScreenMatrix->GetElement(2, 0); localNormal[1] = this->WorldToScreenMatrix->GetElement(2, 1); localNormal[2] = this->WorldToScreenMatrix->GetElement(2, 2); localNormal[3] = 0.0; // Just to be sure. vtkMath::Normalize(localNormal); normal[0] = localNormal[0]; normal[1] = localNormal[1]; normal[2] = localNormal[2]; } //------------------------------------------------------------------------------ vtkMatrix4x4* vtkCamera::GetModelViewTransformMatrix() { this->ComputeModelViewMatrix(); return this->ModelViewTransform->GetMatrix(); } //------------------------------------------------------------------------------ vtkTransform* vtkCamera::GetModelViewTransformObject() { this->ComputeModelViewMatrix(); return this->ModelViewTransform; } //------------------------------------------------------------------------------ vtkMatrix4x4* vtkCamera::GetViewTransformMatrix() { return this->GetModelViewTransformMatrix(); } //------------------------------------------------------------------------------ vtkTransform* vtkCamera::GetViewTransformObject() { return this->GetModelViewTransformObject(); } //------------------------------------------------------------------------------ double* vtkCamera::GetOrientation() { return this->ViewTransform->GetOrientation(); } //------------------------------------------------------------------------------ double* vtkCamera::GetOrientationWXYZ() { return this->ViewTransform->GetOrientationWXYZ(); } //------------------------------------------------------------------------------ void vtkCamera::SetEyeTransformMatrix(const double elements[16]) { this->EyeTransformMatrix->Element[0][0] = elements[0]; this->EyeTransformMatrix->Element[0][1] = elements[1]; this->EyeTransformMatrix->Element[0][2] = elements[2]; this->EyeTransformMatrix->Element[0][3] = elements[3]; this->EyeTransformMatrix->Element[1][0] = elements[4]; this->EyeTransformMatrix->Element[1][1] = elements[5]; this->EyeTransformMatrix->Element[1][2] = elements[6]; this->EyeTransformMatrix->Element[1][3] = elements[7]; this->EyeTransformMatrix->Element[2][0] = elements[8]; this->EyeTransformMatrix->Element[2][1] = elements[9]; this->EyeTransformMatrix->Element[2][2] = elements[10]; this->EyeTransformMatrix->Element[2][3] = elements[11]; this->EyeTransformMatrix->Element[3][0] = elements[12]; this->EyeTransformMatrix->Element[3][1] = elements[13]; this->EyeTransformMatrix->Element[3][2] = elements[14]; this->EyeTransformMatrix->Element[3][3] = elements[15]; this->Modified(); } //------------------------------------------------------------------------------ void vtkCamera::SetModelTransformMatrix(const double elements[16]) { this->ModelTransformMatrix->Element[0][0] = elements[0]; this->ModelTransformMatrix->Element[0][1] = elements[1]; this->ModelTransformMatrix->Element[0][2] = elements[2]; this->ModelTransformMatrix->Element[0][3] = elements[3]; this->ModelTransformMatrix->Element[1][0] = elements[4]; this->ModelTransformMatrix->Element[1][1] = elements[5]; this->ModelTransformMatrix->Element[1][2] = elements[6]; this->ModelTransformMatrix->Element[1][3] = elements[7]; this->ModelTransformMatrix->Element[2][0] = elements[8]; this->ModelTransformMatrix->Element[2][1] = elements[9]; this->ModelTransformMatrix->Element[2][2] = elements[10]; this->ModelTransformMatrix->Element[2][3] = elements[11]; this->ModelTransformMatrix->Element[3][0] = elements[12]; this->ModelTransformMatrix->Element[3][1] = elements[13]; this->ModelTransformMatrix->Element[3][2] = elements[14]; this->ModelTransformMatrix->Element[3][3] = elements[15]; this->Modified(); }