From ce3929fd5f288b7ba1a5b4b7b98c9fa856dc2cc8 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 26 Oct 2006 16:03:17 +0000 Subject: [PATCH] Added beginings of new osgUtil::IntersectionVisitor and osgintersection class --- Make/makedirdefs | 3 +- VisualStudio/OpenSceneGraph.dsw | 21 + .../osgintersection/osgintersection.dsp | 101 +++ examples/osgintersection/GNUmakefile | 18 + examples/osgintersection/GNUmakefile.inst | 14 + examples/osgintersection/osgintersection.cpp | 83 +++ include/osgUtil/IntersectionVisitor | 191 ++++++ src/osgUtil/GNUmakefile | 1 + src/osgUtil/IntersectionVisitor.cpp | 607 ++++++++++++++++++ 9 files changed, 1038 insertions(+), 1 deletion(-) create mode 100644 VisualStudio/examples/osgintersection/osgintersection.dsp create mode 100644 examples/osgintersection/GNUmakefile create mode 100644 examples/osgintersection/GNUmakefile.inst create mode 100644 examples/osgintersection/osgintersection.cpp create mode 100644 include/osgUtil/IntersectionVisitor create mode 100644 src/osgUtil/IntersectionVisitor.cpp diff --git a/Make/makedirdefs b/Make/makedirdefs index 9b1ca631a..8cba19b6f 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -210,6 +210,7 @@ ifeq ($(PRODUCER_INSTALLED),yes) osgcubemap \ osgdelaunay \ osgdepthpartition \ + osgdepthshadow \ osgdistortion \ osgforest \ osgfxbrowser \ @@ -218,6 +219,7 @@ ifeq ($(PRODUCER_INSTALLED),yes) osghangglide \ osghud \ osgimpostor \ + osgintersection \ osgkeyboard \ osgkeyboardmouse \ osglauncher \ @@ -249,7 +251,6 @@ ifeq ($(PRODUCER_INSTALLED),yes) osgshaderterrain \ osgshadow \ osgshadowtexture \ - osgdepthshadow \ osgshape \ osgsimple \ osgsimplepager \ diff --git a/VisualStudio/OpenSceneGraph.dsw b/VisualStudio/OpenSceneGraph.dsw index 4b1683a5e..a7013619a 100644 --- a/VisualStudio/OpenSceneGraph.dsw +++ b/VisualStudio/OpenSceneGraph.dsw @@ -1074,6 +1074,27 @@ Package=<4> ############################################################################### +Project: "Example osgintersection"=.\examples\osgintersection\osgintersection.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Core osg + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgDB + End Project Dependency + Begin Project Dependency + Project_Dep_Name Core osgUtil + End Project Dependency +}}} + +############################################################################### + Project: "Example osgkeyboard"=.\examples\osgkeyboard\osgkeyboard.dsp - Package Owner=<4> Package=<5> diff --git a/VisualStudio/examples/osgintersection/osgintersection.dsp b/VisualStudio/examples/osgintersection/osgintersection.dsp new file mode 100644 index 000000000..90ee7ca1c --- /dev/null +++ b/VisualStudio/examples/osgintersection/osgintersection.dsp @@ -0,0 +1,101 @@ +# Microsoft Developer Studio Project File - Name="Example osgintersection" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Example osgintersection - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "osgintersection.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "osgintersection.mak" CFG="Example osgintersection - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Example osgintersection - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Example osgintersection - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Example osgintersection - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "../../../bin/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GR /GX /O2 /I "../../../include" /I "../../../../OpenThreads/include" /I "../../../../Producer/include" /I "../../../../3rdParty/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "_CRT_SECURE_NO_DEPRECATE" /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 OpenThreadsWin32.lib opengl32.lib /nologo /subsystem:console /debug /machine:I386 /opt:ref /opt:icf /out:"$(OutDir)/osgintersection.exe" /libpath:"../../../lib/$(PlatformName)" /libpath:"../../../../OpenThreads/lib/$(PlatformName)" /libpath:"../../../../Producer/lib/$(PlatformName)" /libpath:"../../../../3rdParty/lib/$(PlatformName)" /libpath:"../../../../3rdParty/lib" + +!ELSEIF "$(CFG)" == "Example osgintersection - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "../../../bin/$(PlatformName)" +# PROP Intermediate_Dir "$(PlatformName)/$(ConfigurationName)" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +MTL=midl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /Gm /GR /GX /Zi /Od /I "../../../include" /I "../../../../OpenThreads/include" /I "../../../../Producer/include" /I "../../../../3rdParty/include" /D "_CONSOLE" /D "_MBCS" /D "FL_DLL" /D "WIN32" /D "_DEBUG" /D "_CRT_SECURE_NO_DEPRECATE" /FR /YX /FD /Zm200 /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 OpenThreadsWin32d.lib opengl32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"libcmt" /out:"$(OutDir)/osgintersectiond.exe" /pdbtype:sept /libpath:"../../../lib/$(PlatformName)" /libpath:"../../../../OpenThreads/lib/$(PlatformName)" /libpath:"../../../../Producer/lib/$(PlatformName)" /libpath:"../../../../3rdParty/lib/$(PlatformName)" /libpath:"../../../../3rdParty/lib" +# SUBTRACT LINK32 /incremental:no + +!ENDIF + +# Begin Target + +# Name "Example osgintersection - Win32 Release" +# Name "Example osgintersection - Win32 Debug" +# Begin Source File + +SOURCE=..\..\..\examples\osgintersection\osgintersection.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\icons\osg_icon.rc +# End Source File +# End Target +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Project diff --git a/examples/osgintersection/GNUmakefile b/examples/osgintersection/GNUmakefile new file mode 100644 index 000000000..f02d536f7 --- /dev/null +++ b/examples/osgintersection/GNUmakefile @@ -0,0 +1,18 @@ +TOPDIR = ../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + osgintersection.cpp\ + +LIBS += -losgText -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) + +INSTFILES = \ + $(CXXFILES)\ + GNUmakefile.inst=GNUmakefile + +EXEC = osgintersection + +INC += $(X_INC) + +include $(TOPDIR)/Make/makerules + diff --git a/examples/osgintersection/GNUmakefile.inst b/examples/osgintersection/GNUmakefile.inst new file mode 100644 index 000000000..4c892aa3c --- /dev/null +++ b/examples/osgintersection/GNUmakefile.inst @@ -0,0 +1,14 @@ +TOPDIR = ../.. +include $(TOPDIR)/Make/makedefs + +CXXFILES =\ + osgintersection.cpp\ + +LIBS += -losgDB -losgText -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) + +EXEC = osgintersection + +INC += $(PRODUCER_INCLUDE_DIR) $(X_INC) +LDFLAGS += $(PRODUCER_LIB_DIR) + +include $(TOPDIR)/Make/makerules diff --git a/examples/osgintersection/osgintersection.cpp b/examples/osgintersection/osgintersection.cpp new file mode 100644 index 000000000..a8498a7d7 --- /dev/null +++ b/examples/osgintersection/osgintersection.cpp @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include + +struct MyReadCallback : public osgUtil::IntersectionVisitor::ReadCallback +{ + virtual osg::Node* readNodeFile(const std::string& filename) + { + return osgDB::readNodeFile(filename); + } +}; + + +int main(int argc, char **argv) +{ + // use an ArgumentParser object to manage the program arguments. + osg::ArgumentParser arguments(&argc,argv); + + // set up the usage document, in case we need to print out how to use this program. + arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates use of node tracker."); + arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()); + arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + + osg::ref_ptr root = osgDB::readNodeFiles(arguments); + + if (!root) + { + std::cout<<"No model loaded, please specify a valid model on the command line."<tick(); + + + osg::BoundingSphere bs = root->getBound(); +#if 1 + osg::Vec3d start = bs.center() + osg::Vec3d(0.0,bs.radius(),0.0); + osg::Vec3d end = bs.center() - osg::Vec3d(0.0, bs.radius(),0.0); +#else + osg::Vec3d start = bs.center() + osg::Vec3d(0.0,0.0, bs.radius()); + osg::Vec3d end = bs.center() - osg::Vec3d(0.0, 0.0, bs.radius()); +#endif + + + osg::ref_ptr intersector = new osgUtil::LineSegmentIntersector(start, end); + + osgUtil::IntersectionVisitor intersectVisitor( intersector.get(), new MyReadCallback ); + + root->accept(intersectVisitor); + + osg::Timer_t endTick = osg::Timer::instance()->tick(); + + std::cout<<"Completed in "<delta_s(startTick,endTick)<containsIntersections() ) + { + osgUtil::LineSegmentIntersector::Intersections& intersections = intersector->getIntersections(); + for(osgUtil::LineSegmentIntersector::Intersections::iterator itr = intersections.begin(); + itr != intersections.end(); + ++itr) + { + const osgUtil::LineSegmentIntersector::Intersection& intersection = *itr; + std::cout<<" ratio "< +#include + +#include + +namespace osgUtil +{ + +// forward declare to allow Intersector to reference it. +class IntersectionVisitor; + +/** Pure virtual base class for implementating custom intersection technique. + * To implement a specific intersection technique on must override all + * the pure virtue methods, concrete examples of how to do this can be seen in + * the LineSegmentIntersector. */ +class Intersector : public osg::Referenced +{ + public: + + virtual Intersector* clone(osgUtil::IntersectionVisitor& iv) = 0; + + virtual void merge(Intersector* intersector) = 0; + + virtual bool enter(const osg::Node& node) = 0; + + virtual void leave() = 0; + + virtual void intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) = 0; + + virtual void reset() = 0; + + virtual bool containsIntersections() = 0; + +}; + +/** Concrent class for implementing line intersections with the scene graph. + * To be used in conjunction with IntersectionVisitor. */ +class LineSegmentIntersector : public Intersector +{ + public: + + LineSegmentIntersector(const osg::Vec3d& start, const osg::Vec3d& end); + + struct Intersection + { + bool operator < (const Intersection& rhs) const { return ratio < rhs.ratio; } + + typedef std::vector IndexList; + + double ratio; + osg::NodePath nodePath; + osg::ref_ptr drawable; + osg::ref_ptr matrix; + osg::Vec3d localIntersectionPoint; + osg::Vec3 localIntersectionNormal; + IndexList indexList; + unsigned int primitiveIndex; + }; + + typedef std::multiset Intersections; + + Intersections& getIntersections() { return _intersections; } + + public: + + virtual Intersector* clone(osgUtil::IntersectionVisitor& iv); + + virtual void merge(Intersector* intersector); + + virtual bool enter(const osg::Node& node); + + virtual void leave(); + + virtual void intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable); + + virtual void reset(); + + virtual bool containsIntersections() { return !_intersections.empty(); } + + protected: + + bool intersects(const osg::BoundingSphere& bs); + bool intersectAndClip(osg::Vec3d& s, osg::Vec3d& e,const osg::BoundingBox& bb); + + osg::Vec3d _start; + osg::Vec3d _end; + + Intersections _intersections; + +}; + +/** InteresectionVisitor is used to testing for intersections with the scene, traversing the scene using generic osgUtil::Intersector's to test against the scene. + * To implement different types of intersection techniques, one implements custom versions of the osgUtil::Intersector, and then + * pass the constructed intersector to the IntersectionVisitor.*/ +class OSGUTIL_EXPORT IntersectionVisitor : public osg::NodeVisitor +{ + public: + + /** Callback used to implement the reading of external files, allowing support for paged databases to be + * intergrated with IntersectionVisitor. A concrete implementation can be found in osgDB. + * Note, this loose coupling approach is required as osgUtil is independent from osgDB where the file reading + * is implemented, and osgDB itself is dependent upon osgUtil so a circular dependency would result from + * tighter integration.*/ + struct ReadCallback : public osg::Referenced + { + virtual osg::Node* readNodeFile(const std::string& filename) = 0; + }; + + + IntersectionVisitor(Intersector* intersector=0, ReadCallback* readCallback=0); + + virtual void reset(); + + /** Set the intersector that will be used to intersect with the scene, and to store any hits that occur.*/ + void setIntersector(Intersector* intersector); + + /** Get the intersector that will be used to intersect with the scene, and to store any hits that occur.*/ + Intersector* getIntersector() { return _intersectorStack.empty() ? 0 : _intersectorStack.front().get(); } + + /** Get the const intersector that will be used to intersect with the scene, and to store any hits that occur.*/ + const Intersector* getIntersector() const { return _intersectorStack.empty() ? 0 : _intersectorStack.front().get(); } + + + /** Set the read callback.*/ + void setReadCallback(ReadCallback* rc) { _readCallback = rc; } + + /** Get the read callback.*/ + ReadCallback* getReadCallback() { return _readCallback.get(); } + + /** Get the const read callback.*/ + const ReadCallback* getReadCallback() const { return _readCallback.get(); } + + osg::RefMatrix* getWindowMatrix() { return _windowStack.empty() ? 0 : _windowStack.back().get(); } + osg::RefMatrix* getProjectionMatrix() { return _projectionStack.empty() ? 0 : _projectionStack.back().get(); } + osg::RefMatrix* getViewMatrix() { return _viewStack.empty() ? 0 : _viewStack.back().get(); } + osg::RefMatrix* getModelMatrix() { return _modelStack.empty() ? 0 : _modelStack.back().get(); } + + + public: + + virtual void apply(osg::Node& node); + virtual void apply(osg::Geode& geode); + virtual void apply(osg::Billboard& geode); + virtual void apply(osg::Group& group); + virtual void apply(osg::LOD& lod); + virtual void apply(osg::PagedLOD& lod); + virtual void apply(osg::Transform& transform); + virtual void apply(osg::Projection& projection); + virtual void apply(osg::CameraNode& camera); + + protected: + + inline bool enter(const osg::Node& node) { return _intersectorStack.empty() ? false : _intersectorStack.back()->enter(node); } + inline void leave() { _intersectorStack.back()->leave(); } + inline void intersect(osg::Drawable* drawable) { _intersectorStack.back()->intersect(*this, drawable); } + inline void push_clone() { _intersectorStack.push_back ( _intersectorStack.front()->clone(*this) ); } + inline void pop_clone() { if (_intersectorStack.size()>=2) { _intersectorStack.front()->merge(_intersectorStack.back().get()); _intersectorStack.pop_back(); } } + + typedef std::list< osg::ref_ptr > IntersectorStack; + IntersectorStack _intersectorStack; + + osg::ref_ptr _readCallback; + + typedef std::list< osg::ref_ptr > MatrixStack; + MatrixStack _windowStack; + MatrixStack _projectionStack; + MatrixStack _viewStack; + MatrixStack _modelStack; + +}; + +} + +#endif + diff --git a/src/osgUtil/GNUmakefile b/src/osgUtil/GNUmakefile index 0e08b341c..bffdb8c1b 100644 --- a/src/osgUtil/GNUmakefile +++ b/src/osgUtil/GNUmakefile @@ -10,6 +10,7 @@ CXXFILES = \ DisplayRequirementsVisitor.cpp\ HalfWayMapGenerator.cpp\ HighlightMapGenerator.cpp\ + IntersectionVisitor.cpp\ IntersectVisitor.cpp\ Optimizer.cpp\ RenderBin.cpp\ diff --git a/src/osgUtil/IntersectionVisitor.cpp b/src/osgUtil/IntersectionVisitor.cpp new file mode 100644 index 000000000..43eb28603 --- /dev/null +++ b/src/osgUtil/IntersectionVisitor.cpp @@ -0,0 +1,607 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace osgUtil; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// LineSegmentIntersector +// + + +struct TriangleIntersection +{ + TriangleIntersection(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; +}; + + +struct TriangleIntersector +{ + osg::Vec3 _s; + osg::Vec3 _d; + float _length; + + int _index; + float _ratio; + bool _hit; + + typedef std::multimap TriangleIntersections; + + TriangleIntersections _intersections; + + TriangleIntersector() + { + } + + TriangleIntersector(const osg::Vec3d& start, osg::Vec3d& end, float ratio=FLT_MAX) + { + set(start,end,ratio); + } + + void set(const osg::Vec3d& start, osg::Vec3d& end, float ratio=FLT_MAX) + { + _hit=false; + _index = 0; + _ratio = ratio; + + _s = start; + _d = end - start; + _length = _d.length(); + _d /= _length; + } + + // bool intersect(const Vec3& v1,const Vec3& v2,const Vec3& v3,float& r) + inline void operator () (const osg::Vec3& v1,const osg::Vec3& v2,const osg::Vec3& v3, bool treatVertexDataAsTemporary) + { + ++_index; + + if (v1==v2 || v2==v3 || v1==v3) return; + + osg::Vec3 v12 = v2-v1; + osg::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; + } + else // d312 < 0 + { + if (ds12>0.0f) return; + if (ds12=0.0f) + { + if (ds23<0.0f) return; + if (ds23>d123) return; + } + else // d123 < 0 + { + if (ds23>0.0f) return; + if (ds23=0.0f) + { + if (ds31<0.0f) return; + if (ds31>d231) return; + } + else // d231 < 0 + { + if (ds31>0.0f) return; + if (ds31_length) return; + + osg::Vec3 normal = v12^v23; + normal.normalize(); + + float r = d/_length; + + + if (treatVertexDataAsTemporary) + { + _intersections.insert(std::pair(r,TriangleIntersection(_index-1,normal,r1,0,r2,0,r3,0))); + } + else + { + _intersections.insert(std::pair(r,TriangleIntersection(_index-1,normal,r1,&v1,r2,&v2,r3,&v3))); + } + _hit = true; + + } + +}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// LineSegmentIntersector +// + +LineSegmentIntersector::LineSegmentIntersector(const osg::Vec3d& start, const osg::Vec3d& end): + _start(start), + _end(end) +{ +} + +Intersector* LineSegmentIntersector::clone(osgUtil::IntersectionVisitor& iv) +{ + osg::RefMatrix* model= iv.getModelMatrix(); + if (model) + { + osg::Matrix inverse; + inverse.invert(*model); + + return new LineSegmentIntersector(_start * inverse, _end * inverse); + } + else + { + return new LineSegmentIntersector(_start, _end); + } +} + +void LineSegmentIntersector::merge(Intersector* intersector) +{ + LineSegmentIntersector* lsi = dynamic_cast(intersector); + _intersections.insert(lsi->_intersections.begin(),lsi->_intersections.end()); +} + +bool LineSegmentIntersector::enter(const osg::Node& node) +{ + return intersects( node.getBound() ); +} + +void LineSegmentIntersector::leave() +{ + // do nothing +} + +void LineSegmentIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawable* drawable) +{ + osg::Vec3d s(_start), e(_end); + if ( !intersectAndClip( s, e, drawable->getBound() ) ) return; + + osg::TriangleFunctor ti; + ti.set(s,e); + drawable->accept(ti); + if (ti._hit) + { + osg::Geometry* geometry = drawable->asGeometry(); + + for(TriangleIntersector::TriangleIntersections::iterator thitr = ti._intersections.begin(); + thitr != ti._intersections.end(); + ++thitr) + { + + // get ratio in s,e range + float ratio = thitr->first; + + // remap ratio into _start, _end range + ratio = ((s-_start).length() + ratio * (e-s).length() )/(_end-_start).length(); + + TriangleIntersection& triHit = thitr->second; + + Intersection hit; + hit.ratio = ratio; + hit.matrix = iv.getModelMatrix(); + hit.nodePath = iv.getNodePath(); + hit.drawable = drawable; + hit.primitiveIndex = triHit._index; + + hit.localIntersectionPoint = s*(1.0f-ratio) + e*ratio; + hit.localIntersectionNormal = triHit._normal; + + if (geometry) + { + osg::Vec3Array* vertices = dynamic_cast(geometry->getVertexArray()); + if (vertices) + { + osg::Vec3* first = &(vertices->front()); + if (triHit._v1) hit.indexList.push_back(triHit._v1-first); + if (triHit._v2) hit.indexList.push_back(triHit._v2-first); + if (triHit._v3) hit.indexList.push_back(triHit._v3-first); + } + } + + _intersections.insert(hit); + + } + } + +} + +void LineSegmentIntersector::reset() +{ + _intersections.clear(); +} + +bool LineSegmentIntersector::intersects(const osg::BoundingSphere& bs) +{ + // if bs not valid then return true based on the assumption that an invalid sphere is yet to be defined. + if (!bs.valid()) return true; + + osg::Vec3d sm = _start - bs._center; + double c = sm.length2()-bs._radius*bs._radius; + if (c<0.0) return true; + + osg::Vec3d se = _end-_start; + double a = se.length2(); + double b = (sm*se)*2.0; + double d = b*b-4.0*a*c; + + if (d<0.0) return false; + + d = sqrt(d); + + double div = 1.0/(2.0*a); + + double r1 = (-b-d)*div; + double r2 = (-b+d)*div; + + if (r1<=0.0 && r2<=0.0) return false; + + if (r1>=1.0 && r2>=1.0) return false; + + // passed all the rejection tests so line must intersect bounding sphere, return true. + return true; +} + +bool LineSegmentIntersector::intersectAndClip(osg::Vec3d& s, osg::Vec3d& e,const osg::BoundingBox& bb) +{ + // compate s and e against the xMin to xMax range of bb. + if (s.x()<=e.x()) + { + + // trivial reject of segment wholely outside. + if (e.x()bb.xMax()) return false; + + if (s.x()bb.xMax()) + { + // clip e to xMax. + e = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x()); + } + } + else + { + if (s.x()bb.xMax()) return false; + + if (e.x()bb.xMax()) + { + // clip e to xMax. + s = s+(e-s)*(bb.xMax()-s.x())/(e.x()-s.x()); + } + } + + // compate s and e against the yMin to yMax range of bb. + if (s.y()<=e.y()) + { + + // trivial reject of segment wholely outside. + if (e.y()bb.yMax()) return false; + + if (s.y()bb.yMax()) + { + // clip e to yMax. + e = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y()); + } + } + else + { + if (s.y()bb.yMax()) return false; + + if (e.y()bb.yMax()) + { + // clip e to yMax. + s = s+(e-s)*(bb.yMax()-s.y())/(e.y()-s.y()); + } + } + + // compate s and e against the zMin to zMax range of bb. + if (s.z()<=e.z()) + { + + // trivial reject of segment wholely outside. + if (e.z()bb.zMax()) return false; + + if (s.z()bb.zMax()) + { + // clip e to zMax. + e = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z()); + } + } + else + { + if (s.z()bb.zMax()) return false; + + if (e.z()bb.zMax()) + { + // clip e to zMax. + s = s+(e-s)*(bb.zMax()-s.z())/(e.z()-s.z()); + } + } + + if (s==e) return false; + + return true; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// IntersectionVisitor +// + +IntersectionVisitor::IntersectionVisitor(Intersector* intersector, ReadCallback* readCallback) +{ + // overide the default node visitor mode. + setTraversalMode(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN); + + setIntersector(intersector); + + setReadCallback(readCallback); +} + +void IntersectionVisitor::setIntersector(Intersector* intersector) +{ + // keep refernce around just in case intersector is already in the _intersectorStack, otherwsie the clear could delete it. + osg::ref_ptr temp = intersector; + + _intersectorStack.clear(); + + if (intersector) _intersectorStack.push_back(intersector); +} + +void IntersectionVisitor::reset() +{ + if (!_intersectorStack.empty()) + { + osg::ref_ptr intersector = _intersectorStack.front(); + intersector->reset(); + + _intersectorStack.clear(); + _intersectorStack.push_back(intersector); + } +} + +void IntersectionVisitor::apply(osg::Node& node) +{ + if (!enter(node)) return; + + traverse(node); + + leave(); +} + +void IntersectionVisitor::apply(osg::Group& group) +{ + if (!enter(group)) return; + + traverse(group); + + leave(); +} + +void IntersectionVisitor::apply(osg::Geode& geode) +{ + if (!enter(geode)) return; + + for(unsigned int i=0; i0) + { + osg::ref_ptr highestResChild; + + if (plod.getNumFileNames() != plod.getNumChildren() && _readCallback.valid()) + { + highestResChild = _readCallback->readNodeFile( plod.getDatabasePath() + plod.getFileName(plod.getNumFileNames()-1) ); + } + else if (plod.getNumChildren()>0) + { + highestResChild = plod.getChild( plod.getNumChildren()-1 ); + } + + if (highestResChild.valid()) + { + highestResChild->accept(*this); + } + } + + leave(); +} + + +void IntersectionVisitor::apply(osg::Transform& transform) +{ + if (!enter(transform)) return; + + osg::ref_ptr matrix = _modelStack.empty() ? new osg::RefMatrix() : new osg::RefMatrix(*_modelStack.back()); + transform.computeLocalToWorldMatrix(*matrix,this); + + _modelStack.push_back(matrix); + + // now push an new intersector clone transform to the new local coordinates + push_clone(); + + traverse(transform); + + // pop the clone. + pop_clone(); + + _modelStack.pop_back(); + + // tidy up an cached cull variabes in the current intersector. + leave(); +} + + +void IntersectionVisitor::apply(osg::Projection& projection) +{ + if (!enter(projection)) return; + + traverse(projection); + + leave(); +} + + +void IntersectionVisitor::apply(osg::CameraNode& camera) +{ + if (!enter(camera)) return; + + traverse(camera); + + leave(); +}