Commit 06e27a0b authored by Jan Möbius's avatar Jan Möbius
Browse files

Merge branch 'bsp-fix-attempt' into 'master'

ACG BSP Tree: Support OpenVolumeMesh based triangle meshes and implement ball intersection (new PR)

See merge request !172
parents 1a23ec78 c36d3857
Pipeline #3367 passed with stage
in 56 minutes and 17 seconds
......@@ -63,7 +63,7 @@
#include "BSPImplT.hh"
#include <cfloat>
#include <cmath>
//== CLASS DEFINITION =========================================================
#include <vector>
......@@ -180,6 +180,16 @@ nearestRaycollision(const Point& _p, const Point& _r) const {
return RayCollision(data.hit_handles);
}
template<class BSPCore>
template<class Callback>
void
BSPImplT<BSPCore>::
intersectBall(const Point &_c, Scalar _r, Callback _callback) const
{
_intersect_ball(*(this->root_), _c, _r, _callback);
}
//-----------------------------------------------------------------------------
......@@ -309,8 +319,42 @@ _raycollision_nearest_directional(Node* _node, RayCollisionData& _data) const
if ( second_node && ACG::Geometry::axisAlignedBBIntersection( _data.ref, _data.ray, second_node->bb_min, second_node->bb_max, tmin, tmax) && (tmin < dist) ) {
_raycollision_nearest_directional(second_node, _data);
}
}
}
}
template<class BSPCore>
template<class Callback>
void BSPImplT<BSPCore>::
_intersect_ball(const Node &_node,
const Point &_c,
Scalar _r,
Callback _callback) const
{
// terminal node
if (!_node.left_child_)
{
const double r_sqr = _r * _r;
for (const auto &fh: _node) {
const double dist = this->traits_.sqrdist(fh, _c);
if (dist < r_sqr) {
_callback(fh);
}
}
}
else // non-terminal node
{
const Scalar dist = _node.plane_.distance(_c);
const Node &left = *_node.left_child_;
const Node &right = *_node.right_child_;
if (dist > -_r){
_intersect_ball(left, _c, _r, _callback);
}
if (dist < _r) {
_intersect_ball(right, _c, _r, _callback);
}
}
}
//=============================================================================
......@@ -144,7 +144,21 @@ public: //---------------------------------------------------------------------
* @param _r Ray direction
* @return Collision information
*/
RayCollision nearestRaycollision(const Point& _p, const Point& _r) const;
RayCollision nearestRaycollision(const Point& _p, const Point& _r) const;
/** \brief intersect mesh with open ball
*
* All triangles that have at least one vertex (!) inside the ball are given to the Callback,
* triangles which have no vertex inside the ball but intersect it MAY be returned. (TODO)
* Each triangle can be returned up to three times, make sure to handle this, e.g.
* by putting the values into an std::(unordered_)set.
*
* @param _c Center of the ball
* @param _r Radius of the ball
* @param _callback Callable that accepts Handle or const Handle&, e.g. (const Handle &h) -> void
*/
template<class Callback>
void intersectBall(const Point & _c, Scalar _r, Callback _callback) const;
private: //---------------------------------------------------------------------
......@@ -188,7 +202,10 @@ private: //---------------------------------------------------------------------
*/
void _raycollision_directional(Node* _node, RayCollisionData& _data) const;
void _raycollision_nearest_directional(Node* _node, RayCollisionData& _data) const;
void _raycollision_nearest_directional(Node* _node, RayCollisionData& _data) const;
template<class Callback>
void _intersect_ball(const Node& _node, const Point & _c, Scalar _r, Callback _callback) const;
template<typename T,typename U>
struct less_pair_second: public std::binary_function<T,U,bool> {
......
......@@ -68,16 +68,17 @@
//== CLASS DEFINITION =========================================================
// Node of the tree: contains parent, children and splitting plane
template <class Mesh>
template <class BSPTraits>
struct TreeNode
{
typedef typename Mesh::FaceHandle Handle;
typedef typename Mesh::Point Point;
typedef typename Mesh::VertexHandle VertexHandle;
typedef std::vector<Handle> Handles;
typedef typename Handles::iterator HandleIter;
typedef typename Point::value_type Scalar;
typedef ACG::Geometry::PlaneT<Scalar> Plane;
typedef typename BSPTraits::Handle Handle;
typedef typename BSPTraits::Point Point;
typedef typename BSPTraits::VertexHandle VertexHandle;
typedef std::vector<Handle> Handles;
typedef typename Handles::iterator HandleIter;
typedef typename Handles::const_iterator HandleConstIter;
typedef typename Point::value_type Scalar;
typedef ACG::Geometry::PlaneT<Scalar> Plane;
TreeNode(const Handles& _handles, TreeNode* _parent)
: handles_(_handles),
......@@ -99,10 +100,19 @@ struct TreeNode
HandleIter begin() {
return handles_.begin();
}
HandleIter end() {
return handles_.end();
}
HandleConstIter begin() const {
return handles_.begin();
}
HandleConstIter end() const {
return handles_.end();
}
size_t size() const {
return handles_.size();
}
......@@ -194,10 +204,10 @@ struct TreeNode
};
template<class Mesh>
std::ostream &operator<< (std::ostream &stream, const TreeNode<Mesh> &node) {
template<class BSPTraits>
std::ostream &operator<< (std::ostream &stream, const TreeNode<BSPTraits> &node) {
stream << "[TreeNode instance. Handles: ";
for (typename std::vector<typename TreeNode<Mesh>::Handle>::const_iterator it = node.handles_.begin(), it_end = node.handles_.end();
for (typename TreeNode<BSPTraits>::Handles::const_iterator it = node.handles_.begin(), it_end = node.handles_.end();
it != it_end; ++it) {
stream << it->idx();
if (it < it_end-1) stream << ", ";
......
......@@ -66,8 +66,8 @@
#include "TriangleBSPCoreT.hh"
#include "BSPImplT.hh"
//== CLASS DEFINITION =========================================================
#include <list>
//== CLASS DEFINITION =========================================================
template <class BSPTraits>
class TriangleBSPT : public BSPImplT< TriangleBSPCoreT<BSPTraits> >
......@@ -81,129 +81,144 @@ public:
//== CLASS DEFINITION =========================================================
template <class Mesh>
class OpenMeshTriangleBSPTraits
template <class Mesh, class SpecificTraits>
class OVMOMCommonTriangleBSPTraits : public SpecificTraits
{
public:
typedef typename Mesh::Scalar Scalar;
typedef typename Mesh::Point Point;
typedef typename Mesh::FaceHandle Handle;
typedef std::vector<Handle> Handles;
typedef typename Handles::iterator HandleIter;
typedef TreeNode<Mesh> Node;
typedef typename SpecificTraits::Point Point;
typedef typename SpecificTraits::Handle Handle;
typedef typename Point::value_type Scalar;
typedef std::vector<Handle> Handles;
typedef typename Handles::iterator HandleIter;
typedef TreeNode<SpecificTraits> Node;
OpenMeshTriangleBSPTraits(const Mesh& _mesh) : mesh_(_mesh) {}
OVMOMCommonTriangleBSPTraits(const Mesh& _mesh) : SpecificTraits(_mesh) {}
/// Returns the points belonging to the face handle _h
inline void points(const Handle _h, Point& _p0, Point& _p1, Point& _p2) const
{
typename Mesh::CFVIter fv_it(mesh_.cfv_iter(_h));
_p0 = mesh_.point(*fv_it);
++fv_it;
_p1 = mesh_.point(*fv_it);
++fv_it;
_p2 = mesh_.point(*fv_it);
}
Scalar sqrdist(const Handle _h, const Point& _p) const
{
Point p0, p1, p2, q;
points(_h, p0, p1, p2);
return ACG::Geometry::distPointTriangleSquaredStable(_p, p0, p1, p2, q);
}
void calculateBoundingBox(Node* _node, Point& median, int& axis)
{
//determine splitting axis
HandleIter it_h;
Point p0, p1, p2, bb_min, bb_max;
bb_min.vectorize(std::numeric_limits<typename Point::value_type>::infinity());
bb_max.vectorize(-std::numeric_limits<typename Point::value_type>::infinity());
std::list<Point> vertices;
for (it_h = _node->begin(); it_h != _node->end(); ++it_h) {
points(*it_h, p0, p1, p2);
/*
bb_min.minimize(p0);
bb_min.minimize(p1);
bb_min.minimize(p2);
bb_max.maximize(p0);
bb_max.maximize(p1);
bb_max.maximize(p2);*/
vertices.push_back(p0);
vertices.push_back(p1);
vertices.push_back(p2);
}
bb_min = _node->bb_min;
bb_max = _node->bb_max;
// split longest side of bounding box
Point bb = bb_max - bb_min;
Scalar length = bb[0];
axis = 0;
if (bb[1] > length)
length = bb[(axis = 1)];
if (bb[2] > length)
length = bb[(axis = 2)];
//calculate the median value in axis-direction
switch (axis) {
case 0:
vertices.sort(x_sort());
break;
case 1:
vertices.sort(y_sort());
break;
case 2:
vertices.sort(z_sort());
break;
Scalar sqrdist(const Handle _h, const Point& _p) const
{
Point p0, p1, p2, q;
this->points(_h, p0, p1, p2);
return ACG::Geometry::distPointTriangleSquaredStable(_p, p0, p1, p2, q);
}
vertices.unique(); ///todo: does this work with Points?!
size_t size = vertices.size();
typename std::list<Point>::iterator it_v;
it_v = vertices.begin();
std::advance(it_v, size / 2);
median = *it_v;
void calculateBoundingBox(Node* _node, Point& median, int& axis)
{
//determine splitting axis
HandleIter it_h;
Point p0, p1, p2, bb_min, bb_max;
bb_min.vectorize(std::numeric_limits<typename Point::value_type>::infinity());
bb_max.vectorize(-std::numeric_limits<typename Point::value_type>::infinity());
std::list<Point> vertices;
for (it_h = _node->begin(); it_h != _node->end(); ++it_h) {
this->points(*it_h, p0, p1, p2);
/*
bb_min.minimize(p0);
bb_min.minimize(p1);
bb_min.minimize(p2);
bb_max.maximize(p0);
bb_max.maximize(p1);
bb_max.maximize(p2);*/
vertices.push_back(p0);
vertices.push_back(p1);
vertices.push_back(p2);
}
bb_min = _node->bb_min;
bb_max = _node->bb_max;
// split longest side of bounding box
Point bb = bb_max - bb_min;
Scalar length = bb[0];
axis = 0;
if (bb[1] > length)
length = bb[(axis = 1)];
if (bb[2] > length)
length = bb[(axis = 2)];
//calculate the median value in axis-direction
switch (axis) {
case 0:
vertices.sort(x_sort());
break;
case 1:
vertices.sort(y_sort());
break;
case 2:
vertices.sort(z_sort());
break;
}
vertices.unique(); ///todo: does this work with Points?!
size_t size = vertices.size();
typename std::list<Point>::iterator it_v;
it_v = vertices.begin();
std::advance(it_v, size / 2);
median = *it_v;
}
}
void calculateBoundingBoxRoot(Node* _node)
{
HandleIter it;
Point p0, p1, p2, bb_min, bb_max;
bb_min.vectorize(FLT_MAX);
bb_max.vectorize(-FLT_MAX);
for (it = _node->begin(); it != _node->end(); ++it) {
points(*it, p0, p1, p2);
bb_min.minimize(p0);
bb_min.minimize(p1);
bb_min.minimize(p2);
bb_max.maximize(p0);
bb_max.maximize(p1);
bb_max.maximize(p2);
void calculateBoundingBoxRoot(Node* _node)
{
HandleIter it;
Point p0, p1, p2, bb_min, bb_max;
bb_min.vectorize(FLT_MAX);
bb_max.vectorize(-FLT_MAX);
for (it = _node->begin(); it != _node->end(); ++it) {
this->points(*it, p0, p1, p2);
bb_min.minimize(p0);
bb_min.minimize(p1);
bb_min.minimize(p2);
bb_max.maximize(p0);
bb_max.maximize(p1);
bb_max.maximize(p2);
}
_node->bb_min = bb_min;
_node->bb_max = bb_max;
}
_node->bb_min = bb_min;
_node->bb_max = bb_max;
}
private:
const Mesh& mesh_;
//functors for sorting in different directions
struct x_sort { bool operator()(const Point& first, const Point& second) { return (first[0] < second[0]); } };
struct y_sort { bool operator()(const Point& first, const Point& second) { return (first[1] < second[1]); } };
struct z_sort { bool operator()(const Point& first, const Point& second) { return (first[2] < second[2]); } };
//functors for sorting in different directions
struct x_sort { bool operator()(const Point& first, const Point& second) { return (first[0] < second[0]); } };
struct y_sort { bool operator()(const Point& first, const Point& second) { return (first[1] < second[1]); } };
struct z_sort { bool operator()(const Point& first, const Point& second) { return (first[2] < second[2]); } };
};
//== CLASS DEFINITION =========================================================
template <class Mesh>
class OMSpecificTriangleBSPTraits
{
public:
typedef typename Mesh::Point Point;
typedef typename Mesh::FaceHandle Handle;
typedef typename Mesh::VertexHandle VertexHandle;
OMSpecificTriangleBSPTraits(const Mesh& _mesh) : mesh_(_mesh) {}
/// Returns the points belonging to the face handle _h
inline void points(const Handle &_h, Point& _p0, Point& _p1, Point& _p2) const
{
const auto &mesh = this->mesh_;
typename Mesh::CFVIter fv_it(mesh.cfv_iter(_h));
_p0 = mesh.point(*fv_it);
++fv_it;
_p1 = mesh.point(*fv_it);
++fv_it;
_p2 = mesh.point(*fv_it);
}
protected:
const Mesh& mesh_;
};
template<class Mesh>
using OpenMeshTriangleBSPTraits = OVMOMCommonTriangleBSPTraits<Mesh, OMSpecificTriangleBSPTraits<Mesh>>;
//== CLASS DEFINITION =========================================================
template <class Mesh>
class OpenMeshTriangleBSPT
class OpenMeshTriangleBSPT
: public TriangleBSPT<OpenMeshTriangleBSPTraits<Mesh> >
{
public:
......@@ -211,9 +226,65 @@ public:
typedef TriangleBSPT<Traits> Base;
typedef typename Traits::Scalar Scalar;
OpenMeshTriangleBSPT(const Mesh& _mesh,
const Scalar& _infinity = std::numeric_limits<Scalar>::infinity()) : Base(Traits(_mesh), _infinity) {}
const Scalar& _infinity = std::numeric_limits<Scalar>::infinity())
: Base(Traits(_mesh), _infinity) {}
};
#ifdef ENABLE_OPENVOLUMEMESH
namespace OpenVolumeMesh {
class VertexHandle;
class FaceHandle;
}
//== CLASS DEFINITION =========================================================
// Make sure all faces of the mesh have valence 3.
template <class Mesh>
class OVMSpecificTriangleBSPTraits
{
public:
typedef typename Mesh::PointT Point;
typedef OpenVolumeMesh::FaceHandle Handle;
typedef OpenVolumeMesh::VertexHandle VertexHandle;
OVMSpecificTriangleBSPTraits(const Mesh& _mesh) : mesh_(_mesh) {}
/// Returns the points belonging to the face handle _h
inline void points(const Handle &_h, Point& _p0, Point& _p1, Point& _p2) const
{
const auto &mesh = this->mesh_;
assert(mesh.valence(_h) == 3);
auto hfv_it (mesh.hfv_iter(mesh.halfface_handle(_h, 0)));
_p0 = mesh.vertex(*hfv_it++);
_p1 = mesh.vertex(*hfv_it++);
_p2 = mesh.vertex(*hfv_it++);
}
protected:
const Mesh& mesh_;
};
template<class Mesh>
using OpenVolumeMeshTriangleBSPTraits = OVMOMCommonTriangleBSPTraits<Mesh, OVMSpecificTriangleBSPTraits<Mesh>>;
//== CLASS DEFINITION =========================================================
template <class Mesh>
class OpenVolumeMeshTriangleBSPT
: public TriangleBSPT<OpenVolumeMeshTriangleBSPTraits<Mesh> >
{
public:
typedef OpenVolumeMeshTriangleBSPTraits<Mesh> Traits;
typedef TriangleBSPT<Traits> Base;
typedef typename Traits::Scalar Scalar;
OpenVolumeMeshTriangleBSPT(const Mesh& _mesh,
const Scalar& _infinity = std::numeric_limits<Scalar>::infinity())
: Base(Traits(_mesh), _infinity) {}
};
#endif // ENABLE_OPENVOLUMEMESH
//=============================================================================
#endif // MB_TRIANGLEBSP_HH defined
//=============================================================================
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment