mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
439 lines
14 KiB
C++
439 lines
14 KiB
C++
/*=============================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkGeoCamera.cxx
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=============================================================================*/
|
|
/*-------------------------------------------------------------------------
|
|
Copyright 2008 Sandia Corporation.
|
|
Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
the U.S. Government retains certain rights in this software.
|
|
-------------------------------------------------------------------------*/
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkGeoCamera.h"
|
|
#include "vtkGeoMath.h"
|
|
#include "vtkGeoTerrainNode.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkCamera.h"
|
|
#include "vtkTransform.h"
|
|
#include <float.h>
|
|
|
|
vtkStandardNewMacro(vtkGeoCamera);
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkGeoCamera::vtkGeoCamera()
|
|
{
|
|
this->VTKCamera = vtkSmartPointer<vtkCamera>::New();
|
|
this->Transform = vtkSmartPointer<vtkTransform>::New();
|
|
|
|
this->OriginLongitude = 0.0;
|
|
this->OriginLatitude = 0.0;
|
|
|
|
// Initial state will be looking at earth over the American continent.
|
|
//this->Longitude = -90.0;
|
|
this->Longitude = 0.0;
|
|
this->Latitude = 0.0;
|
|
this->Distance = vtkGeoMath::EarthRadiusMeters() * 5.0;
|
|
this->Heading = 0.0;
|
|
this->Tilt = 90.0;
|
|
this->LockHeading = true;
|
|
|
|
this->ComputeRectilinearOrigin();
|
|
|
|
this->UpdateAngleRanges();
|
|
this->UpdateVTKCamera();
|
|
|
|
this->Position[0] = this->Position[1] = this->Position[2] = 0.0;
|
|
this->Origin[0] = this->Origin[1] = this->Origin[2] = 0.0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkGeoCamera::~vtkGeoCamera()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
os << indent << "Distance: " << this->Distance << endl;
|
|
os << indent << "Tilt: " << this->Tilt << endl;
|
|
os << indent << "Heading: " << this->Heading << endl;
|
|
os << indent << "Latitude: " << this->Latitude << endl;
|
|
os << indent << "Longitude: " << this->Longitude << endl;
|
|
os << indent << "LockHeading: " << (this->LockHeading ? "on" : "off");
|
|
os << indent << "Origin: {" << this->Origin[0] << ", " << this->Origin[1]
|
|
<< ", " << this->Origin[2] << "}" << endl;
|
|
os << indent << "OriginLatitude: " << this->OriginLatitude << endl;
|
|
os << indent << "OriginLongitude: " << this->OriginLongitude << endl;
|
|
os << indent << "Position: {" << this->Position[0] << ", " << this->Position[1]
|
|
<< ", " << this->Position[2] << "}" << endl;
|
|
os << indent << "VTKCamera: " << endl;
|
|
|
|
this->VTKCamera->PrintSelf(os, indent.GetNextIndent());
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetOriginLatitude(double oLat)
|
|
{
|
|
if (this->OriginLatitude == oLat)
|
|
{
|
|
return;
|
|
}
|
|
this->OriginLatitude = oLat;
|
|
this->Modified();
|
|
this->ComputeRectilinearOrigin();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetOriginLongitude(double oLon)
|
|
{
|
|
if (this->OriginLongitude == oLon)
|
|
{
|
|
return;
|
|
}
|
|
this->OriginLongitude = oLon;
|
|
this->Modified();
|
|
this->ComputeRectilinearOrigin();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::ComputeRectilinearOrigin()
|
|
{
|
|
double tmp = cos(this->OriginLatitude * vtkMath::Pi() / 180.0);
|
|
|
|
this->Origin[1] = tmp * cos(this->OriginLongitude * vtkMath::Pi() / 180.0);
|
|
this->Origin[0] = -tmp * sin(this->OriginLongitude * vtkMath::Pi() / 180.0);
|
|
|
|
this->Origin[2] = sin(this->OriginLatitude * vtkMath::Pi() / 180.0);
|
|
|
|
this->Origin[0] *= vtkGeoMath::EarthRadiusMeters();
|
|
this->Origin[1] *= vtkGeoMath::EarthRadiusMeters();
|
|
this->Origin[2] *= vtkGeoMath::EarthRadiusMeters();
|
|
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetLongitude(double longitude)
|
|
{
|
|
if (this->Longitude == longitude)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
this->Longitude = longitude;
|
|
this->UpdateAngleRanges();
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetLatitude(double latitude)
|
|
{
|
|
if (this->Latitude == latitude)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
this->Latitude = latitude;
|
|
this->UpdateAngleRanges();
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetDistance(double altitude)
|
|
{
|
|
if (this->Distance == altitude)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
this->Distance = altitude;
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetHeading(double heading)
|
|
{
|
|
if (this->Heading == heading)
|
|
{
|
|
return;
|
|
}
|
|
while (heading < -180)
|
|
{
|
|
heading += 360;
|
|
}
|
|
while (heading > 180)
|
|
{
|
|
heading -= 360;
|
|
}
|
|
this->Modified();
|
|
this->Heading = heading;
|
|
this->UpdateAngleRanges();
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::SetTilt(double tilt)
|
|
{
|
|
if (this->Tilt == tilt)
|
|
{
|
|
return;
|
|
}
|
|
this->Modified();
|
|
this->Tilt = tilt;
|
|
this->UpdateVTKCamera();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::UpdateAngleRanges()
|
|
{
|
|
while (this->Heading > 180.0)
|
|
{
|
|
this->Heading -= 360.0;
|
|
}
|
|
while (this->Heading < -180.0)
|
|
{
|
|
this->Heading += 360.0;
|
|
}
|
|
while (this->Longitude > 180.0)
|
|
{
|
|
this->Longitude -= 360.0;
|
|
}
|
|
while (this->Longitude < -180.0)
|
|
{
|
|
this->Longitude += 360.0;
|
|
}
|
|
if (this->Latitude > 90.0)
|
|
{
|
|
this->Latitude = 180.0 - this->Latitude;
|
|
}
|
|
if (this->Latitude < -90.0)
|
|
{
|
|
this->Latitude = -180.0 - this->Latitude;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::UpdateVTKCamera()
|
|
{
|
|
this->Transform->PostMultiply();
|
|
this->Transform->Identity();
|
|
// Tilt
|
|
this->Transform->RotateX(this->Tilt);
|
|
// Heading
|
|
this->Transform->RotateY(-this->Heading);
|
|
// to surface of earth
|
|
this->Transform->Translate(0.0, vtkGeoMath::EarthRadiusMeters(), 0.0);
|
|
// Latitude
|
|
this->Transform->RotateX(this->Latitude);
|
|
// Longitude
|
|
this->Transform->RotateZ(this->Longitude);
|
|
|
|
// Consider origin.
|
|
this->Transform->Translate(-this->Origin[0],
|
|
-this->Origin[1],
|
|
-this->Origin[2]);
|
|
|
|
|
|
double* pt;
|
|
double tmp[3];
|
|
// Find focal point of the camera.
|
|
pt = this->Transform->TransformDoublePoint(0.0, 0.0, 0.0);
|
|
this->VTKCamera->SetFocalPoint(pt);
|
|
// Find position
|
|
this->VTKCamera->GetFocalPoint(tmp);
|
|
// Use arbitrary magnitude.
|
|
pt = this->Transform->TransformDoublePoint(0.0, 0.0, -this->Distance);
|
|
this->VTKCamera->SetPosition(pt);
|
|
// Save the position with out the origin shift so the evaluation works.
|
|
this->Position[0] = pt[0] + this->Origin[0];
|
|
this->Position[1] = pt[1] + this->Origin[1];
|
|
this->Position[2] = pt[2] + this->Origin[2];
|
|
|
|
if (this->LockHeading)
|
|
{
|
|
// Now find view up using heading.
|
|
pt = this->Transform->TransformDoublePoint(0.0, 1.0, 0.0);
|
|
tmp[0] = pt[0] - tmp[0];
|
|
tmp[1] = pt[1] - tmp[1];
|
|
tmp[2] = pt[2] - tmp[2];
|
|
this->VTKCamera->SetViewUp(tmp);
|
|
}
|
|
else
|
|
{
|
|
// Find heading using view up.
|
|
this->VTKCamera->OrthogonalizeViewUp();
|
|
double up[3];
|
|
this->VTKCamera->GetViewUp(up);
|
|
// Project vector to north pole and view up to the following plane:
|
|
// Normal = dir. out of center of earth from focal point, Point = origin.
|
|
|
|
// Compute the plane normal (center of earth at -origin).
|
|
double dir[3];
|
|
dir[0] = -tmp[0] - this->Origin[0];
|
|
dir[1] = -tmp[1] - this->Origin[1];
|
|
dir[2] = -tmp[2] - this->Origin[2];
|
|
vtkMath::Normalize(dir);
|
|
|
|
// Compute direction to north pole (at -origin + (0,0,earth_radius))
|
|
// from focal point.
|
|
double north[3];
|
|
north[0] = -this->Origin[0] - tmp[0];
|
|
north[1] = -this->Origin[1] - tmp[1];
|
|
north[2] = vtkGeoMath::EarthRadiusMeters() - this->Origin[2] - tmp[2];
|
|
double northDot = vtkMath::Dot(north, dir);
|
|
|
|
// Project direction to north pole to our plane.
|
|
double northProj[3];
|
|
northProj[0] = north[0] - northDot*dir[0];
|
|
northProj[1] = north[1] - northDot*dir[1];
|
|
northProj[2] = north[2] - northDot*dir[2];
|
|
vtkMath::Normalize(northProj);
|
|
|
|
// Project view up vector to the same plane.
|
|
double upDot = vtkMath::Dot(up, dir);
|
|
double upProj[3];
|
|
upProj[0] = up[0] - upDot*dir[0];
|
|
upProj[1] = up[1] - upDot*dir[1];
|
|
upProj[2] = up[2] - upDot*dir[2];
|
|
vtkMath::Normalize(upProj);
|
|
|
|
// Determine the angle between the vectors.
|
|
// Do some sin/cos trickery to get it to the full range
|
|
// [-180, 180].
|
|
double dotProd = vtkMath::Dot(northProj, upProj);
|
|
double crossProd[3];
|
|
vtkMath::Cross(northProj, upProj, crossProd);
|
|
this->Heading = vtkMath::DegreesFromRadians( asin( vtkMath::Norm( crossProd ) ) );
|
|
if (dotProd < 0)
|
|
{
|
|
this->Heading = 180.0 - this->Heading;
|
|
}
|
|
if (vtkMath::Dot(crossProd, dir) < 0)
|
|
{
|
|
this->Heading = -this->Heading;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkGeoCamera::InitializeNodeAnalysis(int rendererSize[2])
|
|
{
|
|
this->Aspect[1] = tan( vtkMath::RadiansFromDegrees( this->VTKCamera->GetViewAngle() ) * 0.5 );
|
|
this->Aspect[0] = this->Aspect[1] * rendererSize[0]
|
|
/ static_cast<double>( rendererSize[1] );
|
|
|
|
this->VTKCamera->GetViewPlaneNormal(this->ForwardNormal);
|
|
this->ForwardNormal[0] = - this->ForwardNormal[0];
|
|
this->ForwardNormal[1] = - this->ForwardNormal[1];
|
|
this->ForwardNormal[2] = - this->ForwardNormal[2];
|
|
|
|
this->VTKCamera->GetViewUp(this->UpNormal);
|
|
vtkMath::Normalize(this->UpNormal);
|
|
|
|
vtkMath::Cross(this->ForwardNormal, this->UpNormal, this->RightNormal);
|
|
|
|
// It may not be necessary to keep the above as instance variables.
|
|
for (int ii = 0; ii < 3; ++ii)
|
|
{
|
|
this->LeftPlaneNormal[ii] = - this->ForwardNormal[ii]*this->Aspect[0]
|
|
- this->RightNormal[ii];
|
|
this->RightPlaneNormal[ii] = - this->ForwardNormal[ii]*this->Aspect[0]
|
|
+ this->RightNormal[ii];
|
|
this->DownPlaneNormal[ii] = - this->ForwardNormal[ii]*this->Aspect[1]
|
|
- this->UpNormal[ii];
|
|
this->UpPlaneNormal[ii] = - this->ForwardNormal[ii]*this->Aspect[1]
|
|
+ this->UpNormal[ii];
|
|
}
|
|
vtkMath::Normalize(this->LeftPlaneNormal);
|
|
vtkMath::Normalize(this->RightPlaneNormal);
|
|
vtkMath::Normalize(this->DownPlaneNormal);
|
|
vtkMath::Normalize(this->UpPlaneNormal);
|
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This has to be as fast as possible.
|
|
// It is called for each node every render.
|
|
// These comparisons in rectilinear coordinates are not perfect.
|
|
// I look at a viewplain containing the sphere center.
|
|
// I compate a circle with the view bounds.
|
|
// Another option is to save 4 frustum plane normals in the camera.
|
|
// This would require 5 dot products (15 multiplications).
|
|
double vtkGeoCamera::GetNodeCoverage(vtkGeoTerrainNode* node)
|
|
{
|
|
double sphereCenter[3];
|
|
double sphereRadius;
|
|
double camPosition[3];
|
|
|
|
this->GetPosition(camPosition);
|
|
|
|
// Lets take care of nodes on the opposite side of the earth.
|
|
// I think there should be a better way of figuring this out.
|
|
if (vtkMath::Dot(this->ForwardNormal,node->GetCornerNormal00())>0.0 &&
|
|
vtkMath::Dot(this->ForwardNormal,node->GetCornerNormal01())>0.0 &&
|
|
vtkMath::Dot(this->ForwardNormal,node->GetCornerNormal10())>0.0 &&
|
|
vtkMath::Dot(this->ForwardNormal,node->GetCornerNormal11())>0.0)
|
|
{ // Node is hidden by the earth.
|
|
return 0.0;
|
|
}
|
|
|
|
sphereRadius = node->GetBoundingSphereRadius();
|
|
node->GetBoundingSphereCenter(sphereCenter);
|
|
|
|
// Put the camera's position at the origin.
|
|
sphereCenter[0] = sphereCenter[0] - camPosition[0];
|
|
sphereCenter[1] = sphereCenter[1] - camPosition[1];
|
|
sphereCenter[2] = sphereCenter[2] - camPosition[2];
|
|
|
|
double left = vtkMath::Dot(this->LeftPlaneNormal,sphereCenter);
|
|
double right = vtkMath::Dot(this->RightPlaneNormal,sphereCenter);
|
|
double down = vtkMath::Dot(this->DownPlaneNormal,sphereCenter);
|
|
double up = vtkMath::Dot(this->UpPlaneNormal,sphereCenter);
|
|
double forward = vtkMath::Dot(this->ForwardNormal,sphereCenter);
|
|
if ( left > sphereRadius || right > sphereRadius ||
|
|
down > sphereRadius || up > sphereRadius ||
|
|
forward < -sphereRadius)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
if (forward < sphereRadius)
|
|
{ // Camera is probably in the sphere.
|
|
return 1.0;
|
|
}
|
|
|
|
left = -left;
|
|
if (left > sphereRadius) { left = sphereRadius;}
|
|
up = -up;
|
|
if (up > sphereRadius) { up = sphereRadius;}
|
|
right = -right;
|
|
if (right > sphereRadius) { right = sphereRadius;}
|
|
down = -down;
|
|
if (down > sphereRadius) { down = sphereRadius;}
|
|
|
|
|
|
double coverage = (left+right)*(up+down) / (4.0 * forward*forward*this->Aspect[0]*this->Aspect[1]);
|
|
return coverage;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkCamera* vtkGeoCamera::GetVTKCamera()
|
|
{
|
|
return this->VTKCamera;
|
|
}
|
|
|