<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCamera.cxx

  Copyright (c) <NAME>, <NAME>, <NAME>
  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 "vtkMath.h"
#include "vtkTimeStamp.h"
#include "vtkGraphicsFactory.h"
#include "vtkPerspectiveTransform.h"
#include "vtkTransform.h"
#include "vtkCallbackCommand.h"

#include <math.h>


//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkCamera);

vtkCxxSetObjectMacro(vtkCamera, EyeTransformMatrix, vtkMatrix4x4);
vtkCxxSetObjectMacro(vtkCamera, ModelTransformMatrix, vtkMatrix4x4);

//-----------------------------------------------------------------------------
class vtkCameraCallbackCommand : public vtkCommand
{
public:
  static vtkCameraCallbackCommand *New()
    { return new vtkCameraCallbackCommand; };
  vtkCamera *Self;
  void Execute(vtkObject *, unsigned long, void *)
    {
      if (this->Self)
        {
        this->Self->Modified();
        this->Self->ComputeViewTransform();
        this->Self->ComputeDistance();
        this->Self->ComputeCameraLightTransform();
        }
    }
protected:
  vtkCameraCallbackCommand() { this->Self = NULL; };
  ~vtkCameraCallbackCommand() {};
};

//----------------------------------------------------------------------------
// 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->UseDeeringFrustum  = 0;

  this->ScreenBottomLeft[0] = -1.0;
  this->ScreenBottomLeft[1] = -1.0;
  this->ScreenBottomLeft[2] = -1.0;

  this->ScreenBottomRight[0] =  1.0;
  this->ScreenBottomRight[1] = -1.0;
  this->ScreenBottomRight[2] = -1.0;

  this->ScreenTopRight[0] =  1.0;
  this->ScreenTopRight[1] =  1.0;
  this->ScreenTopRight[2] = -1.0;

  this->EyeSeparation = 0.06;

  this->ScreenOrientation = vtkMatrix4x4::New();
  this->ScreenOrientation->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->Transform = vtkPerspectiveTransform::New();
  this->ViewTransform = vtkTransform::New();
  this->ProjectionTransform = vtkPerspectiveTransform::New();
  this->CameraLightTransform = vtkTransform::New();
  this->ModelViewTransform = vtkTransform::New();
  this->UserTransform = NULL;
  this->UserViewTransform = NULL;
  this->UserViewTransformCallbackCommand = NULL;

  // initialize the ViewTransform
  this->ComputeViewTransform();
  this->ComputeDistance();
  this->ComputeCameraLightTransform();
}

//----------------------------------------------------------------------------
vtkCamera::~vtkCamera()
{
  this->ScreenOrientation->Delete();
  this->ScreenOrientation = NULL;

  this->EyeTransformMatrix->Delete();
  this->EyeTransformMatrix = NULL;

  this->ModelTransformMatrix->Delete();
  this->ModelTransformMatrix = NULL;

  this->Transform->Delete();
  this->ViewTransform->Delete();
  this->ProjectionTransform->Delete();
  this->CameraLightTransform->Delete();
  this->ModelViewTransform->Delete();
  if (this->UserTransform)
    {
    this->UserTransform->UnRegister(this);
    this->UserTransform = NULL;
    }
  if (this->UserViewTransform)
    {
    this->UserViewTransform->RemoveObserver(
      this->UserViewTransformCallbackCommand);
    this->UserViewTransform->UnRegister(this);
    this->UserViewTransform = NULL;
    }
  if (this->UserViewTransformCallbackCommand)
    {
    this->UserViewTransformCallbackCommand->Delete();
    }
}

//----------------------------------------------------------------------------
// return the correct type of Camera
vtkCamera *vtkCamera::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkCamera");
  return static_cast<vtkCamera *>(ret);
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// 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 = NULL;
    }
  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 = NULL;
    }
  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->SetMatrix(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::ComputeScreenOrientation()
{
  // Avoid recalculating screen orientation if we don't need to.
  if(this->ScreenOrientationMTime.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);

    this->ScreenOrientation->SetElement(0, 0, xAxis[0]);
    this->ScreenOrientation->SetElement(0, 1, xAxis[1]);
    this->ScreenOrientation->SetElement(0, 2, xAxis[2]);

    this->ScreenOrientation->SetElement(1, 0, yAxis[0]);
    this->ScreenOrientation->SetElement(1, 1, yAxis[1]);
    this->ScreenOrientation->SetElement(1, 2, yAxis[2]);

    this->ScreenOrientation->SetElement(2, 0, zAxis[0]);
    this->ScreenOrientation->SetElement(2, 1, zAxis[1]);
    this->ScreenOrientation->SetElement(2, 2, zAxis[2]);

    this->ScreenOrientationMTime.Modified();
    }
}

