use a traversal traits instead of a pseudo model of AABBTraits

This commit is contained in:
Sébastien Loriot 2018-08-24 10:51:21 +02:00
parent d7e7c74782
commit df15af614d
4 changed files with 284 additions and 199 deletions

View File

@ -1,4 +1,3 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
@ -19,6 +18,7 @@
//
//
// Author(s) : Maxime Gimeno
// Sebastien Loriot
//
#ifndef CGAL_AABB_DO_INTERSECT_TRANSFORM_TRAITS_H
@ -38,204 +38,263 @@
#include <CGAL/Aff_transformation_3.h>
#include <boost/mpl/if.hpp>
/// \file AABB_do_intersect_transform_traits.h
namespace CGAL {
template<typename Kernel, typename AABBPrimitive,
typename SUPPORTS_ROTATION = CGAL::Tag_true>
class AABB_do_intersect_transform_traits:
public AABB_traits<Kernel, AABBPrimitive>
template<typename AABBTraits, typename Kernel, class SUPPORTS_ROTATION>
class Traversal_traits_with_transformation_helper
{
mutable Aff_transformation_3<Kernel> m_transfo;
mutable bool has_rotation;
typedef AABB_traits<Kernel, AABBPrimitive> BaseTraits;
typedef AABB_do_intersect_transform_traits<Kernel, AABBPrimitive, SUPPORTS_ROTATION> Self;
void set_transformation(const Aff_transformation_3<Kernel>& trans, CGAL::Tag_true) const
{
has_rotation = (trans.m(0,1) != 0
|| trans.m(0,2) != 0
|| trans.m(1,0) != 0
|| trans.m(1,2) != 0
|| trans.m(2,0) != 0
|| trans.m(2,1) !=0);
}
void set_transformation(const Aff_transformation_3<Kernel>& trans, CGAL::Tag_false) const
{}
Bbox_3
compute_transformed_bbox_impl(const Bbox_3& bbox, Tag_true) const
compute_transformed_bbox_impl(const CGAL::Aff_transformation_3<Kernel>& at,
const Bbox_3& bbox,
bool has_rotation,
/*SUPPORTS_ROTATION*/ Tag_true) const
{
CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_UPWARD);
if(!has_rotation)
return compute_transformed_bbox_impl(bbox, Tag_false());
return compute_transformed_bbox_impl(at, bbox, has_rotation, Tag_false());
typedef Simple_cartesian<Interval_nt_advanced> AK;
typedef Cartesian_converter<Kernel, AK> C2F;
C2F c2f;
AK::Aff_transformation_3 af = c2f(m_transfo);
AK::Aff_transformation_3 a_at = c2f(at);
AK::FT xtrm[6] = { c2f(bbox.min(0)), c2f(bbox.max(0)),
c2f(bbox.min(1)), c2f(bbox.max(1)),
c2f(bbox.min(2)), c2f(bbox.max(2)) };
typename AK::Point_3 ps[8];
ps[0] = af( AK::Point_3(xtrm[0], xtrm[2], xtrm[4]) );
ps[1] = af( AK::Point_3(xtrm[0], xtrm[2], xtrm[5]) );
ps[2] = af( AK::Point_3(xtrm[0], xtrm[3], xtrm[4]) );
ps[3] = af( AK::Point_3(xtrm[0], xtrm[3], xtrm[5]) );
ps[0] = a_at( AK::Point_3(xtrm[0], xtrm[2], xtrm[4]) );
ps[1] = a_at( AK::Point_3(xtrm[0], xtrm[2], xtrm[5]) );
ps[2] = a_at( AK::Point_3(xtrm[0], xtrm[3], xtrm[4]) );
ps[3] = a_at( AK::Point_3(xtrm[0], xtrm[3], xtrm[5]) );
ps[4] = af( AK::Point_3(xtrm[1], xtrm[2], xtrm[4]) );
ps[5] = af( AK::Point_3(xtrm[1], xtrm[2], xtrm[5]) );
ps[6] = af( AK::Point_3(xtrm[1], xtrm[3], xtrm[4]) );
ps[7] = af( AK::Point_3(xtrm[1], xtrm[3], xtrm[5]) );
ps[4] = a_at( AK::Point_3(xtrm[1], xtrm[2], xtrm[4]) );
ps[5] = a_at( AK::Point_3(xtrm[1], xtrm[2], xtrm[5]) );
ps[6] = a_at( AK::Point_3(xtrm[1], xtrm[3], xtrm[4]) );
ps[7] = a_at( AK::Point_3(xtrm[1], xtrm[3], xtrm[5]) );
return bbox_3(ps, ps+8);
}
Bbox_3
compute_transformed_bbox_impl(const Bbox_3& bbox, Tag_false) const
compute_transformed_bbox_impl(const CGAL::Aff_transformation_3<Kernel>& at,
const Bbox_3& bbox,
bool,
/*SUPPORTS_ROTATION*/ Tag_false) const
{
CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_UPWARD);
typedef Simple_cartesian<Interval_nt_advanced > AK;
typedef Cartesian_converter<Kernel, AK> C2F;
C2F c2f;
AK::Aff_transformation_3 af = c2f(m_transfo);
AK::Aff_transformation_3 a_at = c2f(at);
AK::FT xtrm[6] = { c2f(bbox.min(0)), c2f(bbox.max(0)),
c2f(bbox.min(1)), c2f(bbox.max(1)),
c2f(bbox.min(2)), c2f(bbox.max(2)) };
typename AK::Point_3 ps[2];
ps[0] = af( AK::Point_3(xtrm[0], xtrm[2], xtrm[4]) );
ps[1] = af( AK::Point_3(xtrm[1], xtrm[3], xtrm[5]) );
ps[0] = a_at( AK::Point_3(xtrm[0], xtrm[2], xtrm[4]) );
ps[1] = a_at( AK::Point_3(xtrm[1], xtrm[3], xtrm[5]) );
return bbox_3(ps, ps+2);
}
public:
//Constructor
AABB_do_intersect_transform_traits(const Aff_transformation_3<Kernel>& transf = Aff_transformation_3<Kernel>(IDENTITY))
bool has_rotation(const CGAL::Aff_transformation_3<Kernel>& at) const
{
has_rotation = false;
set_transformation(transf, SUPPORTS_ROTATION());
return ( at.m(0,1) != 0 || at.m(0,2) != 0 || at.m(1,0) != 0
|| at.m(1,2) != 0 || at.m(2,0) != 0 || at.m(2,1) !=0);
}
// AABBTraits concept types
typedef typename BaseTraits::Point_3 Point_3;
typedef typename BaseTraits::Primitive Primitive;
typedef typename BaseTraits::Bounding_box Bounding_box;
Bbox_3
compute_transformed_bbox(const CGAL::Aff_transformation_3<Kernel>& at,
const Bbox_3& bbox,
bool has_rotation) const
{
return compute_transformed_bbox_impl(at, bbox, has_rotation, SUPPORTS_ROTATION());
}
};
// helper functions
// traversal traits for a tree vs a primitive
template<typename AABBTraits, typename Kernel,
typename SUPPORTS_ROTATION = CGAL::Tag_true>
class Do_intersect_traversal_traits_with_transformation
: public Traversal_traits_with_transformation_helper<AABBTraits, Kernel, SUPPORTS_ROTATION>
{
typedef typename AABBTraits::Primitive Primitive;
typedef ::CGAL::AABB_node<AABBTraits> Node;
typedef Traversal_traits_with_transformation_helper<AABBTraits, Kernel, SUPPORTS_ROTATION> Base;
void register_transformation(CGAL::Tag_true)
{
m_has_rotation = this->has_rotation(m_transfo);
}
void register_transformation(CGAL::Tag_false)
{}
public:
Do_intersect_traversal_traits_with_transformation(const AABBTraits& traits)
: m_is_found(false), m_traits(traits), m_has_rotation(false)
{
}
bool go_further() const { return !m_is_found; }
template <class Query>
void intersection(const Query& query, const Primitive& primitive)
{
if( CGAL::do_intersect(query,
internal::Primitive_helper<AABBTraits>::get_datum(primitive, m_traits).transform(m_transfo)) )
m_is_found = true;
}
template <class Query>
bool do_intersect(const Query& query, const Node& node) const
{
return m_traits.do_intersect_object()(query, compute_transformed_bbox(node.bbox()));
}
bool is_intersection_found() const { return m_is_found; }
void reset()
{
m_is_found = false;
}
const Aff_transformation_3<Kernel>&
transformation() const
{
return m_transfo;
}
void set_transformation(const Aff_transformation_3<Kernel>& transfo)
{
m_transfo = transfo;
register_transformation(SUPPORTS_ROTATION());
}
Bbox_3
compute_transformed_bbox(const Bbox_3& bbox) const
{
return compute_transformed_bbox_impl(bbox, SUPPORTS_ROTATION());
return Base::compute_transformed_bbox(m_transfo, bbox, m_has_rotation);
}
// Do_intersect predicate
class Do_intersect
: BaseTraits::Do_intersect
// helper for Point_inside_vertical_ray_cast
class Transformed_tree_helper
{
typedef AABB_do_intersect_transform_traits<Kernel, AABBPrimitive, SUPPORTS_ROTATION> AABBTraits;
const AABBTraits& m_traits;
typedef typename BaseTraits::Do_intersect Base;
typedef AABB_tree<AABBTraits> Tree;
typedef CGAL::AABB_node<AABBTraits> Node;
typedef Do_intersect_traversal_traits_with_transformation<AABBTraits, Kernel, SUPPORTS_ROTATION> Traversal_traits;
Bounding_box
compute_transformed_bbox(const Bounding_box& bbox) const
{
return m_traits.compute_transformed_bbox(bbox);
}
Traversal_traits m_tt;
public:
Do_intersect(const AABBTraits& traits)
: Base(static_cast<const BaseTraits&>(traits)),
m_traits(traits)
Transformed_tree_helper(const Traversal_traits& tt)
: m_tt(tt)
{}
template<typename Query>
bool operator()(const Query& q, const Bounding_box& bbox) const
Bbox_3 get_tree_bbox(const AABB_tree<AABBTraits>& tree) const
{
return
static_cast<const Base*>(this)->operator()(
q, compute_transformed_bbox(bbox));
return m_tt.compute_transformed_bbox(tree.bbox());
}
template<typename Query>
bool operator()(const Query& q, const Primitive& pr) const
typename AABBTraits::Primitive::Datum
get_primitive_datum(const typename AABBTraits::Primitive& primitive, const AABBTraits& traits) const
{
// transformation is done within Primitive_helper
return do_intersect(q, internal::Primitive_helper<Self>::get_datum(pr,m_traits));
return internal::Primitive_helper<AABBTraits>::get_datum(primitive, traits).transform(m_tt.transformation());
}
// intersection with AABB-tree
template<typename AABBTraits>
bool operator()(const CGAL::AABB_tree<AABBTraits>& other_tree, const Primitive& pr) const
Bbox_3 get_node_bbox(const Node& node) const
{
// transformation is done within Primitive_helper
return other_tree.do_intersect( internal::Primitive_helper<Self>::get_datum(pr,m_traits));
}
template<typename AABBTraits>
bool operator()(const CGAL::AABB_tree<AABBTraits>& other_tree, const Bounding_box& bbox) const
{
return other_tree.do_intersect(compute_transformed_bbox(bbox));
return m_tt.compute_transformed_bbox(node.bbox());
}
};
Do_intersect do_intersect_object() const{
return Do_intersect(*this);
}
//Specific
void set_transformation(const Aff_transformation_3<Kernel>& trans) const
Transformed_tree_helper get_helper() const
{
m_transfo = trans;
set_transformation(trans, SUPPORTS_ROTATION());
return Transformed_tree_helper(*this);
}
const Aff_transformation_3<Kernel>& transformation() const { return m_transfo; }
private:
bool m_is_found;
const AABBTraits& m_traits;
Aff_transformation_3<Kernel> m_transfo;
bool m_has_rotation;
};
namespace internal {
template<typename K, typename P, typename T>
struct Primitive_helper<AABB_do_intersect_transform_traits<K,P,T> ,true>{
typedef AABB_do_intersect_transform_traits<K,P,T> Traits;
static typename Traits::Primitive::Datum get_datum(const typename Traits::Primitive& p,
const Traits & traits)
// traversal traits for a tree
template<typename AABBTraits, class Kernel, typename SUPPORTS_ROTATION = CGAL::Tag_true >
class Do_intersect_traversal_traits_for_two_trees
: public Traversal_traits_with_transformation_helper<AABBTraits, Kernel, SUPPORTS_ROTATION>
{
return p.datum(traits.shared_data()).transform(traits.transformation());
}
typedef typename AABBTraits::Primitive Primitive;
typedef ::CGAL::AABB_node<AABBTraits> Node;
typedef Traversal_traits_with_transformation_helper<AABBTraits, Kernel, SUPPORTS_ROTATION> Base;
static typename Traits::Point_3 get_reference_point(const typename Traits::Primitive& p,const Traits& traits) {
return p.reference_point(traits.shared_data()).transform(traits.transformation());
}
void register_transformation(CGAL::Tag_true)
{
m_has_rotation = this->has_rotation(m_transfo);
}
void register_transformation(CGAL::Tag_false)
{}
Bbox_3
compute_transformed_bbox(const Bbox_3& bbox) const
{
return Base::compute_transformed_bbox(m_transfo, bbox, m_has_rotation);
}
public:
Do_intersect_traversal_traits_for_two_trees(const AABBTraits& traits,
const Aff_transformation_3<Kernel>& transfo,
Do_intersect_traversal_traits_with_transformation<AABBTraits, Kernel, SUPPORTS_ROTATION>& query_traversal_traits)
: m_is_found(false)
, m_traits(traits)
, m_transfo(transfo)
, m_has_rotation(false)
, m_query_traversal_traits(query_traversal_traits)
{
register_transformation(SUPPORTS_ROTATION());
}
bool go_further() const { return !m_is_found; }
void intersection(const AABB_tree<AABBTraits>& query, const Primitive& primitive)
{
query.traversal( internal::Primitive_helper<AABBTraits>::get_datum(primitive,m_traits).transform(m_transfo), m_query_traversal_traits );
m_is_found = m_query_traversal_traits.is_intersection_found();
m_query_traversal_traits.reset();
}
bool do_intersect(const AABB_tree<AABBTraits>& query, const Node& node) const
{
query.traversal( compute_transformed_bbox(node.bbox()), m_query_traversal_traits );
bool res = m_query_traversal_traits.is_intersection_found();
m_query_traversal_traits.reset();
return res;
}
bool is_intersection_found() const { return m_is_found; }
private:
bool m_is_found;
const AABBTraits& m_traits;
const Aff_transformation_3<Kernel>& m_transfo;
bool m_has_rotation;
Do_intersect_traversal_traits_with_transformation<AABBTraits, Kernel, SUPPORTS_ROTATION>& m_query_traversal_traits;
};
template<typename K, typename P, typename T>
typename CGAL::AABB_tree<AABB_do_intersect_transform_traits<K,P,T> >::Bounding_box
get_tree_bbox(const CGAL::AABB_tree<AABB_do_intersect_transform_traits<K,P,T> >& tree)
{
return tree.traits().compute_transformed_bbox(tree.bbox());
}
template<typename K, typename P, typename T>
typename CGAL::AABB_tree<AABB_do_intersect_transform_traits<K,P,T> >::Bounding_box
get_node_bbox(const CGAL::AABB_node<AABB_do_intersect_transform_traits<K,P,T> >& node,
const AABB_do_intersect_transform_traits<K,P,T>& traits)
{
return traits.compute_transformed_bbox(node.bbox());
}
} // end internal
}//end CGAL
#endif //CGAL_AABB_AABB_do_intersect_transform_traits_H

