2012-03-22 01:36:20 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2008-07-04 23:57:48 +08:00
*
2012-03-22 01:36:20 +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
2008-07-04 23:57:48 +08:00
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
2012-03-22 01:36:20 +08:00
*
2008-07-04 23:57:48 +08:00
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2012-03-22 01:36:20 +08:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-07-04 23:57:48 +08:00
* OpenSceneGraph Public License for more details.
*/
#ifndef OSG_KDTREE
#define OSG_KDTREE 1
#include <osg/Shape>
#include <osg/Geometry>
2008-07-12 00:48:39 +08:00
#include <map>
2008-07-04 23:57:48 +08:00
namespace osg
{
/** Implementation of a kdtree for Geometry leaves, to enable fast intersection tests.*/
2012-03-22 01:36:20 +08:00
class OSG_EXPORT KdTree : public osg::Shape
2008-07-04 23:57:48 +08:00
{
public:
2012-03-22 01:36:20 +08:00
2008-07-06 20:14:19 +08:00
KdTree();
2012-03-22 01:36:20 +08:00
2008-07-06 20:14:19 +08:00
KdTree(const KdTree& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
2008-07-04 23:57:48 +08:00
META_Shape(osg, KdTree)
2012-03-22 01:36:20 +08:00
2008-07-13 01:30:17 +08:00
struct OSG_EXPORT BuildOptions
2008-07-06 20:14:19 +08:00
{
2008-07-08 04:27:56 +08:00
BuildOptions();
2012-03-22 01:36:20 +08:00
2008-07-16 21:26:06 +08:00
unsigned int _numVerticesProcessed;
unsigned int _targetNumTrianglesPerLeaf;
unsigned int _maxNumLevels;
2008-07-06 20:14:19 +08:00
};
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
/** Build the kdtree from the specified source geometry object.
2012-03-22 01:36:20 +08:00
* retun true on success. */
2008-07-06 20:14:19 +08:00
virtual bool build(BuildOptions& buildOptions, osg::Geometry* geometry);
2012-03-22 01:36:20 +08:00
2017-05-09 18:33:22 +08:00
void setVertices(osg::Vec3Array* vertices) { _vertices = vertices; }
const osg::Vec3Array* getVertices() const { return _vertices.get(); }
typedef std::vector< unsigned int > Indices;
// index in the VertexIndices vector
void setPrimitiveIndices(const Indices& indices) { _primitiveIndices = indices; }
Indices& getPrimitiveIndices() { return _primitiveIndices; }
const Indices& getPrimitiveIndices() const { return _primitiveIndices; }
// vector containing the primitive vertex index data packed as no_vertice_indices then vertex indices ie. for points it's (1, p0), for lines (2, p0, p1) etc.
void setVertexIndices(const Indices& indices) { _vertexIndices = indices; }
Indices& getVertexIndices() { return _vertexIndices; }
const Indices& getVertexIndices() const { return _vertexIndices; }
inline unsigned int addPoint(unsigned int p0)
2008-07-04 23:57:48 +08:00
{
2017-05-09 18:33:22 +08:00
unsigned int i = _vertexIndices.size();
_primitiveIndices.push_back(i);
_vertexIndices.push_back(1);
_vertexIndices.push_back(p0);
return i;
}
inline unsigned int addLine(unsigned int p0, unsigned int p1)
{
unsigned int i = _vertexIndices.size();
_primitiveIndices.push_back(i);
_vertexIndices.push_back(2);
_vertexIndices.push_back(p0);
_vertexIndices.push_back(p1);
return i;
}
2012-03-22 01:36:20 +08:00
2017-05-09 18:33:22 +08:00
inline unsigned int addTriangle(unsigned int p0, unsigned int p1, unsigned int p2)
{
unsigned int i = _vertexIndices.size();
_primitiveIndices.push_back(i);
_vertexIndices.push_back(3);
_vertexIndices.push_back(p0);
_vertexIndices.push_back(p1);
_vertexIndices.push_back(p2);
return i;
}
2008-07-04 23:57:48 +08:00
2017-05-09 18:33:22 +08:00
inline unsigned int addQuad(unsigned int p0, unsigned int p1, unsigned int p2, unsigned int p3)
{
unsigned int i = _vertexIndices.size();
_primitiveIndices.push_back(i);
_vertexIndices.push_back(4);
_vertexIndices.push_back(p0);
_vertexIndices.push_back(p1);
_vertexIndices.push_back(p2);
_vertexIndices.push_back(p3);
return i;
}
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
typedef int value_type;
2008-07-06 20:14:19 +08:00
struct KdNode
2008-07-04 23:57:48 +08:00
{
2008-07-06 20:14:19 +08:00
KdNode():
2008-07-04 23:57:48 +08:00
first(0),
second(0) {}
2008-07-06 20:14:19 +08:00
KdNode(value_type f, value_type s):
2008-07-04 23:57:48 +08:00
first(f),
second(s) {}
2008-07-10 03:41:36 +08:00
osg::BoundingBox bb;
2012-03-22 01:36:20 +08:00
value_type first;
2008-07-04 23:57:48 +08:00
value_type second;
};
2008-07-07 21:21:37 +08:00
typedef std::vector< KdNode > KdNodeList;
2008-07-08 04:27:56 +08:00
2008-07-06 20:14:19 +08:00
int addNode(const KdNode& node)
{
2012-03-22 01:36:20 +08:00
int num = static_cast<int>(_kdNodes.size());
_kdNodes.push_back(node);
2008-07-06 20:14:19 +08:00
return num;
}
2008-07-12 00:48:39 +08:00
KdNode& getNode(int nodeNum) { return _kdNodes[nodeNum]; }
const KdNode& getNode(int nodeNum) const { return _kdNodes[nodeNum]; }
2012-03-22 01:36:20 +08:00
2008-07-12 00:48:39 +08:00
KdNodeList& getNodes() { return _kdNodes; }
const KdNodeList& getNodes() const { return _kdNodes; }
2008-07-06 20:14:19 +08:00
2017-04-20 01:18:46 +08:00
template<class IntersectFunctor>
void intersect(IntersectFunctor& functor, const KdNode& node) const
{
if (node.first<0)
{
// treat as a leaf
int istart = -node.first-1;
int iend = istart + node.second;
for(int i=istart; i<iend; ++i)
{
2017-05-09 18:33:22 +08:00
unsigned int primitiveIndex = _primitiveIndices[i];
unsigned int numVertices = _vertexIndices[primitiveIndex++];
switch(numVertices)
{
case(1): functor.intersect(_vertices.get(), i, _vertexIndices[primitiveIndex]); break;
2017-05-10 16:19:29 +08:00
case(2): functor.intersect(_vertices.get(), i, _vertexIndices[primitiveIndex], _vertexIndices[primitiveIndex+1]); break;
case(3): functor.intersect(_vertices.get(), i, _vertexIndices[primitiveIndex], _vertexIndices[primitiveIndex+1], _vertexIndices[primitiveIndex+2]); break;
case(4): functor.intersect(_vertices.get(), i, _vertexIndices[primitiveIndex], _vertexIndices[primitiveIndex+1], _vertexIndices[primitiveIndex+2], _vertexIndices[primitiveIndex+3]); break;
2017-05-09 18:33:22 +08:00
default : OSG_NOTICE<<"Warning: KdTree::intersect() encounted unsupported primitive size of "<<numVertices<<std::endl; break;
}
2017-04-20 01:18:46 +08:00
}
}
2017-04-21 02:21:21 +08:00
else if (functor.enter(node.bb))
2017-04-20 01:18:46 +08:00
{
if (node.first>0) intersect(functor, _kdNodes[node.first]);
if (node.second>0) intersect(functor, _kdNodes[node.second]);
2017-04-21 02:21:21 +08:00
functor.leave();
2017-04-20 01:18:46 +08:00
}
}
2008-07-06 20:14:19 +08:00
2008-07-12 00:48:39 +08:00
protected:
2008-07-06 20:14:19 +08:00
2017-05-09 18:33:22 +08:00
osg::ref_ptr<osg::Vec3Array> _vertices;
Indices _primitiveIndices;
Indices _vertexIndices;
KdNodeList _kdNodes;
2008-07-04 23:57:48 +08:00
};
class OSG_EXPORT KdTreeBuilder : public osg::NodeVisitor
{
public:
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
KdTreeBuilder();
2012-03-22 01:36:20 +08:00
2008-07-07 02:27:10 +08:00
KdTreeBuilder(const KdTreeBuilder& rhs);
2013-01-25 02:48:34 +08:00
META_NodeVisitor(osg, KdTreeBuilder)
2008-12-17 20:13:15 +08:00
2008-07-07 02:27:10 +08:00
virtual KdTreeBuilder* clone() { return new KdTreeBuilder(*this); }
2014-06-26 22:16:11 +08:00
void apply(Geometry& geometry);
2012-03-22 01:36:20 +08:00
2008-07-06 20:14:19 +08:00
KdTree::BuildOptions _buildOptions;
2008-07-04 23:57:48 +08:00
osg::ref_ptr<osg::KdTree> _kdTreePrototype;
2008-07-12 00:48:39 +08:00
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
protected:
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
virtual ~KdTreeBuilder() {}
2012-03-22 01:36:20 +08:00
2008-07-04 23:57:48 +08:00
};
}
#endif