364 lines
10 KiB
C++
364 lines
10 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* OpenSceneGraph Public License for more details.
|
|
*/
|
|
|
|
#include <osgSim/Sector>
|
|
#include <osg/Vec2>
|
|
|
|
using namespace osgSim;
|
|
|
|
|
|
//
|
|
// Elevation Range
|
|
//
|
|
|
|
void AzimRange::setAzimuthRange(float minAzimuth,float maxAzimuth,float fadeAngle)
|
|
{
|
|
// clamp the azimuth range.
|
|
const float twoPI = 2.0f*(float)osg::PI;
|
|
while(minAzimuth>maxAzimuth) minAzimuth -= twoPI;
|
|
|
|
// compute the centerline
|
|
float centerAzim = (minAzimuth+maxAzimuth)*0.5f;
|
|
_cosAzim = cos(centerAzim);
|
|
_sinAzim = sin(centerAzim);
|
|
|
|
// compute the half angle range of the sector.
|
|
float angle = (maxAzimuth-minAzimuth)*0.5f;
|
|
_cosAngle = cos(angle);
|
|
|
|
// clamp the fade angle to valid values.
|
|
fadeAngle = osg::clampAbove(fadeAngle,0.0f);
|
|
if (angle+fadeAngle>osg::PI) _cosFadeAngle = -1.0f;
|
|
else _cosFadeAngle = cos(angle+fadeAngle);
|
|
|
|
}
|
|
|
|
void AzimRange::getAzimuthRange(float& minAzimuth, float& maxAzimuth, float& fadeAngle) const
|
|
{
|
|
float centerAzim = atan2(_sinAzim, _cosAzim);
|
|
float angle = acos(_cosAngle);
|
|
minAzimuth = centerAzim - angle;
|
|
maxAzimuth = centerAzim + angle;
|
|
if (_cosFadeAngle == -1.0f) {
|
|
fadeAngle = 2.0f * osg::PI;
|
|
} else {
|
|
fadeAngle = acos(_cosFadeAngle) - angle;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Elevation Range
|
|
//
|
|
void ElevationRange::setElevationRange(float minElevation,float maxElevation,float fadeAngle)
|
|
{
|
|
if (minElevation>maxElevation)
|
|
{
|
|
// need to swap angle pair.
|
|
float tmp = minElevation;
|
|
minElevation = maxElevation;
|
|
maxElevation = tmp;
|
|
}
|
|
|
|
minElevation = osg::clampTo(minElevation,(float)-osg::PI_2,(float)osg::PI_2);
|
|
maxElevation = osg::clampTo(maxElevation,(float)-osg::PI_2,(float)osg::PI_2);
|
|
fadeAngle = osg::clampTo(fadeAngle,0.0f,(float)osg::PI_2);
|
|
|
|
_cosMinElevation = cos(osg::PI_2-minElevation);
|
|
_cosMaxElevation = cos(osg::PI_2-maxElevation);
|
|
|
|
float minFadeAngle = osg::PI_2-minElevation+fadeAngle;
|
|
if (minFadeAngle>=osg::PI) _cosMinFadeElevation = -1.0f;
|
|
else _cosMinFadeElevation = cos(minFadeAngle);
|
|
|
|
float maxFadeAngle = osg::PI_2-maxElevation-fadeAngle;
|
|
if (maxFadeAngle<=0.0f) _cosMaxFadeElevation = 1.0f;
|
|
else _cosMaxFadeElevation = cos(maxFadeAngle);
|
|
|
|
}
|
|
|
|
float ElevationRange::getMinElevation() const
|
|
{
|
|
return osg::PI_2-acos(_cosMinElevation);
|
|
}
|
|
|
|
float ElevationRange::getMaxElevation() const
|
|
{
|
|
return osg::PI_2-acos(_cosMaxElevation);
|
|
}
|
|
|
|
float ElevationRange::getFadeAngle() const
|
|
{
|
|
float fadeAngle = 0.0;
|
|
|
|
// Take the appropriate (unclipped) elevation angle to calculate the fade angle
|
|
if (_cosMinFadeElevation != -1.0f) {
|
|
float minFadeAngle = acos(_cosMinFadeElevation);
|
|
float minElevation = osg::PI_2 - acos(_cosMinElevation);
|
|
fadeAngle = minFadeAngle + minElevation - osg::PI_2;
|
|
|
|
} else if (_cosMaxFadeElevation != 1.0f) {
|
|
float maxFadeAngle = acos(_cosMaxFadeElevation);
|
|
float maxElevation = osg::PI_2 - acos(_cosMaxElevation);
|
|
fadeAngle = osg::PI_2 - maxFadeAngle - maxElevation;
|
|
}
|
|
|
|
return fadeAngle;
|
|
}
|
|
|
|
//
|
|
// ElevationSector
|
|
//
|
|
AzimSector::AzimSector(float minAzimuth,float maxAzimuth,float fadeAngle):
|
|
Sector(),
|
|
AzimRange()
|
|
{
|
|
setAzimuthRange(minAzimuth,maxAzimuth,fadeAngle);
|
|
}
|
|
|
|
float AzimSector::operator() (const osg::Vec3& eyeLocal) const
|
|
{
|
|
return azimSector(eyeLocal);
|
|
}
|
|
|
|
//
|
|
// ElevationSector
|
|
//
|
|
ElevationSector::ElevationSector(float minElevation,float maxElevation,float fadeAngle):
|
|
Sector(),
|
|
ElevationRange()
|
|
{
|
|
setElevationRange(minElevation,maxElevation,fadeAngle);
|
|
}
|
|
|
|
float ElevationSector::operator() (const osg::Vec3& eyeLocal) const
|
|
{
|
|
return elevationSector(eyeLocal);
|
|
}
|
|
|
|
//
|
|
// AzimElevationSector
|
|
//
|
|
AzimElevationSector::AzimElevationSector(float minAzimuth,float maxAzimuth,float minElevation,float maxElevation,float fadeAngle):
|
|
Sector(),
|
|
AzimRange(),
|
|
ElevationRange()
|
|
{
|
|
setAzimuthRange(minAzimuth,maxAzimuth,fadeAngle);
|
|
setElevationRange(minElevation,maxElevation,fadeAngle);
|
|
}
|
|
|
|
|
|
float AzimElevationSector::operator() (const osg::Vec3& eyeLocal) const
|
|
{
|
|
float azimIntensity = azimSector(eyeLocal);
|
|
if (azimIntensity==0.0) return 0.0; // out of sector.
|
|
float elevIntensity = elevationSector(eyeLocal);
|
|
if (elevIntensity==0.0) return 0.0; // out of sector.
|
|
if (azimIntensity<=elevIntensity) return azimIntensity;
|
|
return elevIntensity;
|
|
}
|
|
|
|
//
|
|
// ConeSector
|
|
//
|
|
ConeSector::ConeSector(const osg::Vec3& axis,float angle,float fadeangle):
|
|
Sector()
|
|
{
|
|
setAxis(axis);
|
|
setAngle(angle,fadeangle);
|
|
}
|
|
|
|
void ConeSector::setAxis(const osg::Vec3& axis)
|
|
{
|
|
_axis = axis;
|
|
_axis.normalize();
|
|
}
|
|
|
|
const osg::Vec3& ConeSector::getAxis() const
|
|
{
|
|
return _axis;
|
|
}
|
|
|
|
void ConeSector::setAngle(float angle,float fadeangle)
|
|
{
|
|
_cosAngle = cos(angle);
|
|
_cosAngleFade = cos(angle+fadeangle);
|
|
}
|
|
|
|
float ConeSector::getAngle() const
|
|
{
|
|
return acos(_cosAngle);
|
|
}
|
|
|
|
float ConeSector::getFadeAngle() const
|
|
{
|
|
return acos(_cosAngleFade)-acos(_cosAngle);
|
|
}
|
|
|
|
float ConeSector::operator() (const osg::Vec3& eyeLocal) const
|
|
{
|
|
float dotproduct = eyeLocal*_axis;
|
|
float length = eyeLocal.length();
|
|
if (dotproduct>_cosAngle*length) return 1.0f; // fully in sector
|
|
if (dotproduct<_cosAngleFade*length) return 0.0f; // out of sector
|
|
return (dotproduct-_cosAngleFade*length)/((_cosAngle-_cosAngleFade)*length);
|
|
}
|
|
|
|
//
|
|
// DirectionalSector
|
|
//
|
|
DirectionalSector::DirectionalSector(const osg::Vec3& direction,float horizLobeAngle, float vertLobeAngle, float lobeRollAngle, float fadeAngle):
|
|
Sector()
|
|
{
|
|
setDirection(direction);
|
|
setHorizLobeAngle(horizLobeAngle);
|
|
setVertLobeAngle(vertLobeAngle);
|
|
setLobeRollAngle(lobeRollAngle);
|
|
setFadeAngle(fadeAngle);
|
|
}
|
|
|
|
void DirectionalSector::computeMatrix()
|
|
{
|
|
double heading = atan2(_direction[0], _direction[1]);
|
|
double pitch = atan2(_direction[2], sqrt(_direction[0]*_direction[0] + _direction[1]*_direction[1]));
|
|
double roll = _rollAngle;
|
|
|
|
_local_to_LP.setRotate(osg::Quat(heading,osg::Vec3d(0.0, 0.0, -1.0)));
|
|
_local_to_LP.preMultRotate(osg::Quat(pitch, osg::Vec3d(1.0, 0.0, 0.0)));
|
|
_local_to_LP.preMultRotate(osg::Quat(roll, osg::Vec3d(0.0, 1.0, 0.0)));
|
|
}
|
|
|
|
void DirectionalSector::setDirection(const osg::Vec3& direction)
|
|
{
|
|
_direction = direction ;
|
|
computeMatrix() ;
|
|
}
|
|
|
|
const osg::Vec3& DirectionalSector::getDirection() const
|
|
{
|
|
return _direction;
|
|
}
|
|
|
|
void DirectionalSector::setHorizLobeAngle(float angle)
|
|
{
|
|
_cosHorizAngle = cos(angle*0.5);
|
|
}
|
|
|
|
float DirectionalSector::getHorizLobeAngle() const
|
|
{
|
|
return acos(_cosHorizAngle)*2.0;
|
|
}
|
|
|
|
void DirectionalSector::setVertLobeAngle(float angle)
|
|
{
|
|
_cosVertAngle = cos(angle*0.5);
|
|
}
|
|
|
|
float DirectionalSector::getVertLobeAngle() const
|
|
{
|
|
return acos(_cosVertAngle)*2.0;
|
|
}
|
|
|
|
void DirectionalSector::setLobeRollAngle(float angle)
|
|
{
|
|
_rollAngle = angle ;
|
|
computeMatrix() ;
|
|
}
|
|
|
|
float DirectionalSector::getLobeRollAngle() const
|
|
{
|
|
return _rollAngle ;
|
|
}
|
|
|
|
void DirectionalSector::setFadeAngle(float angle)
|
|
{
|
|
float ang = acos(_cosHorizAngle)+angle ;
|
|
if ( ang > osg::PI ) _cosHorizFadeAngle = -1.0 ;
|
|
else _cosHorizFadeAngle = cos(ang);
|
|
|
|
ang = acos(_cosVertAngle)+angle ;
|
|
if ( ang > osg::PI ) _cosVertFadeAngle = -1.0 ;
|
|
else _cosVertFadeAngle = cos(ang);
|
|
}
|
|
|
|
float DirectionalSector::getFadeAngle() const
|
|
{
|
|
return acos(_cosHorizFadeAngle)-acos(_cosHorizAngle);
|
|
}
|
|
|
|
float DirectionalSector::operator() (const osg::Vec3& eyeLocal) const
|
|
{
|
|
float elev_intensity, azim_intensity ;
|
|
|
|
// Tranform eyeLocal into the LightPoint frame
|
|
osg::Vec3 EPlp = _local_to_LP * eyeLocal ;
|
|
|
|
/*fprintf(stderr, " eyeLocal = %f, %f, %f\n", eyeLocal[0], eyeLocal[1], eyeLocal[2]) ;
|
|
fprintf(stderr, " EPlp = %f, %f, %f\n", EPlp[0], EPlp[1], EPlp[2]) ;*/
|
|
|
|
// Elevation check
|
|
// Project EPlp into LP YZ plane and dot with LPy
|
|
osg::Vec2 EPyz(EPlp[1], EPlp[2]) ;
|
|
EPyz.normalize() ;
|
|
/*fprintf(stderr, " EPyz.normalize() = %f, %f\n", EPyz[0], EPyz[1]) ;
|
|
fprintf(stderr, " _cosVertFadeAngle = %f\n", _cosVertFadeAngle) ;
|
|
fprintf(stderr, " _cosVertAngle = %f\n", _cosVertAngle) ;*/
|
|
// cosElev = EPyz* LPy = EPyz[0]
|
|
if ( EPyz[0] < _cosVertFadeAngle ) {
|
|
// Completely outside elevation range
|
|
//fprintf(stderr, " >> outside el range\n") ;
|
|
return(0.0f) ;
|
|
}
|
|
if ( EPyz[0] < _cosVertAngle ) {
|
|
// In the fade range
|
|
//fprintf(stderr, " >> inside el fade range\n") ;
|
|
elev_intensity = (EPyz[0]-_cosVertFadeAngle)/(_cosVertAngle-_cosVertFadeAngle) ;
|
|
} else {
|
|
// Fully in elevation range
|
|
elev_intensity = 1.0 ;
|
|
//fprintf(stderr, " >> fully inside el range\n") ;
|
|
}
|
|
// Elevation check passed
|
|
|
|
// Azimuth check
|
|
// Project EPlp into LP XY plane and dot with LPy
|
|
osg::Vec2 EPxy(EPlp[0], EPlp[1]) ;
|
|
EPxy.normalize() ;
|
|
/*fprintf(stderr, " EPxy.normalize() = %f, %f\n", EPxy[0], EPxy[1]) ;
|
|
fprintf(stderr, " _cosHorizFadeAngle = %f\n", _cosHorizFadeAngle) ;
|
|
fprintf(stderr, " _cosHorizAngle = %f\n", _cosHorizAngle) ;*/
|
|
// cosAzim = EPxy * LPy = EPxy[1]
|
|
// if cosElev < 0.0, then need to negate EP for azimuth check
|
|
if ( EPyz[0] < 0.0 ) EPxy.set(-EPxy[0], -EPxy[1]) ;
|
|
if ( EPxy[1] < _cosHorizFadeAngle ) {
|
|
// Completely outside azimuth range
|
|
//fprintf(stderr, " >> outside az range\n") ;
|
|
return(0.0f) ;
|
|
}
|
|
if ( EPxy[1] < _cosHorizAngle ) {
|
|
// In fade range
|
|
//fprintf(stderr, " >> inside az fade range\n") ;
|
|
azim_intensity = (EPxy[1]-_cosHorizFadeAngle)/(_cosHorizAngle-_cosHorizFadeAngle) ;
|
|
} else {
|
|
// Fully in azimuth range
|
|
//fprintf(stderr, " >> fully inside az range\n") ;
|
|
azim_intensity = 1.0 ;
|
|
}
|
|
// Azimuth check passed
|
|
|
|
// We're good! Return full intensity
|
|
//fprintf(stderr, " %%%% Returing intensity = %f\n", elev_intensity * azim_intensity) ;
|
|
return elev_intensity * azim_intensity ;
|
|
}
|