//----------------------------------------------------------------------------
void vtkCamera::ComputeDeeringFrustum()
{
  this->ComputeScreenOrientation();

  // \NOTE: Varibles names reflect naming convention used in
  // "High Resolution Virtual Reality", in Proc.
  // SIGGRAPH '92, Computer Graphics, pages 195-202, 1992.

  // Deering calculations.
  double F = this->ClippingRange[1];
  double B = this->ClippingRange[0];

  // vtkMatrix::MultiplyPoint expect homogeneous coordinate.
  double E[4] = {0.0, 0.0, 0.0, 1.0};

  double L[2] = {this->ScreenBottomLeft[0], this->ScreenBottomLeft[1]};
  double H[2] = {this->ScreenTopRight[0],   this->ScreenTopRight[1]};


  if(this->LeftEye)
    {
    E[0] -= this->EyeSeparation / 2.0;
    }
  else
    {
    E[0] += this->EyeSeparation / 2.0;
    }

  // First tranform the eye to new position.
  this->EyeTransformMatrix->MultiplyPoint(E, E);

  // Define world origin.
  double origin[3] = {0.0, 0.0, 0.0};

  double screenNormal[3];
  screenNormal[0] = this->ScreenOrientation->GetElement(0, 2);
  screenNormal[1] = this->ScreenOrientation->GetElement(1, 2);
  screenNormal[2] = this->ScreenOrientation->GetElement(2, 2);

  double planeDCoordinate = -vtkMath::Dot(screenNormal, this->ScreenBottomLeft);
  double screen2originDistance = vtkMath::Dot(screenNormal, origin) + planeDCoordinate;

  // Now transform the eye into the screen coordinate system.
  this->ScreenOrientation->MultiplyPoint(E, E);
  this->ScreenOrientation->MultiplyPoint(H, H);
  this->ScreenOrientation->MultiplyPoint(L, L);

  E[2] += screen2originDistance;

  // Now transform the eye to screen coordinate system.
  this->ScreenOrientation->MultiplyPoint(E, E);
 this->ScreenOrientation->MultiplyPoint(H, H);
  this->ScreenOrientation->MultiplyPoint(L, L);


  double matrix[4][4];
  double width  = H[0] - L[0];
  double height = H[1] - L[1];
  B = E[2] - B;
  F = E[2] - F;

  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] ) ;
      }
    }
}

//----------------------------------------------------------------------------
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();<commit_msg>Move the world into screen space<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCamera.cxx

  Copyright (c) <NAME>, <NAME>, <NAME>
  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 "vtkMath.h"
#include "vtkTimeStamp.h"
#include "vtkGraphicsFactory.h"
#include "vtkPerspectiveTransform.h"
#include "vtkTransform.h"
#include "vtkCallbackCommand.h"

#include <math.h>


//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkCamera);

vtkCxxSetObjectMacro(vtkCamera, EyeTransformMatrix, vtkMatrix4x4);
vtkCxxSetObjectMacro(vtkCamera, ModelTransformMatrix, vtkMatrix4x4);

//-----------------------------------------------------------------------------
class vtkCameraCallbackCommand : public vtkCommand
{
public:
  static vtkCameraCallbackCommand *New()
    { return new vtkCameraCallbackCommand; };
  vtkCamera *Self;
  void Execute(vtkObject *, unsigned long, void *)
    {
      if (this->Self)
        {
        this->Self->Modified();
        this->Self->ComputeViewTransform();
        this->Self->ComputeDistance();
        this->Self->ComputeCameraLightTransform();
        }
    }
protected:
  vtkCameraCallbackCommand() { this->Self = NULL; };
  ~vtkCameraCallbackCommand() {};
};

//----------------------------------------------------------------------------
// 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->UseDeeringFrustum  = 0;

  this->ScreenBottomLeft[0] = -1.0;
  this->ScreenBottomLeft[1] = -1.0;
  this->ScreenBottomLeft[2] = -1.0;

  this->ScreenBottomRight[0] =  1.0;
  this->ScreenBottomRight[1] = -1.0;
  this->ScreenBottomRight[2] = -1.0;

  this->ScreenTopRight[0] =  1.0;
  this->ScreenTopRight[1] =  1.0;
  this->ScreenTopRight[2] = -1.0;

  this->EyeSeparation = 0.06;

  this->ScreenOrientation = vtkMatrix4x4::New();
  this->ScreenOrientation->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->Transform = vtkPerspectiveTransform::New();
  this->ViewTransform = vtkTransform::New();
  this->ProjectionTransform = vtkPerspectiveTransform::New();
  this->CameraLightTransform = vtkTransform::New();
  this->ModelViewTransform = vtkTransform::New();
  this->UserTransform = NULL;
  this->UserViewTransform = NULL;
  this->UserViewTransformCallbackCommand = NULL;

  // initialize the ViewTransform
  this->ComputeViewTransform();
  this->ComputeDistance();
  this->ComputeCameraLightTransform();
}

