2005-04-15 05:41:28 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
2003-01-22 00:45:36 +08:00
*
* 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 .
*/
2001-10-22 05:27:40 +08:00
# include <osgUtil/IntersectVisitor>
# include <osg/Transform>
# include <osg/Geode>
# include <osg/LOD>
# include <osg/Billboard>
# include <osg/Notify>
2002-12-17 01:00:05 +08:00
# include <osg/TriangleFunctor>
2003-04-25 21:47:33 +08:00
# include <osg/Geometry>
2005-12-07 18:25:50 +08:00
# include <osg/Projection>
# include <osg/CameraNode>
2005-04-08 17:01:23 +08:00
# include <osg/io_utils>
2001-01-11 00:32:10 +08:00
# include <float.h>
# include <algorithm>
# include <map>
using namespace osg ;
using namespace osgUtil ;
2002-01-30 20:09:18 +08:00
Hit : : Hit ( )
2001-01-11 00:32:10 +08:00
{
}
2001-09-20 05:08:56 +08:00
2002-01-30 20:09:18 +08:00
Hit : : Hit ( const Hit & hit )
2001-01-11 00:32:10 +08:00
{
2002-01-30 20:09:18 +08:00
// copy data across.
_ratio = hit . _ratio ;
_originalLineSegment = hit . _originalLineSegment ;
_localLineSegment = hit . _localLineSegment ;
_nodePath = hit . _nodePath ;
_geode = hit . _geode ;
2002-06-26 04:27:51 +08:00
_drawable = hit . _drawable ;
2002-01-30 20:09:18 +08:00
_matrix = hit . _matrix ;
_inverse = hit . _inverse ;
_vecIndexList = hit . _vecIndexList ;
_primitiveIndex = hit . _primitiveIndex ;
_intersectPoint = hit . _intersectPoint ;
_intersectNormal = hit . _intersectNormal ;
}
Hit : : ~ Hit ( )
{
}
Hit & Hit : : operator = ( const Hit & hit )
{
if ( & hit = = this ) return * this ;
_matrix = hit . _matrix ;
_inverse = hit . _inverse ;
_originalLineSegment = hit . _originalLineSegment ;
_localLineSegment = hit . _localLineSegment ;
// copy data across.
_ratio = hit . _ratio ;
_nodePath = hit . _nodePath ;
_geode = hit . _geode ;
2002-06-26 04:27:51 +08:00
_drawable = hit . _drawable ;
2002-01-30 20:09:18 +08:00
_vecIndexList = hit . _vecIndexList ;
_primitiveIndex = hit . _primitiveIndex ;
_intersectPoint = hit . _intersectPoint ;
_intersectNormal = hit . _intersectNormal ;
return * this ;
}
const osg : : Vec3 Hit : : getWorldIntersectNormal ( ) const
{
if ( _inverse . valid ( ) )
2001-01-11 00:32:10 +08:00
{
2002-01-30 20:09:18 +08:00
osg : : Vec3 norm = osg : : Matrix : : transform3x3 ( * _inverse , _intersectNormal ) ;
norm . normalize ( ) ;
return norm ;
2001-01-11 00:32:10 +08:00
}
2002-01-30 20:09:18 +08:00
else return _intersectNormal ;
}
2001-01-11 00:32:10 +08:00
2002-01-30 20:09:18 +08:00
IntersectVisitor : : IntersectState : : IntersectState ( )
{
_segmentMaskStack . push_back ( 0xffffffff ) ;
2001-01-11 00:32:10 +08:00
}
2001-09-20 05:08:56 +08:00
2002-01-30 20:09:18 +08:00
IntersectVisitor : : IntersectState : : ~ IntersectState ( )
{
}
2002-11-08 19:00:16 +08:00
bool IntersectVisitor : : IntersectState : : isCulled ( const BoundingSphere & bs , LineSegmentMask & segMaskOut )
2001-01-11 00:32:10 +08:00
{
bool hit = false ;
2002-11-08 19:00:16 +08:00
LineSegmentMask mask = 0x00000001 ;
2001-01-11 00:32:10 +08:00
segMaskOut = 0x00000000 ;
2002-11-08 19:00:16 +08:00
LineSegmentMask segMaskIn = _segmentMaskStack . back ( ) ;
2001-09-20 05:08:56 +08:00
for ( IntersectState : : LineSegmentList : : iterator sitr = _segList . begin ( ) ;
sitr ! = _segList . end ( ) ;
+ + sitr )
2001-01-11 00:32:10 +08:00
{
2001-09-20 05:08:56 +08:00
if ( ( segMaskIn & mask ) & & ( sitr - > second ) - > intersect ( bs ) )
2001-01-11 00:32:10 +08:00
{
segMaskOut = segMaskOut | mask ;
hit = true ;
}
mask = mask < < 1 ;
}
return ! hit ;
}
2002-11-08 19:00:16 +08:00
bool IntersectVisitor : : IntersectState : : isCulled ( const BoundingBox & bb , LineSegmentMask & segMaskOut )
2001-01-11 00:32:10 +08:00
{
bool hit = false ;
2002-11-08 19:00:16 +08:00
LineSegmentMask mask = 0x00000001 ;
2001-01-11 00:32:10 +08:00
segMaskOut = 0x00000000 ;
2002-11-08 19:00:16 +08:00
LineSegmentMask segMaskIn = _segmentMaskStack . back ( ) ;
2001-09-20 05:08:56 +08:00
for ( IntersectState : : LineSegmentList : : iterator sitr = _segList . begin ( ) ;
sitr ! = _segList . end ( ) ;
+ + sitr )
2001-01-11 00:32:10 +08:00
{
2001-09-20 05:08:56 +08:00
if ( ( segMaskIn & mask ) & & ( sitr - > second ) - > intersect ( bb ) )
2001-01-11 00:32:10 +08:00
{
segMaskOut = segMaskOut | mask ;
hit = true ;
}
mask = mask < < 1 ;
}
return ! hit ;
}
2005-12-22 22:06:33 +08:00
void IntersectVisitor : : IntersectState : : addLineSegment ( osg : : LineSegment * seg )
{
// create a new segment transformed to local coordintes.
LineSegment * ns = new LineSegment ;
if ( _model_inverse . valid ( ) )
{
if ( _view_inverse . valid ( ) )
{
osg : : Matrix matrix = ( * ( _view_inverse ) ) * ( * ( _model_inverse ) ) ;
ns - > mult ( * seg , matrix ) ;
}
else
{
ns - > mult ( * seg , * ( _model_inverse ) ) ;
}
}
else if ( _view_inverse . valid ( ) )
{
ns - > mult ( * seg , * ( _view_inverse ) ) ;
}
else
{
* ns = * seg ;
}
_segList . push_back ( LineSegmentPair ( seg , ns ) ) ;
}
2001-01-11 00:32:10 +08:00
IntersectVisitor : : IntersectVisitor ( )
{
2005-02-11 05:18:04 +08:00
2001-01-11 00:32:10 +08:00
// overide the default node visitor mode.
2001-09-20 05:08:56 +08:00
setTraversalMode ( NodeVisitor : : TRAVERSE_ACTIVE_CHILDREN ) ;
2005-02-11 05:18:04 +08:00
// Initialize eyepoint to 0,0,0
setEyePoint ( Vec3 ( 0.0f , 0.0f , 0.0f ) ) ;
setLODSelectionMode ( USE_HEIGHEST_LEVEL_OF_DETAIL ) ; // orignal IntersectVisitor behavior
//setLODSelectionMode(USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION);
2002-07-26 05:50:08 +08:00
2001-01-11 00:32:10 +08:00
reset ( ) ;
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
IntersectVisitor : : ~ IntersectVisitor ( )
{
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : reset ( )
{
2001-09-20 05:08:56 +08:00
_intersectStateStack . clear ( ) ;
2001-01-11 00:32:10 +08:00
// create a empty IntersectState on the the intersectStateStack.
2002-12-16 21:40:58 +08:00
_intersectStateStack . push_back ( new IntersectState ) ;
2001-09-20 05:08:56 +08:00
2002-08-02 23:14:59 +08:00
_segHitList . clear ( ) ;
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
}
2005-02-11 05:18:04 +08:00
float IntersectVisitor : : getDistanceToEyePoint ( const Vec3 & pos , bool /*withLODScale*/ ) const
{
if ( _lodSelectionMode = = USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION )
{
2005-12-19 21:57:04 +08:00
// osg::notify(osg::NOTICE)<<"IntersectVisitor::getDistanceToEyePoint)"<<(pos-getEyePoint()).length()<<std::endl;
2005-02-11 05:18:04 +08:00
// LODScale is not available to IntersectVisitor, so we ignore the withLODScale argument
//if (withLODScale) return (pos-getEyePoint()).length()*getLODScale();
//else return (pos-getEyePoint()).length();
return ( pos - getEyePoint ( ) ) . length ( ) ;
}
else
{
return 0.0f ;
}
}
2001-01-11 00:32:10 +08:00
bool IntersectVisitor : : hits ( )
{
2001-09-20 05:08:56 +08:00
for ( LineSegmentHitListMap : : iterator itr = _segHitList . begin ( ) ;
itr ! = _segHitList . end ( ) ;
+ + itr )
2001-01-11 00:32:10 +08:00
{
if ( ! ( itr - > second . empty ( ) ) ) return true ;
}
return false ;
}
2001-09-20 05:08:56 +08:00
2005-12-19 21:40:32 +08:00
osg : : Vec3 IntersectVisitor : : getEyePoint ( ) const
{
const IntersectState * cis = _intersectStateStack . empty ( ) ? 0 : _intersectStateStack . back ( ) . get ( ) ;
2005-12-22 22:06:33 +08:00
if ( cis & & ( cis - > _model_inverse . valid ( ) | | cis - > _view_inverse . valid ( ) ) )
2005-12-19 21:40:32 +08:00
{
2005-12-22 22:06:33 +08:00
osg : : Vec3 eyePoint = _pseudoEyePoint ;
if ( cis - > _view_inverse . valid ( ) ) eyePoint = eyePoint * ( * ( cis - > _view_inverse ) ) ;
if ( cis - > _model_inverse . valid ( ) ) eyePoint = eyePoint * ( * ( cis - > _model_inverse ) ) ;
//osg::notify(osg::NOTICE)<<"IntersectVisitor::getEyePoint()"<<eyePoint<<std::endl;
return eyePoint ;
2005-12-19 21:40:32 +08:00
}
else
{
return _pseudoEyePoint ;
}
}
2001-09-20 05:08:56 +08:00
void IntersectVisitor : : addLineSegment ( LineSegment * seg )
2001-01-11 00:32:10 +08:00
{
2001-11-06 18:34:51 +08:00
if ( ! seg ) return ;
if ( ! seg - > valid ( ) )
{
2002-06-26 04:27:51 +08:00
notify ( WARN ) < < " Warning: invalid line segment passed to IntersectVisitor::addLineSegment(..) " < < std : : endl ;
notify ( WARN ) < < " " < < seg - > start ( ) < < " " < < seg - > end ( ) < < " segment ignored.. " < < std : : endl ;
2001-11-06 18:34:51 +08:00
return ;
}
2005-10-27 19:11:02 +08:00
2005-02-11 05:18:04 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
2005-10-27 19:11:02 +08:00
if ( cis - > _segList . size ( ) > = 32 )
{
notify ( WARN ) < < " Warning: excessive number of line segmenets passed to IntersectVisitor::addLineSegment(..), maximum permitted is 32 line segments. " < < std : : endl ;
notify ( WARN ) < < " " < < seg - > start ( ) < < " " < < seg - > end ( ) < < " segment ignored.. " < < std : : endl ;
return ;
}
2005-02-11 05:18:04 +08:00
setEyePoint ( seg - > start ( ) ) ; // set start of line segment to be pseudo EyePoint for billboarding and LOD purposes
2001-01-11 00:32:10 +08:00
// first check to see if segment has already been added.
2005-02-11 05:18:04 +08:00
for ( IntersectState : : LineSegmentList : : iterator itr = cis - > _segList . begin ( ) ;
itr ! = cis - > _segList . end ( ) ;
2001-09-20 05:08:56 +08:00
+ + itr )
2001-01-11 00:32:10 +08:00
{
if ( itr - > first = = seg ) return ;
}
2005-12-22 22:06:33 +08:00
cis - > addLineSegment ( seg ) ;
2001-01-11 00:32:10 +08:00
}
2001-09-20 05:08:56 +08:00
2005-12-17 00:27:17 +08:00
void IntersectVisitor : : pushMatrix ( RefMatrix * matrix , osg : : Transform : : ReferenceFrame rf )
2001-01-11 00:32:10 +08:00
{
2002-12-16 21:40:58 +08:00
IntersectState * nis = new IntersectState ;
2001-09-20 05:08:56 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
2005-12-22 22:06:33 +08:00
if ( rf = = osg : : Transform : : RELATIVE_RF )
2001-01-11 00:32:10 +08:00
{
2005-12-22 22:06:33 +08:00
// share the original view matrix
nis - > _view_matrix = cis - > _view_matrix ;
nis - > _view_inverse = cis - > _view_inverse ;
// set up new model matrix
nis - > _model_matrix = matrix ;
if ( cis - > _model_matrix . valid ( ) )
{
nis - > _model_matrix - > postMult ( * ( cis - > _model_matrix ) ) ;
}
RefMatrix * inverse_world = new RefMatrix ;
inverse_world - > invert ( * ( nis - > _model_matrix ) ) ;
nis - > _model_inverse = inverse_world ;
2001-01-11 00:32:10 +08:00
}
else
{
2005-12-22 22:06:33 +08:00
// set a new view matrix
nis - > _view_matrix = matrix ;
RefMatrix * inverse_world = new RefMatrix ;
inverse_world - > invert ( * ( nis - > _view_matrix ) ) ;
nis - > _view_inverse = inverse_world ;
// model matrix now blank.
nis - > _model_matrix = 0 ;
nis - > _model_inverse = 0 ;
2001-01-11 00:32:10 +08:00
}
2001-09-20 05:08:56 +08:00
2002-11-08 19:00:16 +08:00
IntersectState : : LineSegmentMask segMaskIn = cis - > _segmentMaskStack . back ( ) ;
IntersectState : : LineSegmentMask mask = 0x00000001 ;
2001-09-20 05:08:56 +08:00
for ( IntersectState : : LineSegmentList : : iterator sitr = cis - > _segList . begin ( ) ;
sitr ! = cis - > _segList . end ( ) ;
+ + sitr )
2001-01-11 00:32:10 +08:00
{
if ( ( segMaskIn & mask ) )
{
2005-12-22 22:06:33 +08:00
nis - > addLineSegment ( sitr - > first . get ( ) ) ;
2001-01-11 00:32:10 +08:00
}
mask = mask < < 1 ;
}
_intersectStateStack . push_back ( nis ) ;
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : popMatrix ( )
{
2001-09-20 05:08:56 +08:00
if ( ! _intersectStateStack . empty ( ) )
2001-01-11 00:32:10 +08:00
{
_intersectStateStack . pop_back ( ) ;
}
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
bool IntersectVisitor : : enterNode ( Node & node )
{
const BoundingSphere & bs = node . getBound ( ) ;
2005-12-07 19:36:56 +08:00
if ( bs . valid ( ) & & node . isCullingActive ( ) )
2001-01-11 00:32:10 +08:00
{
2001-09-20 05:08:56 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
2002-11-08 19:00:16 +08:00
IntersectState : : LineSegmentMask sm = 0xffffffff ;
2001-01-11 00:32:10 +08:00
if ( cis - > isCulled ( bs , sm ) ) return false ;
cis - > _segmentMaskStack . push_back ( sm ) ;
return true ;
}
else
{
2005-12-07 19:36:56 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
if ( ! cis - > _segmentMaskStack . empty ( ) )
cis - > _segmentMaskStack . push_back ( cis - > _segmentMaskStack . back ( ) ) ;
else
cis - > _segmentMaskStack . push_back ( 0xffffffff ) ;
return true ;
2001-01-11 00:32:10 +08:00
}
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : leaveNode ( )
{
2001-09-20 05:08:56 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
2001-01-11 00:32:10 +08:00
cis - > _segmentMaskStack . pop_back ( ) ;
}
2001-09-20 05:08:56 +08:00
2005-02-11 05:18:04 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : apply ( Node & node )
{
if ( ! enterNode ( node ) ) return ;
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
traverse ( node ) ;
leaveNode ( ) ;
}
2001-09-20 05:08:56 +08:00
2003-04-25 21:47:33 +08:00
struct TriangleHit
{
TriangleHit ( unsigned int index , const osg : : Vec3 & normal , float r1 , const osg : : Vec3 * v1 , float r2 , const osg : : Vec3 * v2 , float r3 , const osg : : Vec3 * v3 ) :
_index ( index ) ,
_normal ( normal ) ,
_r1 ( r1 ) ,
_v1 ( v1 ) ,
_r2 ( r2 ) ,
_v2 ( v2 ) ,
_r3 ( r3 ) ,
_v3 ( v3 ) { }
unsigned int _index ;
const osg : : Vec3 _normal ;
float _r1 ;
const osg : : Vec3 * _v1 ;
float _r2 ;
const osg : : Vec3 * _v2 ;
float _r3 ;
const osg : : Vec3 * _v3 ;
} ;
2001-01-11 00:32:10 +08:00
struct TriangleIntersect
{
2002-01-30 20:09:18 +08:00
osg : : ref_ptr < LineSegment > _seg ;
2001-01-11 00:32:10 +08:00
Vec3 _s ;
Vec3 _d ;
float _length ;
int _index ;
float _ratio ;
bool _hit ;
2003-04-25 21:47:33 +08:00
2001-01-11 00:32:10 +08:00
2003-04-25 21:47:33 +08:00
typedef std : : multimap < float , TriangleHit > TriangleHitList ;
2001-01-11 00:32:10 +08:00
TriangleHitList _thl ;
2002-06-26 04:27:51 +08:00
TriangleIntersect ( )
{
}
2001-09-20 05:08:56 +08:00
TriangleIntersect ( const LineSegment & seg , float ratio = FLT_MAX )
2002-06-26 04:27:51 +08:00
{
set ( seg , ratio ) ;
}
void set ( const LineSegment & seg , float ratio = FLT_MAX )
2001-01-11 00:32:10 +08:00
{
2002-01-30 20:09:18 +08:00
_seg = new LineSegment ( seg ) ;
2001-01-11 00:32:10 +08:00
_hit = false ;
_index = 0 ;
_ratio = ratio ;
2002-01-30 20:09:18 +08:00
_s = _seg - > start ( ) ;
_d = _seg - > end ( ) - _seg - > start ( ) ;
2001-01-11 00:32:10 +08:00
_length = _d . length ( ) ;
_d / = _length ;
}
2001-09-20 05:08:56 +08:00
// bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r)
2003-09-26 05:54:33 +08:00
inline void operator ( ) ( const Vec3 & v1 , const Vec3 & v2 , const Vec3 & v3 , bool treatVertexDataAsTemporary )
2001-01-11 00:32:10 +08:00
{
+ + _index ;
if ( v1 = = v2 | | v2 = = v3 | | v1 = = v3 ) return ;
Vec3 v12 = v2 - v1 ;
Vec3 n12 = v12 ^ _d ;
float ds12 = ( _s - v1 ) * n12 ;
float d312 = ( v3 - v1 ) * n12 ;
if ( d312 > = 0.0f )
{
if ( ds12 < 0.0f ) return ;
if ( ds12 > d312 ) return ;
}
2001-09-20 05:08:56 +08:00
else // d312 < 0
2001-01-11 00:32:10 +08:00
{
if ( ds12 > 0.0f ) return ;
if ( ds12 < d312 ) return ;
}
Vec3 v23 = v3 - v2 ;
Vec3 n23 = v23 ^ _d ;
float ds23 = ( _s - v2 ) * n23 ;
float d123 = ( v1 - v2 ) * n23 ;
if ( d123 > = 0.0f )
{
if ( ds23 < 0.0f ) return ;
if ( ds23 > d123 ) return ;
}
2001-09-20 05:08:56 +08:00
else // d123 < 0
2001-01-11 00:32:10 +08:00
{
if ( ds23 > 0.0f ) return ;
if ( ds23 < d123 ) return ;
}
Vec3 v31 = v1 - v3 ;
Vec3 n31 = v31 ^ _d ;
float ds31 = ( _s - v3 ) * n31 ;
float d231 = ( v2 - v3 ) * n31 ;
if ( d231 > = 0.0f )
{
if ( ds31 < 0.0f ) return ;
if ( ds31 > d231 ) return ;
}
2001-09-20 05:08:56 +08:00
else // d231 < 0
2001-01-11 00:32:10 +08:00
{
if ( ds31 > 0.0f ) return ;
if ( ds31 < d231 ) return ;
}
2001-11-07 20:42:08 +08:00
2001-01-11 00:32:10 +08:00
2001-11-07 20:42:08 +08:00
float r3 ;
if ( ds12 = = 0.0f ) r3 = 0.0f ;
2001-11-08 21:50:32 +08:00
else if ( d312 ! = 0.0f ) r3 = ds12 / d312 ;
2001-11-07 20:42:08 +08:00
else return ; // the triangle and the line must be parallel intersection.
float r1 ;
if ( ds23 = = 0.0f ) r1 = 0.0f ;
2001-11-08 21:50:32 +08:00
else if ( d123 ! = 0.0f ) r1 = ds23 / d123 ;
2001-11-07 20:42:08 +08:00
else return ; // the triangle and the line must be parallel intersection.
float r2 ;
if ( ds31 = = 0.0f ) r2 = 0.0f ;
2001-11-08 21:50:32 +08:00
else if ( d231 ! = 0.0f ) r2 = ds31 / d231 ;
2001-11-07 20:42:08 +08:00
else return ; // the triangle and the line must be parallel intersection.
float total_r = ( r1 + r2 + r3 ) ;
if ( total_r ! = 1.0f )
{
if ( total_r = = 0.0f ) return ; // the triangle and the line must be parallel intersection.
float inv_total_r = 1.0f / total_r ;
r1 * = inv_total_r ;
r2 * = inv_total_r ;
r3 * = inv_total_r ;
}
2001-01-11 00:32:10 +08:00
Vec3 in = v1 * r1 + v2 * r2 + v3 * r3 ;
2005-02-11 05:30:03 +08:00
if ( ! in . valid ( ) )
{
osg : : notify ( WARN ) < < " Warning:: Picked up error in TriangleIntersect " < < std : : endl ;
osg : : notify ( WARN ) < < " ( " < < v1 < < " , \t " < < v2 < < " , \t " < < v3 < < " ) " < < std : : endl ;
osg : : notify ( WARN ) < < " ( " < < r1 < < " , \t " < < r2 < < " , \t " < < r3 < < " ) " < < std : : endl ;
return ;
}
2001-01-11 00:32:10 +08:00
float d = ( in - _s ) * _d ;
if ( d < 0.0f ) return ;
if ( d > _length ) return ;
osg : : Vec3 normal = v12 ^ v23 ;
normal . normalize ( ) ;
float r = d / _length ;
2003-09-26 05:54:33 +08:00
if ( treatVertexDataAsTemporary )
{
_thl . insert ( std : : pair < const float , TriangleHit > ( r , TriangleHit ( _index - 1 , normal , r1 , 0 , r2 , 0 , r3 , 0 ) ) ) ;
}
else
{
_thl . insert ( std : : pair < const float , TriangleHit > ( r , TriangleHit ( _index - 1 , normal , r1 , & v1 , r2 , & v2 , r3 , & v3 ) ) ) ;
}
2001-01-11 00:32:10 +08:00
_hit = true ;
}
} ;
2002-06-26 04:27:51 +08:00
bool IntersectVisitor : : intersect ( Drawable & drawable )
2001-01-11 00:32:10 +08:00
{
bool hitFlag = false ;
2001-09-20 05:08:56 +08:00
IntersectState * cis = _intersectStateStack . back ( ) . get ( ) ;
2001-01-11 00:32:10 +08:00
2002-06-26 04:27:51 +08:00
const BoundingBox & bb = drawable . getBound ( ) ;
2001-01-11 00:32:10 +08:00
2001-09-20 05:08:56 +08:00
for ( IntersectState : : LineSegmentList : : iterator sitr = cis - > _segList . begin ( ) ;
sitr ! = cis - > _segList . end ( ) ;
+ + sitr )
2001-01-11 00:32:10 +08:00
{
2001-09-20 05:08:56 +08:00
if ( sitr - > second - > intersect ( bb ) )
2001-01-11 00:32:10 +08:00
{
2002-06-26 04:27:51 +08:00
TriangleFunctor < TriangleIntersect > ti ;
ti . set ( * sitr - > second ) ;
2002-07-18 23:36:14 +08:00
drawable . accept ( ti ) ;
2001-01-11 00:32:10 +08:00
if ( ti . _hit )
{
2003-04-25 21:47:33 +08:00
osg : : Geometry * geometry = drawable . asGeometry ( ) ;
2001-01-11 00:32:10 +08:00
for ( TriangleIntersect : : TriangleHitList : : iterator thitr = ti . _thl . begin ( ) ;
2001-09-20 05:08:56 +08:00
thitr ! = ti . _thl . end ( ) ;
+ + thitr )
2001-01-11 00:32:10 +08:00
{
2003-04-25 21:47:33 +08:00
2001-01-11 00:32:10 +08:00
Hit hit ;
hit . _nodePath = _nodePath ;
2005-12-22 22:06:33 +08:00
hit . _matrix = cis - > _model_matrix ;
hit . _inverse = cis - > _model_inverse ;
2002-06-26 04:27:51 +08:00
hit . _drawable = & drawable ;
2001-01-11 00:32:10 +08:00
if ( _nodePath . empty ( ) ) hit . _geode = NULL ;
else hit . _geode = dynamic_cast < Geode * > ( _nodePath . back ( ) ) ;
2003-04-25 21:47:33 +08:00
TriangleHit & triHit = thitr - > second ;
2001-01-11 00:32:10 +08:00
hit . _ratio = thitr - > first ;
2003-04-25 21:47:33 +08:00
hit . _primitiveIndex = triHit . _index ;
2001-09-20 05:08:56 +08:00
hit . _originalLineSegment = sitr - > first ;
hit . _localLineSegment = sitr - > second ;
2001-01-11 00:32:10 +08:00
hit . _intersectPoint = sitr - > second - > start ( ) * ( 1.0f - hit . _ratio ) +
2001-09-20 05:08:56 +08:00
sitr - > second - > end ( ) * hit . _ratio ;
2003-04-25 21:47:33 +08:00
hit . _intersectNormal = triHit . _normal ;
if ( geometry )
{
2003-06-24 23:40:09 +08:00
osg : : Vec3Array * vertices = dynamic_cast < osg : : Vec3Array * > ( geometry - > getVertexArray ( ) ) ;
2003-04-25 21:47:33 +08:00
if ( vertices )
{
osg : : Vec3 * first = & ( vertices - > front ( ) ) ;
if ( triHit . _v1 ) hit . _vecIndexList . push_back ( triHit . _v1 - first ) ;
if ( triHit . _v2 ) hit . _vecIndexList . push_back ( triHit . _v2 - first ) ;
2003-06-25 16:50:57 +08:00
if ( triHit . _v3 ) hit . _vecIndexList . push_back ( triHit . _v3 - first ) ;
2003-04-25 21:47:33 +08:00
}
}
2001-01-11 00:32:10 +08:00
2002-01-30 20:09:18 +08:00
_segHitList [ sitr - > first . get ( ) ] . push_back ( hit ) ;
2002-07-26 05:50:08 +08:00
2002-01-30 20:09:18 +08:00
std : : sort ( _segHitList [ sitr - > first . get ( ) ] . begin ( ) , _segHitList [ sitr - > first . get ( ) ] . end ( ) ) ;
2001-01-11 00:32:10 +08:00
hitFlag = true ;
}
}
}
}
return hitFlag ;
}
2001-09-20 05:08:56 +08:00
void IntersectVisitor : : apply ( Geode & geode )
2001-01-11 00:32:10 +08:00
{
2001-09-20 05:08:56 +08:00
if ( ! enterNode ( geode ) ) return ;
2001-01-11 00:32:10 +08:00
2002-07-18 22:20:01 +08:00
for ( unsigned int i = 0 ; i < geode . getNumDrawables ( ) ; i + + )
2001-01-11 00:32:10 +08:00
{
2002-06-26 04:27:51 +08:00
intersect ( * geode . getDrawable ( i ) ) ;
2001-01-11 00:32:10 +08:00
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
leaveNode ( ) ;
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : apply ( Billboard & node )
{
if ( ! enterNode ( node ) ) return ;
2002-01-19 06:36:56 +08:00
2005-02-11 05:18:04 +08:00
// IntersectVisitor doesn't have getEyeLocal(), can we use NodeVisitor::getEyePoint()?
const Vec3 & eye_local = getEyePoint ( ) ;
for ( unsigned int i = 0 ; i < node . getNumDrawables ( ) ; i + + )
{
const Vec3 & pos = node . getPosition ( i ) ;
osg : : ref_ptr < RefMatrix > billboard_matrix = new RefMatrix ;
node . computeMatrix ( * billboard_matrix , eye_local , pos ) ;
2005-12-17 00:27:17 +08:00
pushMatrix ( billboard_matrix . get ( ) , osg : : Transform : : RELATIVE_RF ) ;
2005-02-11 05:18:04 +08:00
intersect ( * node . getDrawable ( i ) ) ;
2005-11-17 21:35:53 +08:00
2005-02-11 05:18:04 +08:00
popMatrix ( ) ;
}
2001-01-11 00:32:10 +08:00
leaveNode ( ) ;
}
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
void IntersectVisitor : : apply ( Group & node )
{
if ( ! enterNode ( node ) ) return ;
2001-09-20 05:08:56 +08:00
2001-01-11 00:32:10 +08:00
traverse ( node ) ;
leaveNode ( ) ;
}
2001-09-20 05:08:56 +08:00
void IntersectVisitor : : apply ( Transform & node )
2001-01-11 00:32:10 +08:00
{
if ( ! enterNode ( node ) ) return ;
2001-09-20 05:08:56 +08:00
2003-01-10 17:25:42 +08:00
osg : : ref_ptr < RefMatrix > matrix = new RefMatrix ;
2003-12-09 22:07:44 +08:00
node . computeLocalToWorldMatrix ( * matrix , this ) ;
2002-02-06 05:54:46 +08:00
2005-12-17 00:27:17 +08:00
pushMatrix ( matrix . get ( ) , node . getReferenceFrame ( ) ) ;
2001-01-11 00:32:10 +08:00
traverse ( node ) ;
popMatrix ( ) ;
leaveNode ( ) ;
}
void IntersectVisitor : : apply ( Switch & node )
{
apply ( ( Group & ) node ) ;
}
void IntersectVisitor : : apply ( LOD & node )
{
apply ( ( Group & ) node ) ;
}
2005-12-07 18:25:50 +08:00
PickVisitor : : PickVisitor ( const osg : : Viewport * viewport , const osg : : Matrixd & proj , const osg : : Matrixd & view , float mx , float my ) :
_mx ( mx ) ,
_my ( my ) ,
_lastViewport ( viewport ) ,
_lastProjectionMatrix ( proj ) ,
_lastViewMatrix ( view )
{
2005-12-19 00:06:17 +08:00
setLODSelectionMode ( USE_SEGMENT_START_POINT_AS_EYE_POINT_FOR_LOD_LEVEL_SELECTION ) ;
2005-12-07 18:25:50 +08:00
if ( viewport & &
mx > = static_cast < float > ( viewport - > x ( ) ) & &
my > = static_cast < float > ( viewport - > y ( ) ) & &
mx < static_cast < float > ( viewport - > x ( ) + viewport - > width ( ) ) & &
my < static_cast < float > ( viewport - > y ( ) + viewport - > height ( ) ) )
{
// mouse pointer intersect viewport so we can proceed to set up a line segment
2005-12-17 00:27:17 +08:00
osg : : Matrix MVPW = proj * viewport - > computeWindowMatrix ( ) ;
2005-12-07 18:25:50 +08:00
osg : : Matrixd inverseMVPW ;
inverseMVPW . invert ( MVPW ) ;
osg : : Vec3 nearPoint = osg : : Vec3 ( mx , my , 0.0f ) * inverseMVPW ;
osg : : Vec3 farPoint = osg : : Vec3 ( mx , my , 1.0f ) * inverseMVPW ;
osg : : LineSegment * lineSegment = new osg : : LineSegment ;
lineSegment - > set ( nearPoint , farPoint ) ;
2005-12-17 00:27:17 +08:00
IntersectState * cis = ! _intersectStateStack . empty ( ) ? _intersectStateStack . back ( ) . get ( ) : 0 ;
if ( cis )
{
2005-12-22 22:06:33 +08:00
cis - > _view_matrix = new RefMatrix ( view ) ;
cis - > _view_inverse = new RefMatrix ;
cis - > _view_inverse - > invert ( * ( cis - > _view_matrix ) ) ;
cis - > _model_matrix = 0 ;
cis - > _model_inverse = 0 ;
2005-12-17 00:27:17 +08:00
}
else
{
osg : : notify ( osg : : NOTICE ) < < " Warning: PickVisitor not set up correctly, picking errors likely " < < std : : endl ;
}
2005-12-07 18:25:50 +08:00
addLineSegment ( lineSegment ) ;
2005-12-17 00:27:17 +08:00
}
2005-12-07 18:25:50 +08:00
}
void PickVisitor : : runNestedPickVisitor ( osg : : Node & node , const osg : : Viewport * viewport , const osg : : Matrix & proj , const osg : : Matrix & view , float mx , float my )
{
PickVisitor newPickVisitor ( viewport , proj , view , mx , my ) ;
newPickVisitor . setTraversalMask ( getTraversalMask ( ) ) ;
2005-12-23 18:59:12 +08:00
newPickVisitor . getNodePath ( ) = getNodePath ( ) ;
2005-12-07 18:25:50 +08:00
// the new pickvisitor over the nodes children.
node . traverse ( newPickVisitor ) ;
for ( LineSegmentHitListMap : : iterator itr = newPickVisitor . _segHitList . begin ( ) ;
itr ! = newPickVisitor . _segHitList . end ( ) ;
+ + itr )
{
_segHitList . insert ( * itr ) ;
}
}
void PickVisitor : : apply ( osg : : Projection & projection )
{
runNestedPickVisitor ( projection ,
_lastViewport . get ( ) ,
projection . getMatrix ( ) ,
_lastViewMatrix ,
_mx , _my ) ;
}
void PickVisitor : : apply ( osg : : CameraNode & camera )
{
2005-12-07 19:36:56 +08:00
if ( ! camera . isRenderToTextureCamera ( ) )
{
2005-12-08 19:01:38 +08:00
if ( camera . getReferenceFrame ( ) = = osg : : CameraNode : : ABSOLUTE_RF )
{
runNestedPickVisitor ( camera ,
camera . getViewport ( ) ? camera . getViewport ( ) : _lastViewport . get ( ) ,
camera . getProjectionMatrix ( ) ,
camera . getViewMatrix ( ) ,
_mx , _my ) ;
}
else if ( camera . getTransformOrder ( ) = = osg : : CameraNode : : POST_MULTIPLE )
{
runNestedPickVisitor ( camera ,
camera . getViewport ( ) ? camera . getViewport ( ) : _lastViewport . get ( ) ,
_lastProjectionMatrix * camera . getProjectionMatrix ( ) ,
_lastViewMatrix * camera . getViewMatrix ( ) ,
_mx , _my ) ;
}
else // PRE_MULTIPLE
{
runNestedPickVisitor ( camera ,
camera . getViewport ( ) ? camera . getViewport ( ) : _lastViewport . get ( ) ,
camera . getProjectionMatrix ( ) * _lastProjectionMatrix ,
camera . getViewMatrix ( ) * _lastViewMatrix ,
_mx , _my ) ;
}
2005-12-07 19:36:56 +08:00
}
2005-12-07 18:25:50 +08:00
}