1
0
Fork 0
flightgear/src/Scenery/hitlist.cxx

689 lines
22 KiB
C++
Raw Normal View History

// hitlist.cxx -
// Height Over Terrain and Assosciated Routines for FlightGear based Scenery
// Written by Norman Vine, started 2000.
2000-06-16 02:15:08 +00:00
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
2000-09-06 00:11:01 +00:00
#include <float.h>
2000-06-16 02:15:08 +00:00
#include <math.h>
#include <plib/sg.h>
#include <plib/ssg.h>
2001-03-24 14:56:37 +00:00
#include <simgear/sg_inlines.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/point3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
2000-06-16 02:15:08 +00:00
#include <simgear/math/vector.hxx>
2003-11-22 12:03:10 +00:00
#include <simgear/timing/timestamp.hxx>
2000-06-16 02:15:08 +00:00
#include <Main/globals.hxx>
#include <Main/viewer.hxx>
#include <Scenery/scenery.hxx>
2000-06-16 02:15:08 +00:00
#include "hitlist.hxx"
// Specialized version of sgMultMat4 needed because of mixed matrix
// types
static inline void sgMultMat4(sgdMat4 dst, sgdMat4 m1, sgMat4 m2) {
for ( int j = 0 ; j < 4 ; j++ ) {
dst[0][j] = m2[0][0] * m1[0][j] +
m2[0][1] * m1[1][j] +
m2[0][2] * m1[2][j] +
m2[0][3] * m1[3][j] ;
dst[1][j] = m2[1][0] * m1[0][j] +
m2[1][1] * m1[1][j] +
m2[1][2] * m1[2][j] +
m2[1][3] * m1[3][j] ;
dst[2][j] = m2[2][0] * m1[0][j] +
m2[2][1] * m1[1][j] +
m2[2][2] * m1[2][j] +
m2[2][3] * m1[3][j] ;
dst[3][j] = m2[3][0] * m1[0][j] +
m2[3][1] * m1[1][j] +
m2[3][2] * m1[2][j] +
m2[3][3] * m1[3][j] ;
}
}
/*
* Walk backwards up the tree, transforming the vertex by all the
* matrices along the way.
*
* Upwards recursion hurts my head.
*/
static void ssgGetEntityTransform(ssgEntity *entity, sgMat4 m ) {
sgMat4 mat ;
// If this node has a parent - get the composite matrix for the
// parent.
if ( entity->getNumParents() > 0 )
ssgGetEntityTransform ( entity->getParent(0), mat ) ;
else
sgMakeIdentMat4 ( mat ) ;
// If this node has a transform - then concatenate it.
if ( entity -> isAKindOf ( ssgTypeTransform () ) ) {
sgMat4 this_mat ;
((ssgTransform *) entity) -> getTransform ( this_mat ) ;
sgPostMultMat4 ( mat, this_mat ) ;
}
sgCopyMat4 ( m, mat ) ;
}
// return the passed entitity's bsphere's center point radius and
// fully formed current model matrix for entity
static inline void ssgGetCurrentBSphere( ssgEntity *entity, sgVec3 center,
float *radius, sgMat4 m )
{
sgSphere *bsphere = entity->getBSphere();
*radius = (double)bsphere->getRadius();
sgCopyVec3( center, bsphere->getCenter() );
sgMakeIdentMat4 ( m ) ;
ssgGetEntityTransform( entity, m );
}
// This is same as PLib's sgdIsectInfLinePlane() and can be replaced
// by it after the next PLib release
static inline bool fgdIsectInfLinePlane( sgdVec3 dst,
const sgdVec3 l_org,
const sgdVec3 l_vec,
const sgdVec4 plane )
2000-06-16 02:15:08 +00:00
{
SGDfloat tmp = sgdScalarProductVec3 ( l_vec, plane ) ;
/* Is line parallel to plane? */
2000-06-16 02:15:08 +00:00
if ( fabs ( tmp ) < FLT_EPSILON )
return false ;
sgdScaleVec3 ( dst, l_vec, -( sgdScalarProductVec3 ( l_org, plane )
+ plane[3] ) / tmp ) ;
2000-06-16 02:15:08 +00:00
sgdAddVec3 ( dst, l_org ) ;
return true ;
}
/*
* Given a point and a triangle lying on the same plane check to see
* if the point is inside the triangle
*
* This is same as PLib's sgdPointInTriangle() and can be replaced by
* it after the next PLib release
*/
static inline bool fgdPointInTriangle( sgdVec3 point, sgdVec3 tri[3] )
{
sgdVec3 dif;
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
// Some tolerance in meters we accept a point to be outside of the triangle
// and still return that it is inside.
SGDfloat eps = 1e-4;
SGDfloat min, max;
// punt if outside bouding cube
SG_MIN_MAX3 ( min, max, tri[0][0], tri[1][0], tri[2][0] );
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
if( (point[0] < min - eps) || (point[0] > max + eps) )
return false;
dif[0] = max - min;
SG_MIN_MAX3 ( min, max, tri[0][1], tri[1][1], tri[2][1] );
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
if( (point[1] < min - eps) || (point[1] > max + eps) )
return false;
dif[1] = max - min;
SG_MIN_MAX3 ( min, max, tri[0][2], tri[1][2], tri[2][2] );
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
if( (point[2] < min - eps) || (point[2] > max + eps) )
return false;
dif[2] = max - min;
// drop the smallest dimension so we only have to work in 2d.
SGDfloat min_dim = SG_MIN3 (dif[0], dif[1], dif[2]);
SGDfloat x1, y1, x2, y2, x3, y3, rx, ry;
if ( fabs(min_dim-dif[0]) <= DBL_EPSILON ) {
// x is the smallest dimension
x1 = point[1];
y1 = point[2];
x2 = tri[0][1];
y2 = tri[0][2];
x3 = tri[1][1];
y3 = tri[1][2];
rx = tri[2][1];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[1]) <= DBL_EPSILON ) {
// y is the smallest dimension
x1 = point[0];
y1 = point[2];
x2 = tri[0][0];
y2 = tri[0][2];
x3 = tri[1][0];
y3 = tri[1][2];
rx = tri[2][0];
ry = tri[2][2];
} else if ( fabs(min_dim-dif[2]) <= DBL_EPSILON ) {
// z is the smallest dimension
x1 = point[0];
y1 = point[1];
x2 = tri[0][0];
y2 = tri[0][1];
x3 = tri[1][0];
y3 = tri[1][1];
rx = tri[2][0];
ry = tri[2][1];
} else {
// all dimensions are really small so lets call it close
// enough and return a successful match
return true;
}
// check if intersection point is on the same side of p1 <-> p2 as p3
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
SGDfloat tmp = (y2 - y3);
SGDfloat tmpn = (x2 - x3);
int side1 = SG_SIGN (tmp * (rx - x3) + (y3 - ry) * tmpn);
int side2 = SG_SIGN (tmp * (x1 - x3) + (y3 - side1*eps - y1) * tmpn);
if ( side1 != side2 ) {
// printf("failed side 1 check\n");
return false;
}
// check if intersection point is on correct side of p2 <-> p3 as p1
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
tmp = (y3 - ry);
tmpn = (x3 - rx);
side1 = SG_SIGN (tmp * (x2 - rx) + (ry - y2) * tmpn);
side2 = SG_SIGN (tmp * (x1 - rx) + (ry - side1*eps - y1) * tmpn);
if ( side1 != side2 ) {
// printf("failed side 2 check\n");
return false;
}
// check if intersection point is on correct side of p1 <-> p3 as p2
Mathias Frhlich: 2. I made YASim query the the ground cache at the wrong place. This one fixed this, one can now land the bo105 on top of the oracle buildings :) 3. Is a followup of the scenery center update code: Register the scenery center transform at the time it is put into the scene graph not at creation time. 4. I held that part back from the past hitlist patch, because I hoped that it will be sufficient (and the last one was in fact the biggest part) without. As some test cases from Melchior showed me, it is not. We have additionally to the wrong computed transform from the prevous patch some roundoff problems. This patch adds some small tolerance to for the point in triangle test. ... may be one even needs to increase the eps value further if starting at some tile boundaries still fails. 5. That is a big chunk. Tested now for two days while hunting the second patch :) . That is a partial rewrite of the groundcache to use its own datastructures for that flat scenegraph in the cache. The basic advantage is, what Erik suggested, to precompute some often used values of these triangles. Also allmost all computations are now in double precision which should decrease (hopefully fix), together with a similar tolerance for some point in triangle tests, the problems with 'no ground below aircraft'. I am playing with octrees for the groundcache, that will finally solve the performance problem when high triangular count models end up in the groundcache. This patch is also some prework for those octrees ...
2005-05-30 08:48:27 +00:00
tmp = (y2 - ry);
tmpn = (x2 - rx);
side1 = SG_SIGN (tmp * (x3 - rx) + (ry - y3) * tmpn);
side2 = SG_SIGN (tmp * (x1 - rx) + (ry - side1*eps - y1) * tmpn);
if ( side1 != side2 ) {
// printf("failed side 3 check\n");
return false;
}
return true;
}
2000-06-16 02:15:08 +00:00
// Check if all three vertices are the same point (or close enough)
static inline int isZeroAreaTri( sgdVec3 tri[3] )
{
return( sgdEqualVec3(tri[0], tri[1]) ||
sgdEqualVec3(tri[1], tri[2]) ||
sgdEqualVec3(tri[2], tri[0]) );
}
// Constructor
FGHitList::FGHitList() :
last(NULL), test_dist(DBL_MAX)
{
}
// Destructor
FGHitList::~FGHitList() {}
2000-06-16 02:15:08 +00:00
/*
Find the intersection of an infinite line with a leaf the line being
defined by a point and direction.
Variables
In:
ssgLeaf pointer -- leaf
qualified matrix -- m
line origin -- orig
line direction -- dir
Out:
result -- intersection point
normal -- intersected tri's normal
Returns:
true if intersection found
false otherwise
!!! WARNING !!!
If you need an exhaustive list of hitpoints YOU MUST use the generic
version of this function as the specialized versions will do an early
out of expensive tests if the point can not be the closest one found
!!! WARNING !!!
2000-06-16 02:15:08 +00:00
*/
int FGHitList::IntersectLeaf( ssgLeaf *leaf, sgdMat4 m,
sgdVec3 orig, sgdVec3 dir )
2000-06-16 02:15:08 +00:00
{
int num_hits = 0;
int i = 0;
for ( ; i < leaf->getNumTriangles(); ++i ) {
short i1, i2, i3;
leaf->getTriangle( i, &i1, &i2, &i3 );
sgdVec3 tri[3];
sgdSetVec3( tri[0], leaf->getVertex( i1 ) );
sgdSetVec3( tri[1], leaf->getVertex( i2 ) );
sgdSetVec3( tri[2], leaf->getVertex( i3 ) );
if( isZeroAreaTri( tri ) )
continue;
sgdVec4 plane;
sgdMakePlane( plane, tri[0], tri[1], tri[2] );
sgdVec3 point;
if( fgdIsectInfLinePlane( point, orig, dir, plane ) ) {
if( fgdPointInTriangle( point, tri ) ) {
// transform point into passed into desired coordinate frame
sgdXformPnt3( point, point, m );
sgdXformPnt4(plane,plane,m);
add(leaf,i,point,plane);
num_hits++;
}
}
}
return num_hits;
}
// Short circuit/slightly optimized version of the full IntersectLeaf()
int FGHitList::IntersectLeaf( ssgLeaf *leaf, sgdMat4 m,
sgdVec3 orig, sgdVec3 dir,
GLenum primType )
{
double tmp_dist;
// number of hits but there could be more that
// were not found because of short circut switch !
// so you may want to use the unspecialized IntersectLeaf()
int n, num_hits = 0;
int ntri = leaf->getNumTriangles();
for ( n = 0; n < ntri; ++n )
{
sgdVec3 tri[3];
switch ( primType )
{
case GL_POLYGON :
SG_LOG( SG_TERRAIN, SG_ALERT,
"WARNING: dubiously handled GL_POLYGON" );
case GL_TRIANGLE_FAN :
/* SG_LOG( SG_TERRAIN, SG_ALERT,
"IntersectLeaf: GL_TRIANGLE_FAN" ); */
if ( !n ) {
sgdSetVec3( tri[0], leaf->getVertex( short(0) ) );
sgdSetVec3( tri[1], leaf->getVertex( short(1) ) );
sgdSetVec3( tri[2], leaf->getVertex( short(2) ) );
} else {
sgdCopyVec3( tri[1], tri[2] );
sgdSetVec3( tri[2], leaf->getVertex( short(n+2) ) );
}
break;
case GL_TRIANGLES :
/* SG_LOG( SG_TERRAIN, SG_DEBUG,
"IntersectLeaf: GL_TRIANGLES" ); */
sgdSetVec3( tri[0], leaf->getVertex( short(n*3) ) );
sgdSetVec3( tri[1], leaf->getVertex( short(n*3+1) ) );
sgdSetVec3( tri[2], leaf->getVertex( short(n*3+2) ) );
break;
case GL_QUAD_STRIP :
SG_LOG( SG_TERRAIN, SG_ALERT,
"WARNING: dubiously handled GL_QUAD_STRIP" );
case GL_TRIANGLE_STRIP :
/* SG_LOG( SG_TERRAIN, SG_ALERT,
"IntersectLeaf: GL_TRIANGLE_STRIP" ); */
if ( !n ) {
sgdSetVec3( tri[0], leaf->getVertex( short(0) ) );
sgdSetVec3( tri[1], leaf->getVertex( short(1) ) );
sgdSetVec3( tri[2], leaf->getVertex( short(2) ) );
} else {
if ( n & 1 ) {
sgdCopyVec3( tri[0], tri[2] );
sgdSetVec3( tri[2], leaf->getVertex( short(n+2) ) );
} else {
sgdCopyVec3( tri[1], tri[2] );
sgdSetVec3( tri[2], leaf->getVertex( short(n+2) ) );
}
}
break;
case GL_QUADS :
SG_LOG( SG_TERRAIN, SG_ALERT,
"WARNING: dubiously handled GL_QUADS" );
sgdSetVec3( tri[0], leaf->getVertex( short(n*2) ) );
sgdSetVec3( tri[1], leaf->getVertex( short(n*2+1) ) );
sgdSetVec3( tri[2], leaf->getVertex( short(n*2 + 2 - (n&1)*4) ) );
break;
default:
SG_LOG( SG_TERRAIN, SG_ALERT,
"WARNING: not-handled structure: " << primType );
return IntersectLeaf( leaf, m, orig, dir);
}
if( isZeroAreaTri( tri ) )
continue;
sgdVec4 plane;
sgdMakePlane( plane, tri[0], tri[1], tri[2] );
sgdVec3 point;
// find point of intersection of line from point org
// in direction dir with triangle's plane
SGDfloat tmp = sgdScalarProductVec3 ( dir, plane ) ;
/* Is line parallel to plane? */
if ( sgdAbs ( tmp ) < FLT_EPSILON /*DBL_EPSILON*/ )
continue ;
// find parametric point
sgdScaleVec3 ( point, dir,
-( sgdScalarProductVec3 ( orig, plane ) + plane[3] )
/ tmp ) ;
// short circut if this point is further away then a previous hit
tmp_dist = sgdDistanceSquaredVec3(point, orig );
if( tmp_dist > test_dist )
continue;
// place parametric point in world
sgdAddVec3 ( point, orig ) ;
if( fgdPointInTriangle( point, tri ) ) {
// transform point into passed coordinate frame
sgdXformPnt3( point, point, m );
sgdXformPnt4(plane,plane,m);
add(leaf,n,point,plane);
test_dist = tmp_dist;
num_hits++;
}
}
return num_hits;
}
inline static bool IN_RANGE( sgdVec3 v, double radius ) {
return ( sgdScalarProductVec3(v, v) < (radius*radius) );
}
void FGHitList::IntersectBranch( ssgBranch *branch, sgdMat4 m,
sgdVec3 orig, sgdVec3 dir )
{
/* the lookat vector and matrix in branch's coordinate frame but
* we won't determine these unless needed, This 'lazy evaluation'
* is a result of profiling data */
sgdVec3 orig_leaf, dir_leaf;
sgdMat4 m_leaf;
// 'lazy evaluation' flag
int first_time = 1;
for ( ssgEntity *kid = branch->getKid( 0 );
kid != NULL;
kid = branch->getNextKid() )
{
if ( kid->getTraversalMask() & SSGTRAV_HOT
&& !kid->getBSphere()->isEmpty() )
{
sgdVec3 center;
sgdSetVec3( center,
kid->getBSphere()->getCenter()[0],
kid->getBSphere()->getCenter()[1],
kid->getBSphere()->getCenter()[2] );
sgdXformPnt3( center, m ) ;
// sgdClosestPointToLineDistSquared( center, orig, dir )
// inlined here because because of profiling results
sgdVec3 u, u1, v;
sgdSubVec3(u, center, orig);
sgdScaleVec3( u1, dir, sgdScalarProductVec3(u,dir)
/ sgdScalarProductVec3(dir,dir) );
sgdSubVec3(v, u, u1);
// double because of possible overflow
if ( IN_RANGE( v, double(kid->getBSphere()->getRadius()) ) )
{
if ( kid->isAKindOf ( ssgTypeBranch() ) )
{
sgdMat4 m_new;
if ( kid->isA( ssgTypeTransform() ) )
{
sgMat4 fxform;
((ssgTransform *)kid)->getTransform( fxform );
sgMultMat4(m_new, m, fxform);
} else {
sgdCopyMat4(m_new, m);
}
IntersectBranch( (ssgBranch *)kid, m_new, orig, dir );
}
else if ( kid->isAKindOf( ssgTypeLeaf() ) )
{
if ( first_time ) {
sgdTransposeNegateMat4( m_leaf, m );
sgdXformPnt3( orig_leaf, orig, m_leaf );
sgdXformVec3( dir_leaf, dir, m_leaf );
first_time = 0;
}
// GLenum primType = ((ssgLeaf *)kid)->getPrimitiveType();
// IntersectLeaf( (ssgLeaf *)kid, m, orig_leaf, dir_leaf,
// primType );
IntersectLeaf( (ssgLeaf *)kid, m, orig_leaf, dir_leaf );
}
} // Out of range
} // branch not requested to be traversed
} // end for loop
}
// a temporary hack until we get everything rewritten with sgdVec3
static inline Point3D operator + (const Point3D& a, const sgdVec3 b)
{
return Point3D(a.x()+b[0], a.y()+b[1], a.z()+b[2]);
}
void FGHitList::Intersect( ssgBranch *scene, sgdVec3 orig, sgdVec3 dir ) {
sgdMat4 m;
clear();
sgdMakeIdentMat4 ( m ) ;
IntersectBranch( scene, m, orig, dir );
2000-06-16 02:15:08 +00:00
}
void FGHitList::Intersect( ssgBranch *scene, sgdMat4 m, sgdVec3 orig, sgdVec3 dir )
{
clear();
IntersectBranch( scene, m, orig, dir );
}
2000-06-16 02:15:08 +00:00
// Determine scenery altitude via ssg.
// returned results are in meters
// static double hitlist1_time = 0.0;
bool fgCurrentElev( sgdVec3 abs_view_pos, double max_alt_m,
sgdVec3 scenery_center,
2002-03-18 19:02:59 +00:00
FGHitList *hit_list,
double *terrain_elev, double *radius, double *normal)
{
// SGTimeStamp start; start.stamp();
bool result;
2002-03-18 19:02:59 +00:00
sgdVec3 view_pos;
sgdSubVec3( view_pos, abs_view_pos, scenery_center );
sgdVec3 orig, dir;
sgdCopyVec3(orig, view_pos );
sgdCopyVec3(dir, abs_view_pos );
hit_list->Intersect( globals->get_scenery()->get_terrain_branch(),
orig, dir );
2002-03-18 19:02:59 +00:00
int this_hit = -1;
int max_hit = -1;
2002-03-18 19:02:59 +00:00
Point3D geoc;
double hit_elev = -9999;
double max_elev = -9999;
2002-03-18 19:02:59 +00:00
Point3D sc(scenery_center[0], scenery_center[1], scenery_center[2]) ;
int hitcount = hit_list->num_hits();
// cout << "hits = " << hitcount << endl;
2002-03-18 19:02:59 +00:00
for ( int i = 0; i < hitcount; ++i ) {
// FIXME: sgCartToGeod is slow. Call it just once for the
// "sc" point, and then handle the rest with a geodetic "up"
// vector approximation. Across one tile, this will be
// acceptable.
double alt = sgCartToGeod( sc + hit_list->get_point(i) ).elev();
// cout << "hit " << i << " lon = " << geoc.lon() << " lat = "
// << lat_geod << " alt = " << alt << " max alt = " << max_alt_m
// << endl;
if ( alt > hit_elev && alt < max_alt_m ) {
// cout << " it's a keeper" << endl;
hit_elev = alt;
2002-03-18 19:02:59 +00:00
this_hit = i;
}
if ( alt > hit_elev ) {
max_elev = alt;
max_hit = i;
}
}
if ( this_hit < 0 ) {
// no hits below us, take the max hit
this_hit = max_hit;
hit_elev = max_elev;
2002-03-18 19:02:59 +00:00
}
if ( hit_elev > -9000 ) {
*terrain_elev = hit_elev;
2002-03-18 19:02:59 +00:00
*radius = geoc.radius();
sgVec3 tmp;
sgSetVec3(tmp, hit_list->get_normal(this_hit));
// cout << "cur_normal: " << tmp[0] << " " << tmp[1] << " " << tmp[2] << endl;
sgdSetVec3( normal, tmp );
// float *up = globals->get_current_view()->get_world_up();
// cout << "world_up : " << up[0] << " " << up[1] << " " << up[2] << endl;
2002-03-18 19:02:59 +00:00
/* ssgState *IntersectedLeafState =
((ssgLeaf*)hit_list->get_entity(this_hit))->getState(); */
result = true;
2002-03-18 19:02:59 +00:00
} else {
SG_LOG( SG_TERRAIN, SG_INFO, "no terrain intersection" );
*terrain_elev = 0.0;
float *up = globals->get_current_view()->get_world_up();
sgdSetVec3(normal, up[0], up[1], up[2]);
result = false;
2002-03-18 19:02:59 +00:00
}
// SGTimeStamp finish; finish.stamp();
// hitlist1_time = ( 29.0 * hitlist1_time + (finish - start) ) / 30.0;
// cout << " time per call = " << hitlist1_time << endl;
return result;
}
// static double hitlist2_time = 0.0;
// Determine scenery altitude via ssg.
// returned results are in meters
bool fgCurrentElev( sgdVec3 abs_view_pos, double max_alt_m,
sgdVec3 scenery_center,
2002-03-18 19:02:59 +00:00
ssgTransform *terra_transform,
FGHitList *hit_list,
double *terrain_elev, double *radius, double *normal)
{
// SGTimeStamp start; start.stamp();
bool result;
2002-03-18 19:02:59 +00:00
sgdVec3 view_pos;
sgdSubVec3( view_pos, abs_view_pos, scenery_center );
sgdVec3 orig, dir;
sgdCopyVec3(orig, view_pos );
sgdCopyVec3(dir, abs_view_pos );
sgdNormalizeVec3(dir);
sgMat4 fxform;
sgMakeIdentMat4 ( fxform ) ;
ssgGetEntityTransform( terra_transform, fxform );
sgdMat4 xform;
sgdSetMat4(xform,fxform);
hit_list->Intersect( terra_transform, xform, orig, dir );
int this_hit = -1;
int max_hit = -1;
2002-03-18 19:02:59 +00:00
Point3D geoc;
double hit_elev = -9999;
double max_elev = -9999;
2002-03-18 19:02:59 +00:00
Point3D sc(scenery_center[0], scenery_center[1], scenery_center[2]) ;
int hitcount = hit_list->num_hits();
// cout << "hits = " << hitcount << endl;
2002-03-18 19:02:59 +00:00
for ( int i = 0; i < hitcount; ++i ) {
// FIXME: sgCartToGeod is slow. Call it just once for the
// "sc" point, and then handle the rest with a geodetic "up"
// vector approximation. Across one tile, this will be
// acceptable.
double alt = sgCartToGeod( sc + hit_list->get_point(i) ).elev();
// cout << "hit " << i << " lon = " << geoc.lon() << " lat = "
// << lat_geod << " alt = " << alt << " max alt = " << max_alt_m
// << endl;
if ( alt > hit_elev && alt < max_alt_m ) {
hit_elev = alt;
2002-03-18 19:02:59 +00:00
this_hit = i;
// cout << " it's a keeper" << endl;
2002-03-18 19:02:59 +00:00
}
if ( alt > hit_elev ) {
max_elev = alt;
max_hit = i;
}
}
if ( this_hit < 0 ) {
// no hits below us, take the max hit
this_hit = max_hit;
hit_elev = max_elev;
2002-03-18 19:02:59 +00:00
}
if ( hit_elev > -9000 ) {
*terrain_elev = hit_elev;
2002-03-18 19:02:59 +00:00
*radius = geoc.radius();
sgVec3 tmp;
sgSetVec3(tmp, hit_list->get_normal(this_hit));
// cout << "cur_normal: " << tmp[0] << " " << tmp[1] << " " << tmp[2] << endl;
sgdSetVec3( normal, tmp );
// float *up = globals->get_current_view()->get_world_up();
// cout << "world_up : " << up[0] << " " << up[1] << " " << up[2] << endl;
2002-03-18 19:02:59 +00:00
/* ssgState *IntersectedLeafState =
((ssgLeaf*)hit_list->get_entity(this_hit))->getState(); */
result = true;
2002-03-18 19:02:59 +00:00
} else {
SG_LOG( SG_TERRAIN, SG_DEBUG, "DOING FULL TERRAIN INTERSECTION" );
result = fgCurrentElev( abs_view_pos, max_alt_m, scenery_center,
hit_list, terrain_elev, radius, normal);
2002-03-18 19:02:59 +00:00
}
// SGTimeStamp finish; finish.stamp();
// hitlist2_time = ( 29.0 * hitlist2_time + (finish - start) ) / 30.0;
// cout << "time per call 2 = " << hitlist2_time << endl;
return result;
}