View File

@ -36,24 +36,32 @@
namespace CGAL {
namespace internal {
// added for AABB_do_intersect_transform_traits
template<class AABBTree>
typename AABBTree::Bounding_box
get_tree_bbox(const AABBTree& tree)
template <class AABBTree>
struct Default_tree_helper
{
return tree.bbox();
}
typedef typename AABBTree::AABB_traits AABB_traits;
typedef typename CGAL::AABB_node<AABB_traits> Node;
template<class AABBNode, class AABBTraits>
typename AABBNode::Bounding_box
get_node_bbox(const AABBNode& node, const AABBTraits&)
{
return node.bbox();
}
Bbox_3 get_tree_bbox(const AABBTree& tree) const
{
return tree.bbox();
}
typename AABBTree::Primitive::Datum
get_primitive_datum(const typename AABBTree::Primitive& primitive, const AABB_traits& traits) const
{
return internal::Primitive_helper<AABB_traits>::get_datum(primitive, traits);
}
Bbox_3 get_node_bbox(const Node& node) const
{
return node.bbox();
}
};
// internal class for point inside test, using existing AABB tree
template<class Kernel, class AABBTree>
class Point_inside_vertical_ray_cast
template<class Kernel, class AABBTree, class Helper = Default_tree_helper<AABBTree> >
class Point_inside_vertical_ray_cast
{
typedef typename Kernel::Point_3 Point;
typedef typename Kernel::Ray_3 Ray;
@ -61,14 +69,20 @@ class Point_inside_vertical_ray_cast
static const unsigned int seed = 1340818006;
Helper m_helper;
public:
Point_inside_vertical_ray_cast(const Helper& h = Helper())
: m_helper(h)
{}
Bounded_side operator()(
const Point& point,
const AABBTree& tree,
typename Kernel::Construct_ray_3 ray_functor = Kernel().construct_ray_3_object(),
typename Kernel::Construct_vector_3 vector_functor = Kernel().construct_vector_3_object() ) const
{
typename Traits::Bounding_box bbox = get_tree_bbox(tree);
typename Traits::Bounding_box bbox = m_helper.get_tree_bbox(tree);
if( point.x() < bbox.xmin() || point.x() > bbox.xmax()
|| point.y() < bbox.ymin() || point.y() > bbox.ymax()
@ -103,8 +117,8 @@ private:
std::pair<boost::logic::tribool,std::size_t>
status( boost::logic::tribool(boost::logic::indeterminate), 0);
Ray_3_Triangle_3_traversal_traits<Traits, Kernel, Boolean_tag<ray_is_vertical> >
traversal_traits(status, tree.traits());
Ray_3_Triangle_3_traversal_traits<Traits, Kernel, Helper, Boolean_tag<ray_is_vertical> >
traversal_traits(status, tree.traits(), m_helper);
tree.traversal(ray, traversal_traits);

View File

@ -15,7 +15,7 @@
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
//
// Author(s) : Sebastien Loriot
@ -36,7 +36,7 @@
namespace CGAL {
namespace internal {
template<typename AABBTraits, class Kernel, class Tag_ray_is_vertical=Tag_false>
template<typename AABBTraits, class Kernel, class Helper, class Tag_ray_is_vertical=Tag_false>
class Ray_3_Triangle_3_traversal_traits
{
protected:
@ -46,11 +46,13 @@ protected:
const AABBTraits& m_aabb_traits;
typedef typename AABBTraits::Primitive Primitive;
typedef CGAL::AABB_node<AABBTraits> Node;
Helper m_helper;
public:
Ray_3_Triangle_3_traversal_traits(std::pair<boost::logic::tribool,std::size_t>& status,
const AABBTraits& aabb_traits)
:m_status(status),m_stop(false), m_aabb_traits(aabb_traits)
const AABBTraits& aabb_traits,
const Helper& h)
:m_status(status),m_stop(false), m_aabb_traits(aabb_traits), m_helper(h)
{m_status.first=true;}
bool go_further() const { return !m_stop; }
@ -60,10 +62,8 @@ public:
{
internal::r3t3_do_intersect_endpoint_position_visitor visitor;
std::pair<bool,internal::R3T3_intersection::type> res=
internal::do_intersect(
(internal::Primitive_helper<AABBTraits>::get_datum(primitive, m_aabb_traits)),
query,Kernel(),visitor);
internal::do_intersect(m_helper.get_primitive_datum(primitive, m_aabb_traits), query,Kernel(),visitor);
if (res.first){
switch (res.second){
case internal::R3T3_intersection::CROSS_FACET:
@ -79,40 +79,40 @@ public:
}
}
}
template<class Query>
bool do_intersect(const Query& query, const Node& node) const
{
return m_aabb_traits.do_intersect_object()(query, node.bbox());
return m_aabb_traits.do_intersect_object()(query, m_helper.get_node_bbox(node));
}
};
//specialization for vertical ray
template<typename AABBTraits, class Kernel>
class Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,Tag_true>:
public Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,Tag_false>
template<typename AABBTraits, class Kernel, class TraversalTraits>
class Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,TraversalTraits,Tag_true>:
public Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,TraversalTraits,Tag_false>
{
typedef Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,Tag_false> Base;
typedef Ray_3_Triangle_3_traversal_traits<AABBTraits,Kernel,TraversalTraits,Tag_false> Base;
typedef typename Kernel::Point_3 Point;
typedef typename Base::Primitive Primitive;
typedef CGAL::AABB_node<AABBTraits> Node;
public:
Ray_3_Triangle_3_traversal_traits(std::pair<boost::logic::tribool,std::size_t>& status, const AABBTraits& aabb_traits)
:Base(status, aabb_traits){}
Ray_3_Triangle_3_traversal_traits(std::pair<boost::logic::tribool,std::size_t>& status, const AABBTraits& aabb_traits, const TraversalTraits& tt)
:Base(status, aabb_traits, tt){}
template <class Query>
bool do_intersect(const Query& query, const Bbox_3& bbox) const
{
const Point& source=query.point(0);
const Point& target=query.point(1);
bool inc_z=target.z()>source.z();
//the ray does not intersect the z-slab
if ( ( inc_z && source.z()>bbox.zmax() )|| (!inc_z && source.z()<bbox.zmin()) ) return false;
//the source is not in the x-slab
if (source.x() > bbox.xmax() || source.x()<bbox.xmin()) return false;
//check if the source is not in the y-slab
@ -122,7 +122,7 @@ public:
template <class Query>
bool do_intersect(const Query& query, const Node& node) const
{
return do_intersect(query,get_node_bbox(node, this->m_aabb_traits));
return do_intersect(query,this->m_helper.get_node_bbox(node));
}
private:
@ -139,44 +139,42 @@ public:
template<class Query>
void intersection(const Query& query, const Primitive& primitive)
{
typename Kernel::Triangle_3 t
= (internal::Primitive_helper<AABBTraits>::get_datum(primitive, this->m_aabb_traits));
typename Kernel::Triangle_3 t = this->m_helper.get_primitive_datum(primitive, this->m_aabb_traits);
if ( !do_intersect(query,t.bbox()) ) return;
typename Kernel::Point_2 p0=z_project(t[0]);
typename Kernel::Point_2 p1=z_project(t[1]);
typename Kernel::Point_2 p2=z_project(t[2]);
int indices[3]={0,1,2}; //to track whether triangle points have been swapt
typename Kernel::Point_2 q=z_project( query.source() );
Orientation orient_2=orientation(p0,p1,p2);
//check whether the face has a normal vector in the xy-plane
if (orient_2==COLLINEAR){
//in that case the projection of the triangle along the z-axis is a segment.
const typename Kernel::Point_2& other_point = p0!=p1?p1:p2;
if ( orientation(p0,other_point,q) != COLLINEAR ) return;///no intersection
//check if the ray source is above or below the triangle and compare it
//check if the ray source is above or below the triangle and compare it
//with the direction of the ray
//TODO and if yes return
//this is just an optimisation, the current code is valid
this->m_status.first=boost::logic::indeterminate;
this->m_stop=true;
return;
}
//regular case
if (orient_2==NEGATIVE){
std::swap(p1,p2);
std::swap(indices[1],indices[2]);
}
//check whether the ray intersect the supporting plane
Orientation orient_3 = orientation(t[indices[0]],t[indices[1]],t[indices[2]],query.source());
if ( orient_3!=COPLANAR &&
if ( orient_3!=COPLANAR &&
(
//indicates whether the ray is oriented toward the positive side of the plane
( POSITIVE == CGAL::sign( query.to_vector().z() ) )
@ -185,7 +183,6 @@ public:
(orient_3==POSITIVE)
)
) return; //no intersection
//position against first segment
switch( orientation(p0,p1,q) ){

View File

@ -28,9 +28,9 @@
#include <CGAL/AABB_tree.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/Polygon_mesh_processing/internal/AABB_do_intersect_transform_traits.h>
#include <CGAL/Polygon_mesh_processing/internal/Side_of_triangle_mesh/Point_inside_vertical_ray_cast.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/property_map.h>
#include <boost/iterator/counting_iterator.hpp>
@ -50,17 +50,16 @@ template <class TriangleMesh, class Kernel, class HAS_ROTATION = CGAL::Tag_true>
class Rigid_mesh_collision_detection
{
typedef CGAL::AABB_face_graph_triangle_primitive<TriangleMesh> Primitive;
typedef CGAL::AABB_do_intersect_transform_traits<Kernel, Primitive, HAS_ROTATION> Traits;
typedef CGAL::AABB_traits<Kernel, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> Tree;
typedef Side_of_triangle_mesh<TriangleMesh, Kernel, Default, Tree> Side_of_tm;
typedef Do_intersect_traversal_traits_with_transformation<Traits, Kernel, HAS_ROTATION> Traversal_traits;
std::vector<const TriangleMesh*> m_triangle_mesh_ptrs;
// TODO: we probably want an option with external trees
std::vector<Tree*> m_aabb_trees;
std::vector<bool> m_is_closed;
std::vector< std::vector<typename Kernel::Point_3> > m_points_per_cc;
std::vector<Traversal_traits> m_traversal_traits;
#if CGAL_CACHE_BOXES
boost::dynamic_bitset<> m_bboxes_is_invalid;
std::vector<Bbox_3> m_bboxes;
@ -108,6 +107,25 @@ class Rigid_mesh_collision_detection
m_points_per_cc.back().push_back( get(boost::vertex_point, tm, *boost::begin(vertices(tm))) );
}
// precondition A and B does not intersect
bool does_A_contains_a_CC_of_B(std::size_t id_A, std::size_t id_B)
{
typename Kernel::Construct_ray_3 ray_functor;
typename Kernel::Construct_vector_3 vector_functor;
typedef typename Traversal_traits::Transformed_tree_helper Helper;
BOOST_FOREACH(const typename Kernel::Point_3& q, m_points_per_cc[id_B])
{
if( internal::Point_inside_vertical_ray_cast<Kernel, Tree, Helper>(m_traversal_traits[id_A].get_helper())(
m_traversal_traits[id_B].transformation()( q ), *m_aabb_trees[id_A],
ray_functor, vector_functor) == CGAL::ON_BOUNDED_SIDE)
{
return true;
}
}
return false;
}
public:
template <class MeshRange>
Rigid_mesh_collision_detection(const MeshRange& triangle_meshes, bool assume_one_CC_per_mesh = false)
@ -131,6 +149,7 @@ public:
m_aabb_trees.reserve(nb_meshes);
m_is_closed.clear();
m_is_closed.resize(nb_meshes, false);
m_traversal_traits.reserve(m_aabb_trees.size());
#if CGAL_CACHE_BOXES
m_bboxes_is_invalid.clear();
m_bboxes_is_invalid.resize(nb_meshes, true);
@ -144,6 +163,7 @@ public:
m_triangle_mesh_ptrs.push_back( &tm );
Tree* t = new Tree(faces(tm).begin(), faces(tm).end(), tm);
m_aabb_trees.push_back(t);
m_traversal_traits.push_back( Traversal_traits(m_aabb_trees.back()->traits()) );
add_cc_points(tm, assume_one_CC);
}
}
@ -154,6 +174,7 @@ public:
m_triangle_mesh_ptrs.push_back( &tm );
Tree* t = new Tree(faces(tm).begin(), faces(tm).end(), tm);
m_aabb_trees.push_back(t);
m_traversal_traits.push_back( Traversal_traits(m_aabb_trees.back()->traits()) );
#if CGAL_CACHE_BOXES
m_bboxes.push_back(Bbox_3());
m_bboxes_is_invalid.resize(m_bboxes_is_invalid.size()+1, true);
@ -169,6 +190,7 @@ public:
m_aabb_trees.erase( m_aabb_trees.begin()+mesh_id);
m_is_closed.erase(m_is_closed.begin()+mesh_id);
m_points_per_cc.erase(m_points_per_cc.begin()+mesh_id);
m_traversal_traits.erase(m_traversal_traits.begin()+mesh_id);
#if CGAL_CACHE_BOXES
// TODO this is a lazy approach that is not optimal
m_bboxes.pop_back();
@ -179,7 +201,7 @@ public:
void set_transformation(std::size_t mesh_id, const Aff_transformation_3<Kernel>& aff_trans)
{
m_aabb_trees[mesh_id]->traits().set_transformation(aff_trans);
m_traversal_traits[mesh_id].set_transformation(aff_trans);
#if CGAL_CACHE_BOXES
m_bboxes_is_invalid.set(mesh_id);
#endif
@ -189,11 +211,11 @@ public:
void update_bboxes()
{
// protector is supposed to have been set
for (boost::dynamic_bitset<>::size_type i = m_bboxes.find_first();
for (boost::dynamic_bitset<>::size_type i = m_bboxes_is_invalid.find_first();
i != m_bboxes_is_invalid.npos;
i = m_bboxes_is_invalid.find_next(i))
{
m_bboxes[i]=internal::get_tree_bbox(*m_aabb_trees[i]);
m_bboxes[i]=m_traversal_traits[i].get_helper().get_tree_bbox(*m_aabb_trees[i]);
}
m_bboxes_is_invalid.reset();
}
@ -261,34 +283,27 @@ public:
if (!do_overlap(m_bboxes[k], m_bboxes[mesh_id])) continue;
#endif
// TODO: think about an alternative that is using a traversal traits
if ( m_aabb_trees[k]->do_intersect( *m_aabb_trees[mesh_id] ) )
Do_intersect_traversal_traits_for_two_trees<Traits, Kernel, HAS_ROTATION> traversal_traits(
m_aabb_trees[k]->traits(), m_traversal_traits[k].transformation(), m_traversal_traits[mesh_id]);
m_aabb_trees[k]->traversal(*m_aabb_trees[mesh_id], traversal_traits);
if (traversal_traits.is_intersection_found())
res.push_back(std::make_pair(k, false));
else{
if (m_is_closed[mesh_id])
{
Side_of_tm side_of_mid(*m_aabb_trees[mesh_id]);
bool stop = false;
BOOST_FOREACH(const typename Kernel::Point_3& q, m_points_per_cc[k])
if ( does_A_contains_a_CC_of_B(mesh_id, k) )
{
if(side_of_mid(m_aabb_trees[k]->traits().transformation()( q )) == CGAL::ON_BOUNDED_SIDE)
{
res.push_back(std::make_pair(k, true));
stop=true;
break;
}
res.push_back(std::make_pair(k, true));
continue;
}
if (stop) continue;
}
if (m_is_closed[k])
{
Side_of_tm side_of_mk(*m_aabb_trees[k]);
BOOST_FOREACH(const typename Kernel::Point_3& q, m_points_per_cc[mesh_id])
if ( does_A_contains_a_CC_of_B(k, mesh_id) )
{
if(side_of_mk(m_aabb_trees[mesh_id]->traits().transformation()( q )) == CGAL::ON_BOUNDED_SIDE)
{
res.push_back(std::make_pair(k, true));
break;
}
res.push_back(std::make_pair(k, true));
continue;
}
}
}