//----------------------------------------------------------------------------
vtkCamera::~vtkCamera()
{
  this->ScreenOrientation->Delete();
  this->ScreenOrientation = NULL;

  this->EyeTransformMatrix->Delete();
  this->EyeTransformMatrix = NULL;

  this->ModelTransformMatrix->Delete();
  this->ModelTransformMatrix = NULL;

  this->Transform->Delete();
  this->ViewTransform->Delete();
  this->ProjectionTransform->Delete();
  this->CameraLightTransform->Delete();
  this->ModelViewTransform->Delete();
  if (this->UserTransform)
    {
    this->UserTransform->UnRegister(this);
    this->UserTransform = NULL;
    }
  if (this->UserViewTransform)
    {
    this->UserViewTransform->RemoveObserver(
      this->UserViewTransformCallbackCommand);
    this->UserViewTransform->UnRegister(this);
    this->UserViewTransform = NULL;
    }
  if (this->UserViewTransformCallbackCommand)
    {
    this->UserViewTransformCallbackCommand->Delete();
    }
}

//----------------------------------------------------------------------------
// return the correct type of Camera
vtkCamera *vtkCamera::New()
{
  // First try to create the object from the vtkObjectFactory
  vtkObject* ret = vtkGraphicsFactory::CreateInstance("vtkCamera");
  return static_cast<vtkCamera *>(ret);
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
// 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 = NULL;
    }
  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 = NULL;
    }
  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->SetMatrix(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::ComputeScreenOrientation()
{
  // Avoid recalculating screen orientation if we don't need to.
  if(this->ScreenOrientationMTime.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);

    this->ScreenOrientation->Identity();

    this->ScreenOrientation->SetElement(0, 0, xAxis[0]);
    this->ScreenOrientation->SetElement(0, 1, xAxis[1]);
    this->ScreenOrientation->SetElement(0, 2, xAxis[2]);

    this->ScreenOrientation->SetElement(1, 0, yAxis[0]);
    this->ScreenOrientation->SetElement(1, 1, yAxis[1]);
    this->ScreenOrientation->SetElement(1, 2, yAxis[2]);

    this->ScreenOrientation->SetElement(2, 0, zAxis[0]);
    this->ScreenOrientation->SetElement(2, 1, zAxis[1]);
    this->ScreenOrientation->SetElement(2, 2, zAxis[2]);

    this->ScreenOrientationMTime.Modified();
    }
}

//----------------------------------------------------------------------------
void vtkCamera::ComputeDeeringFrustum()
{
  this->ComputeScreenOrientation();

  // \NOTE: Varibles names reflect naming convention used in
  // "High Resolution Virtual Reality", in Proc.
  // SIGGRAPH '92, Computer Graphics, pages 195-202, 1992.

  // Deering calculations.
  double F = this->ClippingRange[1];
  double B = this->ClippingRange[0];

  // vtkMatrix::MultiplyPoint expect homogeneous coordinate.
  double E[4] = {0.0, 0.0, 0.0, 1.0};

  double L[2] = {this->ScreenBottomLeft[0], this->ScreenBottomLeft[1]};
  double H[2] = {this->ScreenTopRight[0],   this->ScreenTopRight[1]};


  if(this->LeftEye)
    {
    E[0] -= this->EyeSeparation / 2.0;
    }
  else
    {
    E[0] += this->EyeSeparation / 2.0;
    }

  // First tranform the eye to new position.
  this->EyeTransformMatrix->MultiplyPoint(E, E);

  // Define world origin.
  double origin[3] = {0.0, 0.0, 0.0};

  double screenNormal[3];
  screenNormal[0] = this->ScreenOrientation->GetElement(2, 0);
  screenNormal[1] = this->ScreenOrientation->GetElement(2, 1);
  screenNormal[2] = this->ScreenOrientation->GetElement(2, 2);

  double planeDCoordinate = -vtkMath::Dot(screenNormal, this->ScreenBottomLeft);
  double screen2originDistance = vtkMath::Dot(screenNormal, origin) + planeDCoordinate;

  // Now transform the eye into the screen coordinate system.
  this->ScreenOrientation->MultiplyPoint(E, E);
  this->ScreenOrientation->MultiplyPoint(H, H);
  this->ScreenOrientation->MultiplyPoint(L, L);

  E[2] += screen2originDistance;

  // Now transform the eye to screen coordinate system.
  this->ScreenOrientation->MultiplyPoint(E, E);
  this->ScreenOrientation->MultiplyPoint(H, H);
  this->ScreenOrientation->MultiplyPoint(L, L);

  double matrix[4][4];
  double width  = H[0] - L[0];
  double height = H[1] - L[1];

  B = E[2] - B;
  F = E[2] - F;

  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 into display space.
  vtkMatrix4x4::Multiply4x4(this->ProjectionTransform->GetMatrix(), this->ScreenOrientation,
                            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();
{'fraction_non_alphanumeric': 0.25681862777160047, 'fraction_numerical': 0.022696055987965202, 'mean_word_length': 2.4139778943842805, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 572, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2846653', 'n_tokens_mistral': 9807, 'n_tokens_neox': 9352, 'n_words': 1814}