diff --git a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp index 6c1be534e..fe0ed948b 100644 --- a/examples/osgkeyboardmouse/osgkeyboardmouse.cpp +++ b/examples/osgkeyboardmouse/osgkeyboardmouse.cpp @@ -143,7 +143,9 @@ class PickHandler : public osgGA::GUIEventHandler public: PickHandler(): - _mx(0.0),_my(0.0) {} + _mx(0.0),_my(0.0), + _usePolytopeIntersector(false), + _useWindowCoordinates(false) {} ~PickHandler() {} @@ -165,6 +167,26 @@ public: osg::notify(osg::NOTICE)<<"Saved model to file 'saved_model.osg'"<getSceneData()), "saved_model.osg"); } + else if (ea.getKey()=='p') + { + _usePolytopeIntersector = !_usePolytopeIntersector; + if (_usePolytopeIntersector) + { + osg::notify(osg::NOTICE)<<"Using PolytopeIntersector"<getCamera()->getViewport(); + double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5)); + double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5)); -#if 0 - // use window coordinates - // remap the mouse x,y into viewport coordinates. - osg::Viewport* viewport = viewer->getCamera()->getViewport(); - double mx = viewport->x() + (int)((double )viewport->width()*(ea.getXnormalized()*0.5+0.5)); - double my = viewport->y() + (int)((double )viewport->height()*(ea.getYnormalized()*0.5+0.5)); - - // half width, height. - double w = 5.0f; - double h = 5.0f; - osgUtil::PolytopeIntersector* picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h ); -#else - double mx = ea.getXnormalized(); - double my = ea.getYnormalized(); - double w = 0.05; - double h = 0.05; - osgUtil::PolytopeIntersector* picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); -#endif + // half width, height. + double w = 5.0f; + double h = 5.0f; + picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::WINDOW, mx-w, my-h, mx+w, my+h ); + } else { + double mx = ea.getXnormalized(); + double my = ea.getYnormalized(); + double w = 0.05; + double h = 0.05; + picker = new osgUtil::PolytopeIntersector( osgUtil::Intersector::PROJECTION, mx-w, my-h, mx+w, my+h ); + } osgUtil::IntersectionVisitor iv(picker); viewer->getCamera()->accept(iv); if (picker->containsIntersections()) { - osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection(); + osgUtil::PolytopeIntersector::Intersections& intersections = picker->getIntersections(); - osg::NodePath& nodePath = intersection.nodePath; - node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0; - parent = (nodePath.size()>=2)?dynamic_cast(nodePath[nodePath.size()-2]):0; + for (osgUtil::PolytopeIntersector::Intersections::iterator it=intersections.begin(); + it!=intersections.end(); ++it) { + osgUtil::PolytopeIntersector::Intersection intersection=*it; - if (node) std::cout<<" Hits "<className()<<" nodePath size"<=1)?nodePath[nodePath.size()-1]:0; + parent = (nodePath.size()>=2)?dynamic_cast(nodePath[nodePath.size()-2]):0; + + if (node) std::cout<<" Hits "<className()<<" nodePath size"<getCamera()->getViewport(); - float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f)); - float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f)); - osgUtil::LineSegmentIntersector* picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my ); - #endif - + osgUtil::LineSegmentIntersector* picker; + if (!_useWindowCoordinates) + { + // use non dimensional coordinates - in projection/clip space + picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::PROJECTION, ea.getXnormalized(),ea.getYnormalized() ); + } else { + // use window coordinates + // remap the mouse x,y into viewport coordinates. + osg::Viewport* viewport = viewer->getCamera()->getViewport(); + float mx = viewport->x() + (int)((float)viewport->width()*(ea.getXnormalized()*0.5f+0.5f)); + float my = viewport->y() + (int)((float)viewport->height()*(ea.getYnormalized()*0.5f+0.5f)); + picker = new osgUtil::LineSegmentIntersector( osgUtil::Intersector::WINDOW, mx, my ); + } osgUtil::IntersectionVisitor iv(picker); viewer->getCamera()->accept(iv); @@ -274,36 +302,38 @@ public: parent = (nodePath.size()>=2)?dynamic_cast(nodePath[nodePath.size()-2]):0; if (node) std::cout<<" Hits "<className()<<" nodePath size"<className()<(parent); + if (!parentAsScribe) { - - std::cout<<" parent "<className()<(parent); - if (!parentAsScribe) + // node not already picked, so highlight it with an osgFX::Scribe + osgFX::Scribe* scribe = new osgFX::Scribe(); + scribe->addChild(node); + parent->replaceChild(node,scribe); + } + else + { + // node already picked so we want to remove scribe to unpick it. + osg::Node::ParentList parentList = parentAsScribe->getParents(); + for(osg::Node::ParentList::iterator itr=parentList.begin(); + itr!=parentList.end(); + ++itr) { - // node not already picked, so highlight it with an osgFX::Scribe - osgFX::Scribe* scribe = new osgFX::Scribe(); - scribe->addChild(node); - parent->replaceChild(node,scribe); - } - else - { - // node already picked so we want to remove scribe to unpick it. - osg::Node::ParentList parentList = parentAsScribe->getParents(); - for(osg::Node::ParentList::iterator itr=parentList.begin(); - itr!=parentList.end(); - ++itr) - { - (*itr)->replaceChild(parentAsScribe,node); - } + (*itr)->replaceChild(parentAsScribe,node); } } + } void saveSelectedModel(osg::Node* scene) @@ -323,6 +353,8 @@ public: protected: float _mx,_my; + bool _usePolytopeIntersector; + bool _useWindowCoordinates; }; int main( int argc, char **argv ) diff --git a/include/osg/TemplatePrimitiveFunctor b/include/osg/TemplatePrimitiveFunctor new file mode 100644 index 000000000..cd91ddcd6 --- /dev/null +++ b/include/osg/TemplatePrimitiveFunctor @@ -0,0 +1,302 @@ +/* -*-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. +*/ + +#ifndef OSG_TERMPLATEPRIMITIVEFUNCTOR +#define OSG_TERMPLATEPRIMITIVEFUNCTOR 1 + +#include +#include + +namespace osg { + + + /** Provides access to the primitives that compose an \c osg::Drawable. + *

