From Peter Hrenka, "Due to popular demand I would like to submit this
enhanced version of PolytopeIntersector. New features of PolytopeIntersector : * Dimension mask: The user may specify the dimensions of the primitives to be tested. Checking polytope-triangle and polytope-quad intersections is rather slow so this can be turned off. * Reference plane: The resulting intersections are sorted by the distance to this plane. New memebers of PolytopeIntersector::Intersection : * distance: Distance of localIntersectionPoint to the reference plane * maxDistance: Maximum distance of all intersectionPoints to the reference plane. * intersectionPoints: The points intersecting the planes of the polytope or points completely inside the polytope. * localIntersectionPoint: arithmetic mean of all intersection points * primitiveIndex: Index of the primitive that intersected I added some more output to the example osgkeyboardmouse."
This commit is contained in:
@@ -234,20 +234,22 @@ public:
|
||||
|
||||
if (picker->containsIntersections())
|
||||
{
|
||||
osgUtil::PolytopeIntersector::Intersections& intersections = picker->getIntersections();
|
||||
osgUtil::PolytopeIntersector::Intersection intersection = picker->getFirstIntersection();
|
||||
|
||||
for (osgUtil::PolytopeIntersector::Intersections::iterator it=intersections.begin();
|
||||
it!=intersections.end(); ++it) {
|
||||
osgUtil::PolytopeIntersector::Intersection intersection=*it;
|
||||
osg::notify(osg::NOTICE)<<"Picked "<<intersection.localIntersectionPoint<<std::endl
|
||||
<<" Distance to ref. plane "<<intersection.distance
|
||||
<<", max. dist "<<intersection.maxDistance
|
||||
<<", primitive index "<<intersection.primitiveIndex
|
||||
<<", numIntersectionPoints "
|
||||
<<intersection.numIntersectionPoints
|
||||
<<std::endl;
|
||||
|
||||
osg::NodePath& nodePath = intersection.nodePath;
|
||||
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
|
||||
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
|
||||
|
||||
if (node) std::cout<<" Hits "<<node->className()<<" nodePath size"<<nodePath.size()<<std::endl;
|
||||
toggleScribe(parent, node);
|
||||
}
|
||||
osg::NodePath& nodePath = intersection.nodePath;
|
||||
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
|
||||
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
|
||||
|
||||
if (node) std::cout<<" Hits "<<node->className()<<" nodePath size "<<nodePath.size()<<std::endl;
|
||||
toggleScribe(parent, node);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,14 +24,21 @@ namespace osgUtil
|
||||
class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
|
||||
{
|
||||
public:
|
||||
|
||||
/** Construct a PolytopeIntersector using speified polytope in MODEL coordinates.*/
|
||||
/// dimension enum to specify primitive types to check.
|
||||
enum {
|
||||
DimZero = (1<<0), ///< check for points
|
||||
DimOne = (1<<1), ///< check for lines
|
||||
DimTwo = (1<<2), ///< check for triangles, quad
|
||||
AllDims = (DimZero | DimOne | DimTwo)
|
||||
};
|
||||
|
||||
/** Construct a PolytopeIntersector using specified polytope in MODEL coordinates.*/
|
||||
PolytopeIntersector(const osg::Polytope& polytope);
|
||||
|
||||
/** Construct a PolytopeIntersector using speified polytope in specified coordinate frame.*/
|
||||
|
||||
/** Construct a PolytopeIntersector using specified polytope in specified coordinate frame.*/
|
||||
PolytopeIntersector(CoordinateFrame cf, const osg::Polytope& polytope);
|
||||
|
||||
/** Convinience constructor for supporting picking in WINDOW, or PROJECTION coorindates
|
||||
|
||||
/** Convenience constructor for supporting picking in WINDOW, or PROJECTION coordinates
|
||||
* In WINDOW coordinates (clip space cube) creates a five sided polytope box that has a front face at 0.0 and sides around box xMin, yMin, xMax, yMax.
|
||||
* In PROJECTION coordinates (clip space cube) creates a five sided polytope box that has a front face at -1 and sides around box xMin, yMin, xMax, yMax.
|
||||
* In VIEW and MODEL coordinates (clip space cube) creates a five sided polytope box that has a front face at 0.0 and sides around box xMin, yMin, xMax, yMax.*/
|
||||
@@ -40,16 +47,29 @@ class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
|
||||
struct Intersection
|
||||
{
|
||||
Intersection() {}
|
||||
|
||||
|
||||
bool operator < (const Intersection& rhs) const
|
||||
{
|
||||
if (distance < rhs.distance) return true;
|
||||
if (rhs.distance < distance) return false;
|
||||
if (primitiveIndex < rhs.primitiveIndex) return true;
|
||||
if (rhs.primitiveIndex < primitiveIndex) return false;
|
||||
if (nodePath < rhs.nodePath) return true;
|
||||
if (rhs.nodePath < nodePath ) return false;
|
||||
return (drawable < rhs.drawable);
|
||||
}
|
||||
|
||||
enum { MaxNumIntesectionPoints=6 };
|
||||
|
||||
double distance; ///< distance from reference plane
|
||||
double maxDistance; ///< maximum distance of intersection points from reference plane
|
||||
osg::NodePath nodePath;
|
||||
osg::ref_ptr<osg::Drawable> drawable;
|
||||
osg::ref_ptr<osg::RefMatrix> matrix;
|
||||
osg::Vec3 localIntersectionPoint; ///< center of all intersection points
|
||||
unsigned int numIntersectionPoints;
|
||||
osg::Vec3 intersectionPoints[MaxNumIntesectionPoints];
|
||||
unsigned int primitiveIndex; ///< primitive index
|
||||
};
|
||||
|
||||
typedef std::set<Intersection> Intersections;
|
||||
@@ -60,6 +80,23 @@ class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
|
||||
|
||||
inline Intersection getFirstIntersection() { Intersections& intersections = getIntersections(); return intersections.empty() ? Intersection() : *(intersections.begin()); }
|
||||
|
||||
inline unsigned int getDimensionMask() const { return _dimensionMask; }
|
||||
|
||||
/** set the dimension mask.
|
||||
* As polytope-triangle and polytope-quad intersections are expensive to compute
|
||||
* it is possible to turn them off by calling setDimensionMask( DimZero | DimOne )
|
||||
*/
|
||||
inline void setDimensionMask(unsigned int dimensionMask) { _dimensionMask = dimensionMask; }
|
||||
|
||||
inline const osg::Plane& getReferencePlane() const { return _referencePlane; }
|
||||
|
||||
/** set the plane used to sort the intersections.
|
||||
* The intersections are sorted by the distance of the localIntersectionPoint
|
||||
* and the reference plane. The default for the reference plane is the
|
||||
* last plane of the polytope.
|
||||
*/
|
||||
inline void setReferencePlane(const osg::Plane& plane) { _referencePlane = plane; }
|
||||
|
||||
public:
|
||||
|
||||
virtual Intersector* clone(osgUtil::IntersectionVisitor& iv);
|
||||
@@ -79,7 +116,10 @@ class OSGUTIL_EXPORT PolytopeIntersector : public Intersector
|
||||
PolytopeIntersector* _parent;
|
||||
|
||||
osg::Polytope _polytope;
|
||||
|
||||
|
||||
unsigned int _dimensionMask; ///< mask which dimensions should be checked
|
||||
osg::Plane _referencePlane; ///< plane to use for sorting intersections
|
||||
|
||||
Intersections _intersections;
|
||||
|
||||
};
|
||||
|
||||
@@ -22,266 +22,381 @@
|
||||
using namespace osgUtil;
|
||||
|
||||
|
||||
|
||||
class PolytopePrimitiveIntersector {
|
||||
public:
|
||||
#ifdef OSG_USE_DOUBLE_PLANE
|
||||
typedef double value_type;
|
||||
typedef osg::Vec3d Vec3_type;
|
||||
#else
|
||||
namespace PolytopeIntersectorUtils
|
||||
{
|
||||
#ifdef OSG_USE_FLOAT_PLANE
|
||||
typedef float value_type;
|
||||
typedef osg::Vec3f Vec3_type;
|
||||
#else
|
||||
typedef double value_type;
|
||||
typedef osg::Vec3d Vec3_type;
|
||||
#endif
|
||||
|
||||
typedef osg::Polytope::ClippingMask PlaneMask;
|
||||
typedef osg::Polytope::PlaneList PlaneList;
|
||||
typedef std::vector<std::pair<PlaneMask,Vec3_type> > 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<PlanesLine> LinesList;
|
||||
|
||||
PolytopePrimitiveIntersector() :
|
||||
numPoints(0),
|
||||
numLines(0),
|
||||
numTriangles(0),
|
||||
numQuads(0),
|
||||
_numIntersections(0) {}
|
||||
class PolytopeIntersection {
|
||||
public:
|
||||
enum { MaxNumIntesections = PolytopeIntersector::Intersection::MaxNumIntesectionPoints };
|
||||
|
||||
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;
|
||||
PolytopeIntersection(unsigned int index, const CandList_t& cands, const osg::Plane &referencePlane) :
|
||||
_maxDistance(-1.0), _index(index-1), _numPoints(0)
|
||||
{
|
||||
Vec3_type center;
|
||||
for (CandList_t::const_iterator it=cands.begin(); it!=cands.end(); ++it)
|
||||
{
|
||||
PlaneMask mask = it->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;
|
||||
|
||||
_points[_numPoints++] = it->second;
|
||||
center += it->second;
|
||||
value_type distance = referencePlane.distance(it->second);
|
||||
if (distance > _maxDistance) _maxDistance = distance;
|
||||
if (_numPoints==MaxNumIntesections) break;
|
||||
}
|
||||
center /= value_type(_numPoints);
|
||||
_distance = referencePlane.distance( center );
|
||||
}
|
||||
bool operator<(const PolytopeIntersection& rhs) const { return _distance < rhs._distance; }
|
||||
|
||||
value_type _distance; ///< distance from reference plane
|
||||
value_type _maxDistance; ///< maximum distance of intersection points from reference plane
|
||||
unsigned int _index; ///< primitive index
|
||||
unsigned int _numPoints;
|
||||
osg::Vec3 _points[MaxNumIntesections];
|
||||
}; // class PolytopeIntersection
|
||||
|
||||
typedef std::vector<PolytopeIntersection> Intersections;
|
||||
|
||||
|
||||
class PolytopePrimitiveIntersector {
|
||||
public:
|
||||
|
||||
typedef osg::Polytope::PlaneList PlaneList;
|
||||
|
||||
/// 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<PlanesLine> LinesList;
|
||||
|
||||
PolytopePrimitiveIntersector() :
|
||||
_index(0),
|
||||
_dimensionMask( PolytopeIntersector::AllDims ),
|
||||
_candidates(20) {}
|
||||
|
||||
void addIntersection(unsigned int index, const CandList_t& cands) {
|
||||
intersections.push_back( PolytopeIntersection( index, cands, _referencePlane ) );
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
PlaneMask selector_mask = 0x1;
|
||||
unsigned int numCands=_candidates.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=_candidates.begin(); pointIt!=_candidates.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;
|
||||
}
|
||||
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
|
||||
// handle points
|
||||
void operator()(const Vec3_type v1, bool treatVertexDataAsTemporary)
|
||||
{
|
||||
++_index;
|
||||
if ((_dimensionMask & PolytopeIntersector::DimZero) == 0) return;
|
||||
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
|
||||
}
|
||||
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))) ) );
|
||||
_candidates.clear();
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v1));
|
||||
addIntersection(_index, _candidates);
|
||||
}
|
||||
|
||||
// handle lines
|
||||
void operator()(const Vec3_type v1, const Vec3_type v2, bool treatVertexDataAsTemporary)
|
||||
{
|
||||
++_index;
|
||||
if ((_dimensionMask & PolytopeIntersector::DimOne) == 0) return;
|
||||
|
||||
PlaneMask selector_mask = 0x1;
|
||||
PlaneMask inside_mask = 0x0;
|
||||
_candidates.clear();
|
||||
|
||||
bool v1Inside = true;
|
||||
bool v2Inside = true;
|
||||
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 (d1IsNegative) v1Inside = false;
|
||||
if (d2IsNegative) v2Inside = false;
|
||||
if (d1==0.0f)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, v1) );
|
||||
}
|
||||
else if (d2==0.0f)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, v2) );
|
||||
}
|
||||
else if (d1IsNegative && !d2IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1-(v2-v1)*(d1/(-d1+d2))) ) );
|
||||
} else if (!d1IsNegative && d2IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1+(v2-v1)*(d1/(d1-d2))) ) );
|
||||
}
|
||||
|
||||
}
|
||||
if (inside_mask==_plane_mask)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v1) );
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v2) );
|
||||
addIntersection(_index, _candidates);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int numCands=checkCandidatePoints(inside_mask);
|
||||
if (numCands>0)
|
||||
{
|
||||
if (v1Inside) _candidates.push_back( CandList_t::value_type(_plane_mask, v1) );
|
||||
if (v2Inside) _candidates.push_back( CandList_t::value_type(_plane_mask, v2) );
|
||||
addIntersection(_index, _candidates);
|
||||
}
|
||||
|
||||
}
|
||||
if (inside_mask==_plane_mask) {
|
||||
++_numIntersections;
|
||||
return;
|
||||
|
||||
// handle triangles
|
||||
void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, bool treatVertexDataAsTemporary)
|
||||
{
|
||||
++_index;
|
||||
if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0) return;
|
||||
|
||||
PlaneMask selector_mask = 0x1;
|
||||
PlaneMask inside_mask = 0x0;
|
||||
_candidates.clear();
|
||||
|
||||
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)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, v1) );
|
||||
}
|
||||
else if (d2==0.0f)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, v2) );
|
||||
}
|
||||
else if (d1IsNegative && !d2IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1-(v2-v1)*(d1/(-d1+d2))) ) );
|
||||
}
|
||||
else if (!d1IsNegative && d2IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1+(v2-v1)*(d1/(d1-d2))) ) );
|
||||
}
|
||||
|
||||
// edge v1-v3 intersects
|
||||
if (d3==0.0f)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, v3) );
|
||||
}
|
||||
else if (d1IsNegative && !d3IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1-(v3-v1)*(d1/(-d1+d3))) ) );
|
||||
}
|
||||
else if (!d1IsNegative && d3IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v1+(v3-v1)*(d1/(d1-d3))) ) );
|
||||
}
|
||||
|
||||
// edge v2-v3 intersects
|
||||
if (d2IsNegative && !d3IsNegative)
|
||||
{
|
||||
_candidates.push_back( CandList_t::value_type(selector_mask, (v2-(v3-v2)*(d2/(-d2+d3))) ) );
|
||||
} else if (!d2IsNegative && d3IsNegative)
|
||||
{
|
||||
_candidates.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
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v1) );
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v2) );
|
||||
_candidates.push_back( CandList_t::value_type(_plane_mask, v3) );
|
||||
addIntersection(_index, _candidates);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_candidates.empty() && _planes.size()<3) return;
|
||||
|
||||
unsigned int numCands=checkCandidatePoints(inside_mask);
|
||||
|
||||
if (numCands>0)
|
||||
{
|
||||
addIntersection(_index, _candidates);
|
||||
return;
|
||||
}
|
||||
|
||||
// handle case where the polytope goes through the triangle
|
||||
// without containing any point of it
|
||||
|
||||
LinesList& lines=getPolytopeLines();
|
||||
_candidates.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)<eps()) continue;
|
||||
|
||||
const value_type f=1.0f/a;
|
||||
const Vec3_type s=(line.pos-v1);
|
||||
const value_type u=f*(s*p);
|
||||
if (u<0.0f || u>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);
|
||||
|
||||
_candidates.push_back(CandList_t::value_type(line.mask, line.pos+line.dir*t));
|
||||
}
|
||||
|
||||
numCands=checkCandidatePoints(inside_mask);
|
||||
|
||||
if (numCands>0)
|
||||
{
|
||||
addIntersection(_index, _candidates);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
unsigned int numCands=checkCandidatePoints(inside_mask, cand);
|
||||
if (numCands>0) {
|
||||
++_numIntersections;
|
||||
/// handle quads
|
||||
void operator()(const Vec3_type v1, const Vec3_type v2, const Vec3_type v3, const Vec3_type v4, bool treatVertexDataAsTemporary)
|
||||
{
|
||||
if ((_dimensionMask & PolytopeIntersector::DimTwo) == 0)
|
||||
{
|
||||
++_index;
|
||||
return;
|
||||
}
|
||||
this->operator()(v1,v2,v3,treatVertexDataAsTemporary);
|
||||
|
||||
--_index;
|
||||
|
||||
this->operator()(v1,v3,v4,treatVertexDataAsTemporary);
|
||||
}
|
||||
|
||||
}
|
||||
void setDimensionMask(unsigned int dimensionMask) { _dimensionMask = dimensionMask; }
|
||||
|
||||
// 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
|
||||
void setPolytope(osg::Polytope& polytope, osg::Plane& referencePlane)
|
||||
{
|
||||
_referencePlane = referencePlane;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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))) ) );
|
||||
}
|
||||
_plane_mask = 0x0;
|
||||
_planes.clear();
|
||||
_planes.reserve(numActivePlanes);
|
||||
_lines.clear();
|
||||
|
||||
// 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))) ) );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (_plane_mask==inside_mask) { // triangle lies inside of all planes
|
||||
++_numIntersections;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cand.empty() && _planes.size()<3) {
|
||||
return;
|
||||
}
|
||||
/// get boundary lines of polytope
|
||||
LinesList& getPolytopeLines()
|
||||
{
|
||||
if (!_lines.empty()) return _lines;
|
||||
|
||||
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)<eps()) continue;
|
||||
const value_type f=1.0f/a;
|
||||
const Vec3_type s=(line.pos-v1);
|
||||
const value_type u=f*(s*p);
|
||||
if (u<0.0f || u>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 ) {
|
||||
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
|
||||
@@ -298,25 +413,26 @@ public:
|
||||
const Vec3_type linePoint=point1+searchDirection*seachDist;
|
||||
_lines.push_back(PlanesLine(selector_mask|sub_selector_mask, linePoint, lineDirection));
|
||||
}
|
||||
}
|
||||
return _lines;
|
||||
}
|
||||
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 getNumPlanes() const { return _planes.size(); }
|
||||
|
||||
unsigned int numPoints;
|
||||
unsigned int numLines;
|
||||
unsigned int numTriangles;
|
||||
unsigned int numQuads;
|
||||
Intersections intersections;
|
||||
osg::Plane _referencePlane;
|
||||
|
||||
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;
|
||||
};
|
||||
unsigned int _index;
|
||||
|
||||
private:
|
||||
unsigned int _dimensionMask;
|
||||
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
|
||||
CandList_t _candidates;
|
||||
}; // class PolytopePrimitiveIntersector
|
||||
|
||||
} // namespace PolytopeIntersectorUtils
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -325,20 +441,31 @@ private:
|
||||
//
|
||||
PolytopeIntersector::PolytopeIntersector(const osg::Polytope& polytope):
|
||||
_parent(0),
|
||||
_polytope(polytope)
|
||||
_polytope(polytope),
|
||||
_dimensionMask( AllDims )
|
||||
{
|
||||
if (!_polytope.getPlaneList().empty())
|
||||
{
|
||||
_referencePlane = _polytope.getPlaneList().back();
|
||||
}
|
||||
}
|
||||
|
||||
PolytopeIntersector::PolytopeIntersector(CoordinateFrame cf, const osg::Polytope& polytope):
|
||||
Intersector(cf),
|
||||
_parent(0),
|
||||
_polytope(polytope)
|
||||
_polytope(polytope),
|
||||
_dimensionMask( AllDims )
|
||||
{
|
||||
if (!_polytope.getPlaneList().empty())
|
||||
{
|
||||
_referencePlane = _polytope.getPlaneList().back();
|
||||
}
|
||||
}
|
||||
|
||||
PolytopeIntersector::PolytopeIntersector(CoordinateFrame cf, double xMin, double yMin, double xMax, double yMax):
|
||||
Intersector(cf),
|
||||
_parent(0)
|
||||
_parent(0),
|
||||
_dimensionMask( AllDims )
|
||||
{
|
||||
double zNear = 0.0;
|
||||
switch(cf)
|
||||
@@ -354,6 +481,8 @@ PolytopeIntersector::PolytopeIntersector(CoordinateFrame cf, double xMin, double
|
||||
_polytope.add(osg::Plane(0.0, 1.0, 0.0,-yMin));
|
||||
_polytope.add(osg::Plane(0.0,-1.0,0.0, yMax));
|
||||
_polytope.add(osg::Plane(0.0,0.0,1.0, zNear));
|
||||
|
||||
_referencePlane = _polytope.getPlaneList().back();
|
||||
}
|
||||
|
||||
Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
|
||||
@@ -362,6 +491,8 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
|
||||
{
|
||||
osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(_polytope);
|
||||
pi->_parent = this;
|
||||
pi->_dimensionMask = this->_dimensionMask;
|
||||
pi->_referencePlane = this->_referencePlane;
|
||||
return pi.release();
|
||||
}
|
||||
|
||||
@@ -395,6 +526,9 @@ Intersector* PolytopeIntersector::clone(osgUtil::IntersectionVisitor& iv)
|
||||
|
||||
osg::ref_ptr<PolytopeIntersector> pi = new PolytopeIntersector(transformedPolytope);
|
||||
pi->_parent = this;
|
||||
pi->_dimensionMask = this->_dimensionMask;
|
||||
pi->_referencePlane = this->_referencePlane;
|
||||
pi->_referencePlane.transformProvidingInverse(matrix);
|
||||
return pi.release();
|
||||
}
|
||||
|
||||
@@ -414,25 +548,43 @@ void PolytopeIntersector::intersect(osgUtil::IntersectionVisitor& iv, osg::Drawa
|
||||
{
|
||||
if ( !_polytope.contains( drawable->getBound() ) ) return;
|
||||
|
||||
osg::TemplatePrimitiveFunctor<PolytopePrimitiveIntersector> func;
|
||||
func.setPolytope(_polytope);
|
||||
osg::TemplatePrimitiveFunctor<PolytopeIntersectorUtils::PolytopePrimitiveIntersector> func;
|
||||
func.setPolytope( _polytope, _referencePlane );
|
||||
func.setDimensionMask( _dimensionMask );
|
||||
|
||||
drawable->accept(func);
|
||||
|
||||
if (func.getNumIntersections()==0) {
|
||||
return;
|
||||
if (func.intersections.empty()) return;
|
||||
|
||||
|
||||
for(PolytopeIntersectorUtils::Intersections::const_iterator it=func.intersections.begin();
|
||||
it!=func.intersections.end();
|
||||
++it)
|
||||
{
|
||||
const PolytopeIntersectorUtils::PolytopeIntersection& intersection = *it;
|
||||
|
||||
Intersection hit;
|
||||
hit.distance = intersection._distance;
|
||||
hit.maxDistance = intersection._maxDistance;
|
||||
hit.primitiveIndex = intersection._index;
|
||||
hit.nodePath = iv.getNodePath();
|
||||
hit.drawable = drawable;
|
||||
hit.matrix = iv.getModelMatrix();
|
||||
|
||||
osg::Vec3 center;
|
||||
for (unsigned int i=0; i<intersection._numPoints; ++i)
|
||||
{
|
||||
center += intersection._points[i];
|
||||
}
|
||||
center /= float(intersection._numPoints);
|
||||
hit.localIntersectionPoint = center;
|
||||
|
||||
hit.numIntersectionPoints = intersection._numPoints;
|
||||
std::copy(&intersection._points[0], &intersection._points[intersection._numPoints],
|
||||
&hit.intersectionPoints[0]);
|
||||
|
||||
insertIntersection(hit);
|
||||
}
|
||||
|
||||
osg::notify(osg::INFO) << func.getNumIntersections() << " intersections with "
|
||||
<< func.numPoints<<" points, "<< func.numLines
|
||||
<<" lines, "<< func.numTriangles
|
||||
<<" triangles, "<<func.numQuads<<" quads"<<std::endl;
|
||||
|
||||
Intersection hit;
|
||||
hit.nodePath = iv.getNodePath();
|
||||
hit.drawable = drawable;
|
||||
|
||||
insertIntersection(hit);
|
||||
}
|
||||
|
||||
|
||||
@@ -442,3 +594,4 @@ void PolytopeIntersector::reset()
|
||||
|
||||
_intersections.clear();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user