Notice that \c TemplatePrimitiveFunctor is a class template, and that it inherits + * from its template parameter \c T. This template parameter must implement + * operator()(const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 + * v3, bool treatVertexDataAsTemporary), + * operator()(const osg::Vec3 v1, const osg::Vec3 v2, bool + * treatVertexDataAsTemporary), operator()(const osg::Vec3 v1, + * const osg::Vec3 v2, const osg::Vec3 v3, bool treatVertexDataAsTemporary), + * and operator()(const osg::Vec3 v1, const osg::Vec3 v2, const osg::Vec3 v3, + * const osg::Vec3 v4, bool treatVertexDataAsTemporary) which will be called + * for the matching primitive when the functor is applied to a \c Drawable. + * Parameters \c v1, \c v2, \c v3, and \c v4 are the vertices of the primitive. + * The last parameter, \c treatVertexDataAsTemporary, indicates whether these + * vertices are coming from a "real" vertex array, or from a temporary vertex array, + * created by the \c TemplatePrimitiveFunctor from some other geometry representation. + * @see \c PrimitiveFunctor for general usage hints. + */ + template + class TemplatePrimitiveFunctor : public PrimitiveFunctor, public T + { + public: + + TemplatePrimitiveFunctor() + { + _vertexArraySize=0; + _vertexArrayPtr=0; + _modeCache=0; + _treatVertexDataAsTemporary=false; + } + + virtual ~TemplatePrimitiveFunctor() {} + + void setTreatVertexDataAsTemporary(bool treatVertexDataAsTemporary) { _treatVertexDataAsTemporary=treatVertexDataAsTemporary; } + bool getTreatVertexDataAsTemporary() const { return _treatVertexDataAsTemporary; } + + virtual void setVertexArray(unsigned int,const Vec2*) + { + notify(WARN)<<"Triangle Functor does not support Vec2* vertex arrays"<operator()(*(vptr),*(vptr+1),*(vptr+2),_treatVertexDataAsTemporary); + break; + } + case(GL_TRIANGLE_STRIP): { + const Vec3* vptr = &_vertexArrayPtr[first]; + for(GLsizei i=2;ioperator()(*(vptr),*(vptr+2),*(vptr+1),_treatVertexDataAsTemporary); + else this->operator()(*(vptr),*(vptr+1),*(vptr+2),_treatVertexDataAsTemporary); + } + break; + } + case(GL_QUADS): { + const Vec3* vptr = &_vertexArrayPtr[first]; + for(GLsizei i=3;ioperator()(*(vptr),*(vptr+1),*(vptr+2),*(vptr+3),_treatVertexDataAsTemporary); + } + break; + } + case(GL_QUAD_STRIP): { + const Vec3* vptr = &_vertexArrayPtr[first]; + for(GLsizei i=3;ioperator()(*(vptr),*(vptr+1),*(vptr+3),*(vptr+2),_treatVertexDataAsTemporary); + } + break; + } + case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN + case(GL_TRIANGLE_FAN): { + const Vec3* vfirst = &_vertexArrayPtr[first]; + const Vec3* vptr = vfirst+1; + for(GLsizei i=2;ioperator()(*(vfirst),*(vptr),*(vptr+1),_treatVertexDataAsTemporary); + } + break; + } + case(GL_POINTS): { + const Vec3* vlast = &_vertexArrayPtr[first+count]; + for(const Vec3* vptr=&_vertexArrayPtr[first];vptroperator()(*(vptr),_treatVertexDataAsTemporary); + break; + } + case(GL_LINES): { + const Vec3* vlast = &_vertexArrayPtr[first+count]; + for(const Vec3* vptr=&_vertexArrayPtr[first];vptroperator()(*(vptr),*(vptr+1),_treatVertexDataAsTemporary); + break; + } + case(GL_LINE_STRIP): { + const Vec3* vlast = &_vertexArrayPtr[first+count]; + for(const Vec3* vptr=&_vertexArrayPtr[first];vptroperator()(*(vptr),*(vptr+1),_treatVertexDataAsTemporary); + break; + } + case(GL_LINE_LOOP): { + const Vec3* vlast = &_vertexArrayPtr[first+count]; + for(const Vec3* vptr=&_vertexArrayPtr[first];vptroperator()(*(vptr),*(vptr+1),_treatVertexDataAsTemporary); + this->operator()(*(vlast-1),_vertexArrayPtr[first],_treatVertexDataAsTemporary); + break; + } + default: + break; + } + } + + template + void drawElementsTemplate(GLenum mode,GLsizei count,const IndexType* indices) + { + if (indices==0 || count==0) return; + + typedef const IndexType* IndexPointer; + + switch(mode) + { + case(GL_TRIANGLES): { + IndexPointer ilast = &indices[count]; + for(IndexPointer iptr=indices;iptroperator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)],_vertexArrayPtr[*(iptr+2)],_treatVertexDataAsTemporary); + break; + } + case(GL_TRIANGLE_STRIP): { + IndexPointer iptr = indices; + for(GLsizei i=2;ioperator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+2)], + _vertexArrayPtr[*(iptr+1)],_treatVertexDataAsTemporary); + else this->operator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)], + _vertexArrayPtr[*(iptr+2)],_treatVertexDataAsTemporary); + } + break; + } + case(GL_QUADS): { + IndexPointer iptr = indices; + for(GLsizei i=3;ioperator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)], + _vertexArrayPtr[*(iptr+2)],_vertexArrayPtr[*(iptr+3)], + _treatVertexDataAsTemporary); + } + break; + } + case(GL_QUAD_STRIP): { + IndexPointer iptr = indices; + for(GLsizei i=3;ioperator()(_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)], + _vertexArrayPtr[*(iptr+3)],_vertexArrayPtr[*(iptr+2)], + _treatVertexDataAsTemporary); + } + break; + } + case(GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN + case(GL_TRIANGLE_FAN): { + IndexPointer iptr = indices; + const Vec3& vfirst = _vertexArrayPtr[*iptr]; + ++iptr; + for(GLsizei i=2;ioperator()(vfirst,_vertexArrayPtr[*(iptr)],_vertexArrayPtr[*(iptr+1)], + _treatVertexDataAsTemporary); + } + break; + } + case(GL_POINTS): { + IndexPointer ilast = &indices[count]; + for(IndexPointer iptr=indices;iptroperator()(_vertexArrayPtr[*iptr],_treatVertexDataAsTemporary); + break; + } + case(GL_LINES): { + IndexPointer ilast = &indices[count]; + for(IndexPointer iptr=indices;iptroperator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)], + _treatVertexDataAsTemporary); + break; + } + case(GL_LINE_STRIP): { + IndexPointer ilast = &indices[count]; + for(IndexPointer iptr=indices;iptroperator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)], + _treatVertexDataAsTemporary); + break; + } + case(GL_LINE_LOOP): { + IndexPointer ilast = &indices[count]; + for(IndexPointer iptr=indices;iptroperator()(_vertexArrayPtr[*iptr],_vertexArrayPtr[*(iptr+1)], + _treatVertexDataAsTemporary); + break; + this->operator()(_vertexArrayPtr[*(ilast-1)],_vertexArrayPtr[indices[0]], + _treatVertexDataAsTemporary); + } + default: + break; + } + } + + + virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) + { + drawElementsTemplate(mode, count, indices); + } + + virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) + { + drawElementsTemplate(mode, count, indices); + } + + virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) + { + drawElementsTemplate(mode, count, indices); + } + + /** Note: + * begin(..),vertex(..) & end() are convenience methods for adapting + * non vertex array primitives to vertex array based primitives. + * This is done to simplify the implementation of primtive functor + * subclasses - users only need override drawArray and drawElements. + */ + virtual void begin(GLenum mode) + { + _modeCache = mode; + _vertexCache.clear(); + } + + virtual void vertex(const Vec2& vert) { _vertexCache.push_back(osg::Vec3(vert[0],vert[1],0.0f)); } + virtual void vertex(const Vec3& vert) { _vertexCache.push_back(vert); } + virtual void vertex(const Vec4& vert) { _vertexCache.push_back(osg::Vec3(vert[0],vert[1],vert[2])/vert[3]); } + virtual void vertex(float x,float y) { _vertexCache.push_back(osg::Vec3(x,y,0.0f)); } + virtual void vertex(float x,float y,float z) { _vertexCache.push_back(osg::Vec3(x,y,z)); } + virtual void vertex(float x,float y,float z,float w) { _vertexCache.push_back(osg::Vec3(x,y,z)/w); } + virtual void end() + { + if (!_vertexCache.empty()) + { + setVertexArray(_vertexCache.size(),&_vertexCache.front()); + _treatVertexDataAsTemporary = true; + drawArrays(_modeCache,0,_vertexCache.size()); + } + } + + protected: + + + unsigned int _vertexArraySize; + const Vec3* _vertexArrayPtr; + + GLenum _modeCache; + std::vector _vertexCache; + bool _treatVertexDataAsTemporary; + }; + + +} + +#endif diff --git a/src/osgUtil/PolytopeIntersector.cpp b/src/osgUtil/PolytopeIntersector.cpp index 870605427..236a175ee 100644 --- a/src/osgUtil/PolytopeIntersector.cpp +++ b/src/osgUtil/PolytopeIntersector.cpp @@ -1,13 +1,13 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield +/* -*-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 + * 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ @@ -17,11 +17,308 @@ #include #include #include -#include +#include using namespace osgUtil; + +class PolytopePrimitiveIntersector { +public: +#ifdef OSG_USE_DOUBLE_PLANE + typedef double value_type; + typedef osg::Vec3d Vec3_type; +#else + typedef float value_type; + typedef osg::Vec3f Vec3_type; +#endif + + typedef osg::Polytope::ClippingMask PlaneMask; + typedef osg::Polytope::PlaneList PlaneList; + typedef std::vector > CandList_t; + + /// a line defined by the intersection of two planes + struct PlanesLine { + PlanesLine(PlaneMask m, Vec3_type p, Vec3_type d) : + mask(m), pos(p), dir(d) {} + PlaneMask mask; + Vec3_type pos; + Vec3_type dir; + }; + typedef std::vector LinesList; + + PolytopePrimitiveIntersector() : + numPoints(0), + numLines(0), + numTriangles(0), + numQuads(0), + _numIntersections(0) {} + + value_type eps() { return 1e-6; } + + /// check which candidate points lie within the polytope volume + /// mark outliers with mask == 0, return number of remaining candidates + unsigned int checkCandidatePoints(PlaneMask inside_mask, CandList_t& cand) { + PlaneMask selector_mask = 0x1; + unsigned int numCands=cand.size(); + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end() && numCands>0; + ++it, selector_mask <<= 1) { + const osg::Plane& plane=*it; + if (selector_mask & inside_mask) continue; + for (CandList_t::iterator pointIt=cand.begin(); pointIt!=cand.end(); ++pointIt) { + PlaneMask mask=pointIt->first; + if (mask==0) continue; + if (selector_mask & mask) continue; + if (plane.distance(pointIt->second)<0.0f) { + mask=0; // mark as outside + --numCands; + if (numCands==0) return 0; + } + } + } + return numCands; + } + + // handle points + void operator()(const Vec3_type v1, bool treatVertexDataAsTemporary) { + ++numPoints; + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it) { + const osg::Plane& plane=*it; + const value_type d1=plane.distance(v1); + if (d1<0.0f) return; // point outside + } + ++_numIntersections; + } + + // handle lines + void operator()(const Vec3_type v1, const Vec3_type v2, bool treatVertexDataAsTemporary) + { + ++numLines; + PlaneMask selector_mask = 0x1; + PlaneMask inside_mask = 0x0; + CandList_t cand; + + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it, selector_mask<<=1) { + const osg::Plane& plane=*it; + const value_type d1=plane.distance(v1); + const value_type d2=plane.distance(v2); + const bool d1IsNegative = (d1<0.0f); + const bool d2IsNegative = (d2<0.0f); + if (d1IsNegative && d2IsNegative) return; // line outside + if (!d1IsNegative && !d2IsNegative) { + inside_mask |= selector_mask; + continue; // completly inside + } + if (d1==0.0f) { + cand.push_back( CandList_t::value_type(selector_mask, v1) ); + } else if (d2==0.0f) { + cand.push_back( CandList_t::value_type(selector_mask, v2) ); + } else if (d1IsNegative && !d2IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1-(v2-v1)*(d1/(-d1+d2))) ) ); + } else if (!d1IsNegative && d2IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1+(v2-v1)*(d1/(d1-d2))) ) ); + } + + } + if (inside_mask==_plane_mask) { + ++_numIntersections; + return; + } + + unsigned int numCands=checkCandidatePoints(inside_mask, cand); + if (numCands>0) { + ++_numIntersections; + } + + } + + // handle triangles + void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, + bool treatVertexDataAsTemporary) + { + ++numTriangles; + PlaneMask selector_mask = 0x1; + PlaneMask inside_mask = 0x0; + CandList_t cand; + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); + ++it, selector_mask <<= 1) { + const osg::Plane& plane=*it; + const value_type d1=plane.distance(v1); + const value_type d2=plane.distance(v2); + const value_type d3=plane.distance(v3); + const bool d1IsNegative = (d1<0.0f); + const bool d2IsNegative = (d2<0.0f); + const bool d3IsNegative = (d3<0.0f); + if (d1IsNegative && d2IsNegative && d3IsNegative) return; // triangle outside + if (!d1IsNegative && !d2IsNegative && !d3IsNegative) { + inside_mask |= selector_mask; + continue; // completly inside + } + + // edge v1-v2 intersects + if (d1==0.0f) { + cand.push_back( CandList_t::value_type(selector_mask, v1) ); + } else if (d2==0.0f) { + cand.push_back( CandList_t::value_type(selector_mask, v2) ); + } else if (d1IsNegative && !d2IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1-(v2-v1)*(d1/(-d1+d2))) ) ); + } else if (!d1IsNegative && d2IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1+(v2-v1)*(d1/(d1-d2))) ) ); + } + + // edge v1-v3 intersects + if (d3==0.0f) { + cand.push_back( CandList_t::value_type(selector_mask, v3) ); + } else if (d1IsNegative && !d3IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1-(v3-v1)*(d1/(-d1+d3))) ) ); + } else if (!d1IsNegative && d3IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v1+(v3-v1)*(d1/(d1-d3))) ) ); + } + + // edge v2-v3 intersects + if (d2IsNegative && !d3IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v2-(v3-v2)*(d2/(-d2+d3))) ) ); + } else if (!d2IsNegative && d3IsNegative) { + cand.push_back( CandList_t::value_type(selector_mask, (v2+(v3-v2)*(d2/(d2-d3))) ) ); + } + } + + if (_plane_mask==inside_mask) { // triangle lies inside of all planes + ++_numIntersections; + return; + } + + if (cand.empty() && _planes.size()<3) { + return; + } + + unsigned int numCands=checkCandidatePoints(inside_mask, cand); + + if (numCands>0) { + ++_numIntersections; + return; + } + + // handle case where the polytope goes through the triangle + // without containing any point of it + + LinesList& lines=getPolytopeLines(); + cand.clear(); + + // check all polytope lines against the triangle + // use algorithm from "Real-time rendering" (second edition) pp.580 + const Vec3_type e1=v2-v1; + const Vec3_type e2=v3-v1; + + for (LinesList::const_iterator it=lines.begin(); it!=lines.end(); ++it) { + const PlanesLine& line=*it; + + Vec3_type p=line.dir^e2; + const value_type a=e1*p; + if (osg::absolute(a)1.0f) continue; + const Vec3_type q=s^e1; + const value_type v=f*(line.dir*q); + if (v<0.0f || u+v>1.0f) continue; + const value_type t=f*(e2*q); + + cand.push_back(CandList_t::value_type(line.mask, line.pos+line.dir*t)); + } + + numCands=checkCandidatePoints(inside_mask, cand); + + if (numCands>0) { + ++_numIntersections; + return; + } + + } + + /// handle quads + void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, const Vec3_type v4, + bool treatVertexDataAsTemporary) { + ++numQuads; + this->operator()(v1,v2,v3,treatVertexDataAsTemporary); + this->operator()(v1,v3,v4,treatVertexDataAsTemporary); + numTriangles-=2; + } + + void setPolytope(osg::Polytope& polytope) { + + const PlaneMask currentMask = polytope.getCurrentMask(); + PlaneMask selector_mask = 0x1; + + const PlaneList& planeList = polytope.getPlaneList(); + unsigned int numActivePlanes = 0; + + PlaneList::const_iterator itr; + for(itr=planeList.begin(); itr!=planeList.end(); ++itr) { + if (currentMask&selector_mask) ++numActivePlanes; + selector_mask <<= 1; + } + + _plane_mask = 0x0; + _planes.clear(); + _planes.reserve(numActivePlanes); + _lines.clear(); + + selector_mask=0x1; + for(itr=planeList.begin(); itr!=planeList.end(); ++itr) { + if (currentMask&selector_mask) { + _planes.push_back(*itr); + _plane_mask <<= 1; + _plane_mask |= 0x1; + } + selector_mask <<= 1; + } + } + + /// get boundary lines of polytope + LinesList& getPolytopeLines() { + if (!_lines.empty()) return _lines; + + PlaneMask selector_mask = 0x1; + for (PlaneList::const_iterator it=_planes.begin(); it!=_planes.end(); ++it, selector_mask <<= 1 ) { + const osg::Plane& plane1=*it; + const Vec3_type normal1=plane1.getNormal(); + const Vec3_type point1=normal1*(-plane1[3]); /// canonical point on plane1 + PlaneMask sub_selector_mask = (selector_mask<<1); + for (PlaneList::const_iterator jt=it+1; jt!=_planes.end(); ++jt, sub_selector_mask <<= 1 ) { + const osg::Plane& plane2=*jt; + const Vec3_type normal2=plane2.getNormal(); + if (osg::absolute(normal1*normal2) > (1.0-eps())) continue; + const Vec3_type lineDirection = normal1^normal2; + + const Vec3_type searchDirection = lineDirection^normal1; /// search dir in plane1 + const value_type seachDist = -plane2.distance(point1)/(searchDirection*normal2); + if (osg::isNaN(seachDist)) continue; + const Vec3_type linePoint=point1+searchDirection*seachDist; + _lines.push_back(PlanesLine(selector_mask|sub_selector_mask, linePoint, lineDirection)); + } + } + return _lines; + } + + unsigned int getNumIntersections() const { return _numIntersections; } + unsigned int getNumPrimitives() const { return numPoints+numLines+numTriangles; } + unsigned int getNumPlanes() const { return _planes.size(); } + + unsigned int numPoints; + unsigned int numLines; + unsigned int numTriangles; + unsigned int numQuads; + +private: + PlaneList _planes; ///< active planes extracted from polytope + LinesList _lines; ///< all intersection lines of two polytope planes + PlaneMask _plane_mask; ///< mask for all planes of the polytope + unsigned int _numIntersections; +}; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // PolytopeIntersector @@ -73,18 +370,18 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv) osg::Matrix matrix; switch (_coordinateFrame) { - case(WINDOW): + case(WINDOW): if (iv.getWindowMatrix()) matrix.preMult( *iv.getWindowMatrix() ); if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; - case(PROJECTION): + case(PROJECTION): if (iv.getProjectionMatrix()) matrix.preMult( *iv.getProjectionMatrix() ); if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; - case(VIEW): + case(VIEW): if (iv.getViewMatrix()) matrix.preMult( *iv.getViewMatrix() ); if (iv.getModelMatrix()) matrix.preMult( *iv.getModelMatrix() ); break; @@ -117,17 +414,24 @@ void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawa { if ( !_polytope.contains( drawable->getBound() ) ) return; - osg::Geometry* geometry = drawable->asGeometry(); - osg::Vec3Array* vertices = geometry ? dynamic_cast(geometry->getVertexArray()) : 0; - if (vertices) - { - if (!_polytope.contains(*vertices)) return; + osg::TemplatePrimitiveFunctor func; + func.setPolytope(_polytope); + + drawable->accept(func); + + if (func.getNumIntersections()==0) { + return; } + osg::notify(osg::INFO) << func.getNumIntersections() << " intersections with " + << func.numPoints<<" points, "<< func.numLines + <<" lines, "<< func.numTriangles + <<" triangles, "<