mirror of https://github.com/CGAL/cgal
Merge pull request #3369 from maxGimeno/AABB_tree-AABB_transformed_traits-GF
[Small Feature] Add collision detection in PMP
This commit is contained in:
commit
cdbe19b480
|
|
@ -0,0 +1,41 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
project( AABB_traits_benchmark)
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_policy(VERSION 3.1)
|
||||
|
||||
|
||||
if ( COMMAND cmake_policy )
|
||||
|
||||
cmake_policy( SET CMP0003 NEW )
|
||||
|
||||
endif()
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET)
|
||||
if ( CGAL_FOUND )
|
||||
include( ${CGAL_USE_FILE} )
|
||||
else ()
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
# Boost and its components
|
||||
find_package( Boost REQUIRED )
|
||||
# include for local directory
|
||||
if ( NOT Boost_FOUND )
|
||||
message(STATUS "This project requires the Boost library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# include for local package
|
||||
include_directories( BEFORE ../../include )
|
||||
|
||||
add_executable (test_ test.cpp)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,176 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Polygon_mesh_processing/intersection.h>
|
||||
#include <CGAL/Polygon_mesh_processing/transform.h>
|
||||
|
||||
#include <CGAL/boost/graph/copy_face_graph.h>
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/AABB_do_intersect_transform_traits.h>
|
||||
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||
#include <CGAL/Side_of_triangle_mesh.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
|
||||
typedef CGAL::AABB_face_graph_triangle_primitive<Surface_mesh> Primitive;
|
||||
typedef CGAL::AABB_do_intersect_transform_traits<K, Primitive> Traits;
|
||||
typedef CGAL::AABB_tree<Traits> Tree;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
void naive_test(int k, const char* fname,
|
||||
int& nb_inter, int& nb_no_inter, int& nb_include)
|
||||
{
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh tm, tm2;
|
||||
input >> tm;
|
||||
copy_face_graph(tm, tm2);
|
||||
CGAL::Aff_transformation_3<K> init1(CGAL::SCALING, 6.0);
|
||||
PMP::transform(init1, tm);
|
||||
CGAL::Bbox_3 box = PMP::bbox(tm);
|
||||
typedef CGAL::AABB_tree<CGAL::AABB_traits<K, Primitive> > Tree;
|
||||
Tree tmTree(tm.faces_begin(), tm.faces_end(), tm);
|
||||
Tree tmTree2(tm2.faces_begin(), tm2.faces_end(), tm2);
|
||||
CGAL::Aff_transformation_3<K> init2(CGAL::TRANSLATION, - K::Vector_3(
|
||||
(box.xmax()-box.xmin()),0,0));
|
||||
PMP::transform(init2, tm2);
|
||||
|
||||
tmTree.build();
|
||||
K::Vector_3 unit_vec = (2.0/k * K::Vector_3((box.xmax()-box.xmin()),
|
||||
0,
|
||||
0));
|
||||
CGAL::Aff_transformation_3<K> T0(CGAL::IDENTITY);
|
||||
K::FT rot[9];
|
||||
rot[0] = 1.0;
|
||||
rot[1] = 0.0;
|
||||
rot[2] = 0.0;
|
||||
rot[3] = 0.0;
|
||||
rot[4] = std::cos(CGAL_PI/4.0);
|
||||
rot[5] = -std::sin(CGAL_PI/4.0);
|
||||
rot[6] = 0.0;
|
||||
rot[7] = std::sin(CGAL_PI/4.0);
|
||||
rot[8] = std::cos(CGAL_PI/4.0);
|
||||
CGAL::Aff_transformation_3<K> R(rot[0], rot[1], rot[2],
|
||||
rot[3], rot[4], rot[5],
|
||||
rot[6], rot[7], rot[8]);
|
||||
|
||||
CGAL::Side_of_triangle_mesh<Surface_mesh, K> sotm1(tm);
|
||||
for(int i=1; i<k+1; ++i)
|
||||
{
|
||||
CGAL::Aff_transformation_3<K> T1 = CGAL::Aff_transformation_3<K>(CGAL::TRANSLATION, i*unit_vec);
|
||||
CGAL::Aff_transformation_3<K> transfo = T0*R*T1;
|
||||
PMP::transform(transfo, tm2);
|
||||
tmTree2.build();
|
||||
if(tmTree2.do_intersect(tmTree))
|
||||
++nb_inter;
|
||||
else
|
||||
{
|
||||
if(sotm1(tm2.point(*tm2.vertices().begin())) != CGAL::ON_UNBOUNDED_SIDE)
|
||||
{
|
||||
++nb_include;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGAL::Side_of_triangle_mesh<Surface_mesh, K> sotm2(tm2);
|
||||
if(sotm2(tm.point(*tm.vertices().begin())) != CGAL::ON_UNBOUNDED_SIDE)
|
||||
++nb_include;
|
||||
else
|
||||
++nb_no_inter;
|
||||
}
|
||||
}
|
||||
T0 = CGAL::Aff_transformation_3<K>(CGAL::TRANSLATION, -i*unit_vec);
|
||||
}
|
||||
}
|
||||
void test_no_collision(int k, const char* fname,
|
||||
int& nb_inter, int& nb_no_inter, int& nb_include)
|
||||
{
|
||||
std::ifstream input(fname);
|
||||
Surface_mesh tm, tm2;
|
||||
input >> tm;
|
||||
copy_face_graph(tm, tm2);
|
||||
CGAL::Aff_transformation_3<K> init1(CGAL::SCALING, 6.0);
|
||||
PMP::transform(init1, tm);
|
||||
CGAL::Bbox_3 box = PMP::bbox(tm);
|
||||
Tree tmTree(tm.faces_begin(), tm.faces_end(), tm);
|
||||
Tree tmTree2(tm2.faces_begin(), tm2.faces_end(), tm2);
|
||||
CGAL::Aff_transformation_3<K> init2(CGAL::TRANSLATION, - K::Vector_3(
|
||||
(box.xmax()-box.xmin()),0,0));
|
||||
PMP::transform(init2, tm2);
|
||||
|
||||
tmTree.build();
|
||||
tmTree2.build();
|
||||
typedef boost::property_map<Surface_mesh, CGAL::vertex_point_t>::type VPM;
|
||||
VPM vpm2 = get(CGAL::vertex_point, tm2);
|
||||
|
||||
K::Vector_3 unit_vec = (2.0/k * K::Vector_3((box.xmax()-box.xmin()),
|
||||
0,
|
||||
0));
|
||||
|
||||
CGAL::Side_of_triangle_mesh<Surface_mesh, K,
|
||||
VPM, Tree> sotm1(tmTree);
|
||||
for(int i=1; i<k+1; ++i)
|
||||
{
|
||||
K::FT rot[9];
|
||||
rot[0] = 1.0;
|
||||
rot[1] = 0.0;
|
||||
rot[2] = 0.0;
|
||||
rot[3] = 0.0;
|
||||
rot[4] = std::cos(i*CGAL_PI/4.0);
|
||||
rot[5] = -std::sin(i*CGAL_PI/4.0);
|
||||
rot[6] = 0.0;
|
||||
rot[7] = std::sin(i*CGAL_PI/4.0);
|
||||
rot[8] = std::cos(i*CGAL_PI/4.0);
|
||||
CGAL::Aff_transformation_3<K> R(rot[0], rot[1], rot[2],
|
||||
rot[3], rot[4], rot[5],
|
||||
rot[6], rot[7], rot[8]);
|
||||
CGAL::Aff_transformation_3<K> T1 = CGAL::Aff_transformation_3<K>(CGAL::TRANSLATION, i*unit_vec);
|
||||
CGAL::Aff_transformation_3<K> transfo = R*T1;
|
||||
tmTree2.traits().set_transformation(transfo);
|
||||
CGAL::Interval_nt_advanced::Protector protector;
|
||||
if(tmTree2.do_intersect(tmTree))
|
||||
++nb_inter;
|
||||
else
|
||||
{
|
||||
if(sotm1(transfo.transform(vpm2[*tm2.vertices().begin()])) != CGAL::ON_UNBOUNDED_SIDE)
|
||||
{
|
||||
++nb_include;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGAL::Side_of_triangle_mesh<Surface_mesh, K,
|
||||
VPM, Tree> sotm2(tmTree2);
|
||||
if(sotm2(tm.point(*tm.vertices().begin())) != CGAL::ON_UNBOUNDED_SIDE)
|
||||
++nb_include;
|
||||
else
|
||||
++nb_no_inter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
int k = (argc>1) ? atoi(argv[1]) : 10;
|
||||
const char* path = (argc>2)?argv[2]:"data/handle"
|
||||
".off";
|
||||
|
||||
std::cout<< k<<" steps in "<<path<<std::endl;
|
||||
int nb_inter(0), nb_no_inter(0), nb_include(0),
|
||||
naive_inter(0), naive_no_inter(0), naive_include(0);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
naive_test(k, path, naive_inter, naive_no_inter, naive_include);
|
||||
auto end = std::chrono::steady_clock::now();
|
||||
std::cout<<"Naive test :"<<naive_inter<<" collisions, "<<naive_include<<" inclusions, "<<naive_no_inter<<" no collision, calculated in "
|
||||
<<std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "μs." << std::endl;
|
||||
start = std::chrono::steady_clock::now();
|
||||
test_no_collision(k, path,nb_inter, nb_no_inter, nb_include);
|
||||
end = std::chrono::steady_clock::now();
|
||||
std::cout<<"With transform_traits: "<<nb_inter<<" collisions, "<<nb_include<<" inclusions, "<<nb_no_inter<<" no collision, calculated in "
|
||||
<<std::chrono::duration_cast<std::chrono::microseconds>(end - start).count() << "μs." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -75,25 +75,17 @@ using Intersection_and_primitive_id = unspecified_type;
|
|||
|
||||
/// \name Splitting
|
||||
/// During the construction of the AABB tree, the primitives are
|
||||
/// sorted according to some comparison functions related to the \f$x\f$,
|
||||
/// \f$ y\f$ or \f$ z\f$ coordinate axis:
|
||||
/// splitted according to some comparison functions related to the longest axis:
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
A functor object to split a range of primitives into two sub-ranges along the X-axis. Provides the operator:
|
||||
`void operator()(InputIterator first, InputIterator beyond);` %Iterator type `InputIterator` must be a model of RandomAccessIterator and have `Primitive` as value type. The operator is used for determining the primitives assigned to the two children nodes of a given node, assuming that the goal is to split the X-dimension of the bounding box of the node. The primitives assigned to this node are passed as argument to the operator. It should modify the iterator range in such a way that its first half and its second half correspond to the two children nodes.
|
||||
A functor object to split a range of primitives into two sub-ranges along the longest axis. Provides the operator:
|
||||
`void operator()(InputIterator first, InputIterator beyond);` %Iterator type `InputIterator` must be a model of RandomAccessIterator
|
||||
and have `Primitive` as value type. The operator is used for determining the primitives assigned to the two children nodes of a given node,
|
||||
assuming that the goal is to split the chosen axis dimension of the bounding box of the node. The primitives assigned to this node are passed as argument
|
||||
to the operator. It should modify the iterator range in such a way that its first half and its second half correspond to the two children nodes.
|
||||
*/
|
||||
typedef unspecified_type Split_primitives_along_x_axis;
|
||||
|
||||
/*!
|
||||
A functor object to split a range of primitives into two sub-ranges along the Y-axis. See `Split_primitives_along_x_axis` for the detailed description.
|
||||
*/
|
||||
typedef unspecified_type Split_primitives_along_y_axis;
|
||||
|
||||
/*!
|
||||
A functor object to split a range of primitives into two sub-ranges along the Z-axis. See `Split_primitives_along_x_axis` for the detailed description.
|
||||
*/
|
||||
typedef unspecified_type Split_primitives_along_z_axis;
|
||||
typedef unspecified_type Split_primitives;
|
||||
|
||||
/*!
|
||||
A functor object to compute the bounding box of a set of primitives. Provides the operator:
|
||||
|
|
@ -132,7 +124,7 @@ A functor object to compute the intersection of a query and a primitive. Provide
|
|||
\cgalHeading{Note on Backward Compatibility}
|
||||
Before the release 4.3 of \cgal, the return type of this function used to be `boost::optional<Object_and_primitive_id>`.
|
||||
*/
|
||||
typedef unspecified_type Intersect;
|
||||
typedef unspecified_type Intersection;
|
||||
|
||||
/// \name Distance Queries
|
||||
/// The following predicates are required for each
|
||||
|
|
@ -170,19 +162,9 @@ typedef unspecified_type Equal_3;
|
|||
/// @{
|
||||
|
||||
/*!
|
||||
Returns the primitive splitting functor for the X axis.
|
||||
Returns the primitive splitting functor.
|
||||
*/
|
||||
Split_primitives_along_x_axis split_primitives_along_x_axis_object();
|
||||
|
||||
/*!
|
||||
Returns the primitive splitting functor for the Y axis.
|
||||
*/
|
||||
Split_primitives_along_y_axis split_primitives_along_y_axis_object();
|
||||
|
||||
/*!
|
||||
Returns the primitive splitting functor for the Z axis.
|
||||
*/
|
||||
Split_primitives_along_z_axis split_primitives_along_z_axis_object();
|
||||
Split_primitives split_primitives_object();
|
||||
|
||||
/*!
|
||||
Returns the bounding box constructor.
|
||||
|
|
@ -197,7 +179,7 @@ Do_intersect do_intersect_object();
|
|||
/*!
|
||||
Returns the intersection constructor.
|
||||
*/
|
||||
Intersect intersect_object();
|
||||
Intersection intersection_object();
|
||||
|
||||
/*!
|
||||
Returns the distance comparison functor.
|
||||
|
|
|
|||
|
|
@ -70,17 +70,17 @@ class AABB_face_graph_triangle_primitive
|
|||
FaceGraph,
|
||||
typename Default::Get<VertexPointPMap,
|
||||
typename boost::property_map< FaceGraph,
|
||||
vertex_point_t>::type >::type>,
|
||||
vertex_point_t>::const_type >::type>,
|
||||
One_point_from_face_descriptor_map<
|
||||
FaceGraph,
|
||||
typename Default::Get<VertexPointPMap,
|
||||
typename boost::property_map< FaceGraph,
|
||||
vertex_point_t>::type >::type>,
|
||||
vertex_point_t>::const_type >::type>,
|
||||
OneFaceGraphPerTree,
|
||||
CacheDatum >
|
||||
#endif
|
||||
{
|
||||
typedef typename Default::Get<VertexPointPMap, typename boost::property_map< FaceGraph, vertex_point_t>::type >::type VertexPointPMap_;
|
||||
typedef typename Default::Get<VertexPointPMap, typename boost::property_map< FaceGraph, vertex_point_t>::const_type >::type VertexPointPMap_;
|
||||
|
||||
typedef typename boost::graph_traits<FaceGraph>::face_descriptor Id_;
|
||||
typedef Triangle_from_face_descriptor_map<FaceGraph,VertexPointPMap_> Triangle_property_map;
|
||||
|
|
|
|||
|
|
@ -176,6 +176,10 @@ struct AABB_traits_base_2<GeomTraits,true>{
|
|||
/// \addtogroup PkgAABBTreeRef
|
||||
/// @{
|
||||
|
||||
// forward declaration
|
||||
template< typename AABBTraits>
|
||||
class AABB_tree;
|
||||
|
||||
/// This traits class handles any type of 3D geometric
|
||||
/// primitives provided that the proper intersection tests and
|
||||
/// constructions are implemented. It handles points, rays, lines and
|
||||
|
|
@ -289,14 +293,15 @@ public:
|
|||
* Sorts the range defined by [first,beyond[. Sort is achieved on bbox longuest
|
||||
* axis, using the comparison function `<dim>_less_than` (dim in {x,y,z})
|
||||
*/
|
||||
class Sort_primitives
|
||||
class Split_primitives
|
||||
{
|
||||
typedef AABB_traits<GeomTraits,AABBPrimitive,BboxMap> Traits;
|
||||
const Traits& m_traits;
|
||||
public:
|
||||
Sort_primitives(const AABB_traits<GeomTraits,AABBPrimitive,BboxMap>& traits)
|
||||
Split_primitives(const AABB_traits<GeomTraits,AABBPrimitive,BboxMap>& traits)
|
||||
: m_traits(traits) {}
|
||||
|
||||
typedef void result_type;
|
||||
template<typename PrimitiveIterator>
|
||||
void operator()(PrimitiveIterator first,
|
||||
PrimitiveIterator beyond,
|
||||
|
|
@ -320,7 +325,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
Sort_primitives sort_primitives_object() const {return Sort_primitives(*this);}
|
||||
Split_primitives split_primitives_object() const {return Split_primitives(*this);}
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -369,6 +374,19 @@ public:
|
|||
{
|
||||
return GeomTraits().do_intersect_3_object()(q, internal::Primitive_helper<AT>::get_datum(pr,m_traits));
|
||||
}
|
||||
|
||||
// intersection with AABB-tree
|
||||
template<typename AABBTraits>
|
||||
bool operator()(const CGAL::AABB_tree<AABBTraits>& other_tree, const Primitive& pr) const
|
||||
{
|
||||
return other_tree.do_intersect( internal::Primitive_helper<AT>::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(bbox);
|
||||
}
|
||||
};
|
||||
|
||||
Do_intersect do_intersect_object() const {return Do_intersect(*this);}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ AABB_node<Tr>::expand(ConstPrimitiveIterator first,
|
|||
m_bbox = traits.compute_bbox_object()(first, beyond);
|
||||
|
||||
// sort primitives along longest axis aabb
|
||||
traits.sort_primitives_object()(first, beyond, m_bbox);
|
||||
traits.split_primitives_object()(first, beyond, m_bbox);
|
||||
|
||||
switch(range)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include <boost/graph/properties.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <CGAL/Dynamic_property_map.h>
|
||||
|
||||
#include <CGAL/basic.h>
|
||||
|
|
@ -267,7 +269,9 @@ struct Edge_index_accessor
|
|||
reference operator[](Handle h) const { return h.id(); }
|
||||
};
|
||||
|
||||
template<typename Handle, typename ValueType, typename Reference>
|
||||
template<typename Handle, typename ValueType, typename Reference,
|
||||
bool is_const = boost::is_const<
|
||||
typename boost::remove_reference<Reference>::type >::value>
|
||||
struct Point_accessor
|
||||
: boost::put_get_helper< Reference, Point_accessor<Handle, ValueType, Reference> >
|
||||
{
|
||||
|
|
@ -279,6 +283,26 @@ struct Point_accessor
|
|||
reference operator[](Handle h) const { return h->point(); }
|
||||
};
|
||||
|
||||
// partial specialization for const map to make them constructible from non-const map
|
||||
template<typename Handle, typename ValueType, typename ConstReference>
|
||||
struct Point_accessor<Handle, ValueType, ConstReference, true>
|
||||
: boost::put_get_helper< ConstReference, Point_accessor<Handle, ValueType, ConstReference, true> >
|
||||
{
|
||||
typedef boost::lvalue_property_map_tag category;
|
||||
typedef ConstReference reference;
|
||||
typedef ValueType value_type;
|
||||
typedef Handle key_type;
|
||||
|
||||
typedef typename boost::mpl::if_< boost::is_reference<ConstReference>,
|
||||
ValueType&,
|
||||
ValueType >::type Reference;
|
||||
|
||||
Point_accessor() {}
|
||||
Point_accessor(Point_accessor<Handle, ValueType, Reference, false>) {}
|
||||
|
||||
reference operator[](Handle h) const { return h->point(); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Needed by PMP::detec_features and Mesh_3
|
||||
|
|
|
|||
|
|
@ -393,6 +393,24 @@ public:
|
|||
return std::make_pair(operator()(pp.first), operator()(pp.second));
|
||||
}
|
||||
|
||||
typename K2::Aff_transformation_3
|
||||
operator()(const typename K1::Aff_transformation_3 &a) const
|
||||
{
|
||||
typedef typename K2::Aff_transformation_3 Aff_transformation_3;
|
||||
typename K2::FT t[12];
|
||||
for(int i=0; i< 3; ++i)
|
||||
{
|
||||
for(int j=0; j<4; ++j)
|
||||
{
|
||||
t[i*4+j] = a.m(i,j);
|
||||
}
|
||||
}
|
||||
return Aff_transformation_3(
|
||||
t[0],t[1],t[2],t[3],
|
||||
t[4],t[5],t[6],t[7],
|
||||
t[8],t[9],t[10],t[11],
|
||||
a.m(3,3));
|
||||
}
|
||||
private:
|
||||
Converter c;
|
||||
K2 k;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <CGAL/Iterator_range.h>
|
||||
#include <CGAL/HalfedgeDS_decorator.h>
|
||||
#include <CGAL/HalfedgeDS_default.h>
|
||||
#include <CGAL/boost/graph/properties.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
|
@ -446,21 +447,6 @@ num_faces(const HalfedgeDS_default<T,I,A>& p)
|
|||
{
|
||||
return p.size_of_faces();
|
||||
}
|
||||
namespace internal {
|
||||
|
||||
template<typename Handle, typename ValueType, typename Reference>
|
||||
struct HDS_Point_accessor
|
||||
: boost::put_get_helper< Reference, HDS_Point_accessor<Handle, ValueType, Reference> >
|
||||
{
|
||||
typedef boost::lvalue_property_map_tag category;
|
||||
typedef Reference reference;
|
||||
typedef ValueType value_type;
|
||||
typedef Handle key_type;
|
||||
|
||||
reference operator[](Handle h) const { return h->point(); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <class T>
|
||||
struct HDS_property_map;
|
||||
|
|
@ -471,13 +457,13 @@ struct HDS_property_map<vertex_point_t>
|
|||
template<class T, class I, class A>
|
||||
struct bind_
|
||||
{
|
||||
typedef internal::HDS_Point_accessor<
|
||||
typedef internal::Point_accessor<
|
||||
typename boost::graph_traits<
|
||||
HalfedgeDS_default<T, I, A>
|
||||
>::vertex_descriptor,
|
||||
typename T::Point_3, typename T::Point_3&> type;
|
||||
|
||||
typedef internal::HDS_Point_accessor<
|
||||
typedef internal::Point_accessor<
|
||||
typename boost::graph_traits<
|
||||
HalfedgeDS_default<T, I, A>
|
||||
>::vertex_descriptor,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ Release date: March 2019
|
|||
- `CGAL::Polygon_mesh_processing::extract_boundary_cycles()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycle()`
|
||||
- `CGAL::Polygon_mesh_processing::merge_duplicated_vertices_in_boundary_cycles()`
|
||||
- Added the class `CGAL::Rigid_triangle_mesh_collision_detection` to detect intersections between meshes
|
||||
and volumes undergoing affine transformations.
|
||||
|
||||
Release 4.13
|
||||
------------
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
//
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2016 GeometryFactory SARL (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: LGPL-3.0+
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
//
|
||||
// Warning: this file is generated, see include/CGAL/licence/README.md
|
||||
|
||||
|
||||
#ifndef CGAL_LICENSE_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_H
|
||||
#define CGAL_LICENSE_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_H
|
||||
|
||||
#include <CGAL/config.h>
|
||||
#include <CGAL/license.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE
|
||||
|
||||
# if CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
|
||||
CGAL_pragma_warning("Your commercial license for CGAL does not cover "
|
||||
"this release of the Polygon Mesh Processing - Collision Detection package.")
|
||||
# endif
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "Your commercial license for CGAL does not cover this release \
|
||||
of the Polygon Mesh Processing - Collision Detection package. \
|
||||
You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
# endif // CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
#else // no CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
CGAL_pragma_warning("\nThe macro CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE is not defined."
|
||||
"\nYou use the CGAL Polygon Mesh Processing - Collision Detection package under "
|
||||
"the terms of the GPLv3+.")
|
||||
# endif // CGAL_LICENSE_WARNING
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "The macro CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE is not defined.\
|
||||
You use the CGAL Polygon Mesh Processing - Collision Detection package under the terms of \
|
||||
the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
#endif // no CGAL_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_COMMERCIAL_LICENSE
|
||||
|
||||
#endif // CGAL_LICENSE_CHECK_POLYGON_MESH_PROCESSING_COLLISION_DETECTION_H
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
To generate the `PACKAGE.h` files, from the file `package_list.txt`:
|
||||
To generate the `PACKAGE.h` files, from the file `gpl_package_list.txt`:
|
||||
|
||||
cmake -P generate_files.cmake
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ Polygon_mesh_processing/predicate Polygon Mesh Processing - Predicate
|
|||
Polygon_mesh_processing/repair Polygon Mesh Processing - Repair
|
||||
Polygon_mesh_processing/miscellaneous Polygon Mesh Processing - Miscellaneous
|
||||
Polygon_mesh_processing/detect_features Polygon Mesh Processing - Feature Detection
|
||||
Polygon_mesh_processing/collision_detection Polygon Mesh Processing - Collision Detection
|
||||
Polyhedron 3D Polyhedral Surface
|
||||
Polyline_simplification_2 2D Polyline Simplification
|
||||
Polytope_distance_d Optimal Distances
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ AABB_node_with_join<Tr>::expand(ConstPrimitiveIterator first,
|
|||
m_bbox = traits.compute_bbox_object()(first, beyond);
|
||||
|
||||
// sort primitives along longest axis aabb
|
||||
traits.sort_primitives_object()(first, beyond, m_bbox);
|
||||
traits.split_primitives_object()(first, beyond, m_bbox);
|
||||
|
||||
switch(range)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public:
|
|||
|
||||
// Put the n/2 smallest primitives in the front, the n/2 largest primitives
|
||||
// in the back. They are compared along the bbox' longest axis.
|
||||
class Sort_primitives
|
||||
class Split_primitives
|
||||
{
|
||||
public:
|
||||
template<typename PrimitiveIterator>
|
||||
|
|
@ -111,9 +111,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
Sort_primitives sort_primitives_object() const
|
||||
Split_primitives split_primitives_object() const
|
||||
{
|
||||
return Sort_primitives();
|
||||
return Split_primitives();
|
||||
}
|
||||
|
||||
// Computes the bounding box of a set of primitives
|
||||
|
|
|
|||
|
|
@ -181,6 +181,9 @@ and provides a list of the parameters that are used in this package.
|
|||
- `CGAL::Polygon_mesh_processing::detect_sharp_edges()`
|
||||
- `CGAL::Polygon_mesh_processing::detect_vertex_incident_patches()`
|
||||
|
||||
## Collision Detection
|
||||
- `CGAL::Rigid_triangle_mesh_collision_detection`
|
||||
|
||||
## Miscellaneous ##
|
||||
- `CGAL::Polygon_mesh_slicer`
|
||||
- `CGAL::Side_of_triangle_mesh`
|
||||
|
|
|
|||
|
|
@ -0,0 +1,304 @@
|
|||
// Copyright (c) 2018 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Maxime Gimeno
|
||||
// Sebastien Loriot
|
||||
//
|
||||
|
||||
#ifndef CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_TRANSFORMATION
|
||||
#define CGAL_PMP_INTERNAL_AABB_TRAVERSAL_TRAITS_WITH_TRANSFORMATION
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/collision_detection.h>
|
||||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/intersections.h>
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/internal/AABB_tree/Has_nested_type_Shared_data.h>
|
||||
#include <CGAL/internal/AABB_tree/Is_ray_intersection_geomtraits.h>
|
||||
#include <CGAL/internal/AABB_tree/Primitive_helper.h>
|
||||
#include <CGAL/Filtered_predicate.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Box_intersection_d/Box_with_info_d.h>
|
||||
#include <CGAL/Aff_transformation_3.h>
|
||||
#include <boost/mpl/if.hpp>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template<typename AABBTraits, typename Kernel, class SUPPORTS_ROTATION>
|
||||
class Traversal_traits_with_transformation_helper
|
||||
{
|
||||
Bbox_3
|
||||
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(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 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] = 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] = 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 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 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] = 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:
|
||||
|
||||
bool has_rotation(const CGAL::Aff_transformation_3<Kernel>& at) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
};
|
||||
|
||||
// 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():
|
||||
m_traits_ptr(NULL)
|
||||
{}
|
||||
|
||||
Do_intersect_traversal_traits_with_transformation(const AABBTraits& traits)
|
||||
: m_is_found(false), m_traits_ptr(&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_ptr).transform(m_transfo)) )
|
||||
m_is_found = true;
|
||||
}
|
||||
|
||||
template <class Query>
|
||||
bool do_intersect(const Query& query, const Node& node) const
|
||||
{
|
||||
return m_traits_ptr->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 Base::compute_transformed_bbox(m_transfo, bbox, m_has_rotation);
|
||||
}
|
||||
|
||||
// helper for Point_inside_vertical_ray_cast
|
||||
class Transformed_tree_helper
|
||||
{
|
||||
typedef AABB_tree<AABBTraits> Tree;
|
||||
typedef CGAL::AABB_node<AABBTraits> Node;
|
||||
typedef Do_intersect_traversal_traits_with_transformation<AABBTraits, Kernel, SUPPORTS_ROTATION> Traversal_traits;
|
||||
|
||||
Traversal_traits m_tt;
|
||||
|
||||
public:
|
||||
|
||||
Transformed_tree_helper(const Traversal_traits& tt)
|
||||
: m_tt(tt)
|
||||
{}
|
||||
|
||||
Bbox_3 get_tree_bbox(const AABB_tree<AABBTraits>& tree) const
|
||||
{
|
||||
return m_tt.compute_transformed_bbox(tree.bbox());
|
||||
}
|
||||
|
||||
typename AABBTraits::Primitive::Datum
|
||||
get_primitive_datum(const typename AABBTraits::Primitive& primitive, const AABBTraits& traits) const
|
||||
{
|
||||
return internal::Primitive_helper<AABBTraits>::get_datum(primitive, traits).transform(m_tt.transformation());
|
||||
}
|
||||
|
||||
Bbox_3 get_node_bbox(const Node& node) const
|
||||
{
|
||||
return m_tt.compute_transformed_bbox(node.bbox());
|
||||
}
|
||||
};
|
||||
|
||||
Transformed_tree_helper get_helper() const
|
||||
{
|
||||
return Transformed_tree_helper(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_is_found;
|
||||
const AABBTraits* m_traits_ptr;
|
||||
Aff_transformation_3<Kernel> m_transfo;
|
||||
bool m_has_rotation;
|
||||
};
|
||||
|
||||
|
||||
// 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>
|
||||
{
|
||||
typedef typename AABBTraits::Primitive Primitive;
|
||||
typedef ::CGAL::AABB_node<AABBTraits> Node;
|
||||
typedef Traversal_traits_with_transformation_helper<AABBTraits, Kernel, SUPPORTS_ROTATION> Base;
|
||||
typedef Do_intersect_traversal_traits_with_transformation<AABBTraits, Kernel, SUPPORTS_ROTATION> Query_traversal_traits;
|
||||
|
||||
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,
|
||||
const Query_traversal_traits& 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)
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
}//end CGAL
|
||||
|
||||
#endif //CGAL_AABB_AABB_do_intersect_transform_traits_H
|
||||
|
|
@ -36,9 +36,32 @@
|
|||
namespace CGAL {
|
||||
namespace internal {
|
||||
|
||||
template <class AABBTree>
|
||||
struct Default_tree_helper
|
||||
{
|
||||
typedef typename AABBTree::AABB_traits AABB_traits;
|
||||
typedef typename CGAL::AABB_node<AABB_traits> Node;
|
||||
|
||||
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;
|
||||
|
|
@ -46,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
|
||||
{
|
||||
const typename Traits::Bounding_box& bbox = tree.bbox();
|
||||
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()
|
||||
|
|
@ -64,7 +93,7 @@ public:
|
|||
|
||||
//the direction of the vertical ray depends on the position of the point in the bbox
|
||||
//in order to limit the expected number of nodes visited.
|
||||
Ray query = ray_functor(point, vector_functor(0,0,(2*point.z() < tree.bbox().zmax()+tree.bbox().zmin()?-1:1)));
|
||||
Ray query = ray_functor(point, vector_functor(0,0,(2*point.z() < bbox.zmax()+bbox.zmin()?-1:1)));
|
||||
boost::optional<Bounded_side> res = is_inside_ray_tree_traversal<true>(query, tree);
|
||||
|
||||
if(res == boost::none)
|
||||
|
|
@ -88,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,node.bbox());
|
||||
return do_intersect(query,this->m_helper.get_node_bbox(node));
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -139,45 +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
|
||||
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() ) )
|
||||
|
|
@ -186,7 +183,6 @@ public:
|
|||
(orient_3==POSITIVE)
|
||||
)
|
||||
) return; //no intersection
|
||||
|
||||
|
||||
//position against first segment
|
||||
switch( orientation(p0,p1,q) ){
|
||||
|
|
|
|||
|
|
@ -0,0 +1,639 @@
|
|||
// Copyright (c) 2018 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
//
|
||||
//
|
||||
// Author(s) : Maxime Gimeno and Sebastien Loriot
|
||||
|
||||
|
||||
#ifndef CGAL_RIGID_TRIANGLE_MESH_COLLISION_DETECTION_H
|
||||
#define CGAL_RIGID_TRIANGLE_MESH_COLLISION_DETECTION_H
|
||||
|
||||
#include <CGAL/license/Polygon_mesh_processing/collision_detection.h>
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/Polygon_mesh_processing/internal/AABB_traversal_traits_with_transformation.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/property_map.h>
|
||||
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
|
||||
#ifndef CGAL_RMCD_CACHE_BOXES
|
||||
#define CGAL_RMCD_CACHE_BOXES 0
|
||||
#endif
|
||||
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
* \ingroup PkgPolygonMeshProcessing
|
||||
* This class provides methods to perform some intersection tests between triangle meshes
|
||||
* that undergo affine transformations (rotation, translation, and scaling).
|
||||
* Meshes are added to an internal set and are referenced using an id assigned when added to the set.
|
||||
* Note that the exact predicate framework applies on the meshes after having applied the transformation
|
||||
* to the coordinates of the points of the vertices of each mesh.
|
||||
*
|
||||
* @tparam TriangleMesh a model of `HalfedgeListGraph` and `FaceListGraph`
|
||||
* @tparam VertexPointMap a model of `ReadablePropertyMap` with the vertex descriptor of `TriangleMesh` as key type,
|
||||
* and a point from a CGAL Kernel as value type. %Default is the internal point property map
|
||||
* of `TriangleMesh` if it exists.
|
||||
* @tparam Kernel a model of CGAL Kernel. %Default is the kernel of the value type of `VertexPointMap` retrieved using
|
||||
* `Kernel_traits`.
|
||||
* @tparam AABBTree an `AABB_tree` that can containing faces of `TriangleMesh`. %Default is using `AABB_traits` with
|
||||
* `AABB_face_graph_triangle_primitive` as primitive type.
|
||||
* @tparam Has_rotation tag indicating whether the transformations applied to meshes may contain rotations (`Tag_true`)
|
||||
* or if only translations and scalings are applied (`Tag_false`). Some optimizations are
|
||||
* switch on in case there are no rotations.
|
||||
*/
|
||||
template <class TriangleMesh,
|
||||
class VertexPointMap = Default,
|
||||
class Kernel = Default,
|
||||
class AABBTree = Default,
|
||||
class Has_rotation = CGAL::Tag_true>
|
||||
class Rigid_triangle_mesh_collision_detection
|
||||
{
|
||||
// Vertex point map type
|
||||
typedef typename property_map_selector<TriangleMesh, boost::vertex_point_t
|
||||
>::const_type Default_vpm;
|
||||
typedef typename Default::Get<VertexPointMap, Default_vpm>::type Vpm;
|
||||
|
||||
// Kernel type
|
||||
typedef typename Kernel_traits<
|
||||
typename boost::property_traits<Vpm>::value_type>::Kernel Default_kernel;
|
||||
typedef typename Default::Get<Kernel, Default_kernel>::type K;
|
||||
|
||||
// AABB-tree type
|
||||
typedef AABB_face_graph_triangle_primitive<TriangleMesh,
|
||||
Vpm> Default_primitive;
|
||||
typedef AABB_traits<K, Default_primitive> Default_tree_traits;
|
||||
typedef CGAL::AABB_tree<Default_tree_traits> Default_tree;
|
||||
typedef typename Default::Get<AABBTree, Default_tree>::type Tree;
|
||||
typedef typename Tree::AABB_traits Tree_traits;
|
||||
|
||||
// Transformed Tree traversal traits
|
||||
typedef Do_intersect_traversal_traits_with_transformation<Tree_traits,
|
||||
K,
|
||||
Has_rotation>
|
||||
Traversal_traits;
|
||||
|
||||
// Data members
|
||||
std::vector<bool> m_own_aabb_trees;
|
||||
std::vector<Tree*> m_aabb_trees;
|
||||
std::vector<bool> m_is_closed;
|
||||
std::vector< std::vector<typename K::Point_3> > m_points_per_cc;
|
||||
std::vector<Traversal_traits> m_traversal_traits;
|
||||
std::size_t m_free_id; // position in m_id_pool of the first free element
|
||||
std::vector<std::size_t> m_id_pool; // 0-> m_id_pool-1 are valid mesh ids
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
boost::dynamic_bitset<> m_bboxes_is_invalid;
|
||||
std::vector<Bbox_3> m_bboxes;
|
||||
#endif
|
||||
|
||||
// internal functions
|
||||
std::size_t get_id_for_new_mesh()
|
||||
{
|
||||
if (m_free_id==m_id_pool.size())
|
||||
{
|
||||
m_id_pool.push_back(m_free_id);
|
||||
++m_free_id;
|
||||
m_own_aabb_trees.resize(m_free_id);
|
||||
m_aabb_trees.resize(m_free_id, NULL);
|
||||
m_is_closed.resize(m_free_id);
|
||||
m_points_per_cc.resize(m_free_id);
|
||||
m_traversal_traits.resize(m_free_id);
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
m_bboxes.resize(m_free_id);
|
||||
m_bboxes_is_invalid.resize(m_free_id, true);
|
||||
#endif
|
||||
return m_id_pool.back();
|
||||
}
|
||||
return m_id_pool[m_free_id++];
|
||||
}
|
||||
|
||||
template <class NamedParameters>
|
||||
void add_cc_points(const TriangleMesh& tm, std::size_t id, const NamedParameters& np)
|
||||
{
|
||||
collect_one_point_per_connected_component(tm, m_points_per_cc[id], np);
|
||||
}
|
||||
|
||||
// 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) const
|
||||
{
|
||||
typename K::Construct_ray_3 ray_functor;
|
||||
typename K::Construct_vector_3 vector_functor;
|
||||
typedef typename Traversal_traits::Transformed_tree_helper Helper;
|
||||
|
||||
BOOST_FOREACH(const typename K::Point_3& q, m_points_per_cc[id_B])
|
||||
{
|
||||
if( internal::Point_inside_vertical_ray_cast<K, 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;
|
||||
}
|
||||
|
||||
// this function expects a protector was initialized
|
||||
bool does_A_intersect_B(std::size_t id_A, std::size_t id_B) const
|
||||
{
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
if (!do_overlap(m_bboxes[id_B], m_bboxes[id_A])) continue;
|
||||
#endif
|
||||
|
||||
Do_intersect_traversal_traits_for_two_trees<Tree_traits, K, Has_rotation> traversal_traits(
|
||||
m_aabb_trees[id_B]->traits(), m_traversal_traits[id_B].transformation(), m_traversal_traits[id_A]);
|
||||
m_aabb_trees[id_B]->traversal(*m_aabb_trees[id_A], traversal_traits);
|
||||
return traversal_traits.is_intersection_found();
|
||||
}
|
||||
|
||||
public:
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
/// The AABB_tree type representing the triangles of each input mesh
|
||||
typedef unspecified_type AABB_tree;
|
||||
/// The vertex point map type used with `TriangleMesh`
|
||||
typedef unspecified_type Vertex_point_map;
|
||||
#else
|
||||
typedef Tree AABB_tree;
|
||||
typedef Vpm Vertex_point_map;
|
||||
#endif
|
||||
/// Point type
|
||||
typedef typename boost::property_traits<Vertex_point_map>::value_type Point_3;
|
||||
|
||||
Rigid_triangle_mesh_collision_detection()
|
||||
: m_free_id(0)
|
||||
{}
|
||||
|
||||
~Rigid_triangle_mesh_collision_detection()
|
||||
{
|
||||
for (std::size_t k=0; k<m_free_id; ++k)
|
||||
{
|
||||
std::size_t id = m_id_pool[k];
|
||||
if (m_own_aabb_trees[id]) delete m_aabb_trees[id];
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* adds mesh `tm` to the set of meshes to be considered for intersection.
|
||||
*
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* \return the id of `tm` used to refer to that mesh.
|
||||
*
|
||||
* @param tm triangulated surface mesh to add
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map}
|
||||
* a property map containing the index of each face of `tm`. It must be initialized
|
||||
* and the value must be unique per face and in the range `[0, num_faces(tm)[`.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{apply_per_connected_component}
|
||||
* if `false`, `tm` is assumed to have only one connected component, avoiding
|
||||
* the extraction of connected components. Default is `true`.
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*/
|
||||
template <class NamedParameters>
|
||||
std::size_t add_mesh(const TriangleMesh& tm,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
// handle vpm
|
||||
using Polygon_mesh_processing::GetVertexPointMap;
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::const_type Local_vpm;
|
||||
CGAL_USE_TYPE(Local_vpm);
|
||||
CGAL_assertion_code(
|
||||
static const bool same_vpm = (boost::is_same<Local_vpm,Vpm>::value); )
|
||||
CGAL_static_assertion(same_vpm);
|
||||
|
||||
Vpm vpm =
|
||||
boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, tm) );
|
||||
// now add the mesh
|
||||
std::size_t id = get_id_for_new_mesh();
|
||||
CGAL_assertion( m_aabb_trees[id] == NULL );
|
||||
m_is_closed[id] = is_closed(tm);
|
||||
m_own_aabb_trees[id] = true;
|
||||
Tree* t = new Tree(boost::begin(faces(tm)), boost::end(faces(tm)), tm, vpm);
|
||||
t->build();
|
||||
m_aabb_trees[id] = t;
|
||||
m_traversal_traits[id] = Traversal_traits(m_aabb_trees[id]->traits());
|
||||
add_cc_points(tm, id, np);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* adds an instance of a triangulated surface mesh using an external tree of its faces.
|
||||
* \warning The tree is not copied and the lifetime of `tree` must be longer than that of this class.
|
||||
*
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* \return the id of `tm` used to refer to that mesh.
|
||||
*
|
||||
* @param tree an AABB-tree of faces of a mesh
|
||||
* @param tm triangulated surface mesh
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map}
|
||||
* a property map containing the index of each face of `tm`. It must be initialized
|
||||
* and the value must be unique per face and in the range `[0, num_faces(tm)[`.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{apply_per_connected_component}
|
||||
* if `false`, `tm` is assumed to have only one connected component, avoiding
|
||||
* the extraction of connected components. Default is `true`.
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*/
|
||||
template <class NamedParameters>
|
||||
std::size_t add_mesh(const AABB_tree& tree, const TriangleMesh& tm, const NamedParameters& np)
|
||||
{
|
||||
std::size_t id = get_id_for_new_mesh();
|
||||
CGAL_assertion( m_aabb_trees[id] == NULL );
|
||||
m_is_closed[id] = is_closed(tm);
|
||||
m_own_aabb_trees[id] = false ;
|
||||
m_aabb_trees[id] = const_cast<Tree*>(&tree);
|
||||
m_traversal_traits[id] = Traversal_traits(m_aabb_trees[id]->traits());
|
||||
collect_one_point_per_connected_component(tm, m_points_per_cc[id], np);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* sets the transformation associated to a mesh identified by its id in the set.
|
||||
*/
|
||||
void set_transformation(std::size_t mesh_id, const Aff_transformation_3<K>& aff_trans)
|
||||
{
|
||||
CGAL_assertion(m_aabb_trees[mesh_id] != NULL);
|
||||
m_traversal_traits[mesh_id].set_transformation(aff_trans);
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
m_bboxes_is_invalid.set(mesh_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
void update_bboxes()
|
||||
{
|
||||
// protector is supposed to have been set
|
||||
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]=m_traversal_traits[i].get_helper().get_tree_bbox(*m_aabb_trees[i]);
|
||||
}
|
||||
m_bboxes_is_invalid.reset();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* returns a vector of the ids of meshes within `ids` that have at least a face
|
||||
* intersecting a face of the mesh with id `mesh_id`.
|
||||
* If `mesh_id` is in `ids` it is not reported.
|
||||
* \tparam MeshIdRange a range of ids convertible to `std::size_t`.
|
||||
*/
|
||||
template <class MeshIdRange>
|
||||
std::vector<std::size_t>
|
||||
get_all_intersections(std::size_t mesh_id, const MeshIdRange& ids) const
|
||||
{
|
||||
CGAL_assertion(m_aabb_trees[mesh_id] != NULL);
|
||||
CGAL::Interval_nt_advanced::Protector protector;
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
update_bboxes();
|
||||
#endif
|
||||
std::vector<std::size_t> res;
|
||||
|
||||
// TODO: use a non-naive version
|
||||
BOOST_FOREACH(std::size_t k, ids)
|
||||
{
|
||||
CGAL_assertion(m_aabb_trees[k] != NULL);
|
||||
if(k==mesh_id) continue;
|
||||
|
||||
if (does_A_intersect_B(mesh_id, k))
|
||||
res.push_back(k);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* returns a vector of the ids of meshes in the set that have at least a face
|
||||
* intersecting a face of the mesh with id `mesh_id`
|
||||
*/
|
||||
std::vector<std::size_t>
|
||||
get_all_intersections(std::size_t mesh_id) const
|
||||
{
|
||||
return get_all_intersections(
|
||||
mesh_id,
|
||||
make_range(m_id_pool.begin(),m_id_pool.begin()+m_free_id) );
|
||||
}
|
||||
|
||||
/*!
|
||||
* returns a vector of the ids of meshes within `ids` that are intersecting with the mesh with id `mesh_id`,
|
||||
* considering volume inclusions for closed meshes.
|
||||
* More precisely, if at least one face of a mesh with id `i` intersects a face
|
||||
* of the mesh with id `mesh_id`, the pair `(i, false)` is put in the output vector.
|
||||
* If there is no face intersection, but at least one of the meshes with ids `i` and `mesh_id` is closed,
|
||||
* and at least one connected component is included in the bounded volume defined by a closed mesh then the pair
|
||||
* `(i, true)` is put in the output vector (independently of mesh `i` or `mesh_id` being the one including the other).
|
||||
* The inclusion test is done using `Side_of_triangle_mesh`, in particular surface orientation is ignored and only the
|
||||
* nesting level of connected components defines a bounded volume. If a mesh has some self-intersection the inclusion
|
||||
* test may return incorrect results.
|
||||
* If `mesh_id` is in `ids` it is not reported.
|
||||
*
|
||||
* \tparam MeshIdRange a range of ids convertible to `std::size_t`.
|
||||
*
|
||||
* \note If a mesh is made of several connected components and at least one component is not closed,
|
||||
* then no inclusion test will be made even if some components are closed.
|
||||
*
|
||||
*/
|
||||
template <class MeshIdRange>
|
||||
std::vector<std::pair<std::size_t, bool> >
|
||||
get_all_intersections_and_inclusions(std::size_t mesh_id, const MeshIdRange& ids) const
|
||||
{
|
||||
CGAL_assertion(m_aabb_trees[mesh_id] != NULL);
|
||||
CGAL::Interval_nt_advanced::Protector protector;
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
update_bboxes();
|
||||
#endif
|
||||
std::vector<std::pair<std::size_t, bool> > res;
|
||||
|
||||
// TODO: use a non-naive version
|
||||
BOOST_FOREACH(std::size_t k, ids)
|
||||
{
|
||||
CGAL_assertion(m_aabb_trees[k] != NULL);
|
||||
if(k==mesh_id) continue;
|
||||
|
||||
if (does_A_intersect_B(mesh_id, k))
|
||||
res.push_back(std::make_pair(k, false));
|
||||
else{
|
||||
if (m_is_closed[mesh_id])
|
||||
{
|
||||
if ( does_A_contains_a_CC_of_B(mesh_id, k) )
|
||||
{
|
||||
res.push_back(std::make_pair(k, true));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (m_is_closed[k])
|
||||
{
|
||||
if ( does_A_contains_a_CC_of_B(k, mesh_id) )
|
||||
{
|
||||
res.push_back(std::make_pair(k, true));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*!
|
||||
* returns a vector of the ids of meshes in the set that are intersecting with the mesh with id `mesh_id`,
|
||||
* considering volume inclusions for closed meshes.
|
||||
* See the previous overload for details.
|
||||
*/
|
||||
std::vector<std::pair<std::size_t, bool> >
|
||||
get_all_intersections_and_inclusions(std::size_t mesh_id) const
|
||||
{
|
||||
return get_all_intersections_and_inclusions(mesh_id,
|
||||
make_range(m_id_pool.begin(),m_id_pool.begin()+m_free_id) );
|
||||
}
|
||||
|
||||
/// \name Memory Management
|
||||
/*!
|
||||
* increases the capacity of data structures used internally, `size` being the number of meshes expected to be added.
|
||||
*/
|
||||
void reserve(std::size_t size)
|
||||
{
|
||||
m_own_aabb_trees.reserve(size);
|
||||
m_aabb_trees.reserve(size);
|
||||
m_is_closed.reserve(size);
|
||||
m_points_per_cc.reserve(size);
|
||||
m_traversal_traits.reserve(size);
|
||||
#if CGAL_RMCD_CACHE_BOXES
|
||||
m_bboxes.reserve(size);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* removes the mesh with id `mesh_id` from the set, the indices of other meshes are kept unchanged.
|
||||
*/
|
||||
void remove_mesh(std::size_t mesh_id)
|
||||
{
|
||||
std::vector<std::size_t>::iterator itf =
|
||||
std::find(m_id_pool.begin(), m_id_pool.begin()+m_free_id, mesh_id);
|
||||
if (itf == m_id_pool.begin()+m_free_id) return;
|
||||
|
||||
if (m_own_aabb_trees[mesh_id]) delete m_aabb_trees[mesh_id];
|
||||
m_points_per_cc[mesh_id].clear();
|
||||
m_aabb_trees[mesh_id] = NULL;
|
||||
if (m_id_pool[m_free_id-1]!=mesh_id)
|
||||
std::swap(m_id_pool[m_free_id-1], *itf);
|
||||
--m_free_id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* returns the number of meshes in the set
|
||||
*/
|
||||
std::size_t size() const
|
||||
{
|
||||
return m_free_id;
|
||||
}
|
||||
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
/*!
|
||||
* returns the number of times `add_mesh()` was called minus the number of times `remove_mesh()` (with a valid mesh id) was called
|
||||
*/
|
||||
std::size_t size_of_garbage()
|
||||
{
|
||||
return m_id_pool.size() - m_free_id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* returns `false` if `mesh_id` corresponds to an id not used (removed and/or not affected), and `true` otherwise.
|
||||
*/
|
||||
bool is_valid_index(std::size_t mesh_id)
|
||||
{
|
||||
if (mesh_id >= m_id_pool.size()) return false;
|
||||
return m_aabb_trees[mesh_id] != NULL;
|
||||
}
|
||||
|
||||
/// \name Helper Static Function
|
||||
|
||||
/*!
|
||||
* fills `points` with one point per connected component of `tm`. This is a helper function
|
||||
* intended to be used before calling the `add_mesh()` overload taking an AABB-tree instead of a mesh
|
||||
* as input parameter.
|
||||
*
|
||||
* @tparam NamedParameters a sequence of \ref pmp_namedparameters "Named Parameters"
|
||||
*
|
||||
* @param tm input triangulated surface mesh
|
||||
* @param [out] points will contain one point per connected component of `tm`
|
||||
* @param np optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
|
||||
*
|
||||
* \cgalNamedParamsBegin
|
||||
* \cgalParamBegin{vertex_point_map}
|
||||
* the property map with the points associated to the vertices of `tm`.
|
||||
* If this parameter is omitted, an internal property map for
|
||||
* `CGAL::vertex_point_t` must be available in `TriangleMesh`
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{face_index_map}
|
||||
* a property map containing the index of each face of `tm`. It must be initialized
|
||||
* and the value must be unique per face and in the range `[0, num_faces(tm)[`.
|
||||
* \cgalParamEnd
|
||||
* \cgalParamBegin{apply_per_connected_component}
|
||||
* if `false`, `tm` is assumed to have only one connected component, avoiding
|
||||
* the extraction of connected components. %Default is `true`.
|
||||
* \cgalParamEnd
|
||||
* \cgalNamedParamsEnd
|
||||
*/
|
||||
template <class NamedParameters>
|
||||
static
|
||||
void collect_one_point_per_connected_component(
|
||||
const TriangleMesh& tm,
|
||||
std::vector<Point_3>& points,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
using Polygon_mesh_processing::GetVertexPointMap;
|
||||
using Polygon_mesh_processing::GetFaceIndexMap;
|
||||
|
||||
const bool maybe_several_cc =
|
||||
boost::choose_param(
|
||||
boost::get_param(np, internal_np::apply_per_connected_component), true);
|
||||
|
||||
typedef typename GetVertexPointMap<TriangleMesh,
|
||||
NamedParameters>::const_type Local_vpm;
|
||||
CGAL_USE_TYPE(Local_vpm);
|
||||
|
||||
CGAL_assertion_code(
|
||||
static const bool same_vpm = (boost::is_same<Local_vpm,Vpm>::value); )
|
||||
CGAL_static_assertion(same_vpm);
|
||||
|
||||
Vpm vpm =
|
||||
boost::choose_param(boost::get_param(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, tm) );
|
||||
|
||||
if (maybe_several_cc)
|
||||
{
|
||||
// used for face cc id map
|
||||
std::vector<std::size_t> cc_ids(num_faces(tm));
|
||||
|
||||
// face index map
|
||||
typedef typename GetFaceIndexMap<TriangleMesh,
|
||||
NamedParameters>::type Fid_map;
|
||||
|
||||
Fid_map fid_map =
|
||||
boost::choose_param(boost::get_param(np, internal_np::face_index),
|
||||
get_const_property_map(boost::face_index, tm));
|
||||
|
||||
std::size_t nb_cc =
|
||||
Polygon_mesh_processing::connected_components(
|
||||
tm, bind_property_maps(fid_map, make_property_map(cc_ids)),
|
||||
parameters::face_index_map(fid_map));
|
||||
if (nb_cc != 1)
|
||||
{
|
||||
typedef boost::graph_traits<TriangleMesh> GrTr;
|
||||
std::vector<typename GrTr::vertex_descriptor>
|
||||
vertex_per_cc(nb_cc, GrTr::null_vertex());
|
||||
|
||||
BOOST_FOREACH(typename GrTr::face_descriptor f, faces(tm))
|
||||
{
|
||||
std::size_t cc_id = cc_ids[get(fid_map, f)];
|
||||
if (vertex_per_cc[cc_id] == GrTr::null_vertex())
|
||||
{
|
||||
vertex_per_cc[cc_id] = target( halfedge(f, tm), tm);
|
||||
points.push_back( get(vpm, vertex_per_cc[cc_id]) );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// only one CC
|
||||
points.push_back( get(vpm, *boost::begin(vertices(tm))) );
|
||||
}
|
||||
|
||||
/*!
|
||||
* adds an instance of a triangulated surface mesh using an external tree of its faces.
|
||||
* \warning The tree is not copied and the lifetime of `tree` must be longer than that of this class.
|
||||
*
|
||||
* \return the id of the instance used to refer to that mesh.
|
||||
*
|
||||
* @param tree an AABB-tree of faces of a mesh
|
||||
* @param is_closed `true` is the mesh in `tree` is closed, and `false` otherwise.
|
||||
* \link is_closed() `CGAL::is_closed()` \endlink can be used for that purpose.
|
||||
* @param points_per_cc a vector containing one point of a vertex for each connected
|
||||
* component of the triangle surface mesh in `tree`
|
||||
*/
|
||||
std::size_t add_mesh(const AABB_tree& tree,
|
||||
bool is_closed,
|
||||
const std::vector<Point_3>& points_per_cc)
|
||||
{
|
||||
std::size_t id = get_id_for_new_mesh();
|
||||
CGAL_assertion( m_aabb_trees[id] == NULL );
|
||||
m_is_closed[id] = is_closed;
|
||||
m_own_aabb_trees[id] = false ;
|
||||
m_aabb_trees[id] = const_cast<Tree*>(&tree);
|
||||
m_traversal_traits[id] = Traversal_traits(m_aabb_trees[id]->traits());
|
||||
m_points_per_cc[id] = points_per_cc;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// versions without NP
|
||||
static
|
||||
void collect_one_point_per_connected_component(
|
||||
const TriangleMesh& tm,
|
||||
std::vector<typename K::Point_3>& points)
|
||||
{
|
||||
collect_one_point_per_connected_component(tm, points, parameters::all_default());
|
||||
}
|
||||
|
||||
std::size_t add_mesh(const TriangleMesh& tm)
|
||||
{
|
||||
return add_mesh(tm, parameters::all_default());
|
||||
}
|
||||
|
||||
std::size_t add_mesh(const AABB_tree& tree, const TriangleMesh& tm)
|
||||
{
|
||||
return add_mesh(tree, tm, parameters::all_default());
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // end of CGAL namespace
|
||||
|
||||
#undef CGAL_RMCD_CACHE_BOXES
|
||||
|
||||
#endif // CGAL_RIGID_TRIANGLE_MESH_COLLISION_DETECTION_H
|
||||
|
|
@ -103,6 +103,7 @@ endif()
|
|||
create_single_source_cgal_program("extrude_test.cpp")
|
||||
create_single_source_cgal_program("test_merging_border_vertices.cpp")
|
||||
create_single_source_cgal_program("test_shape_predicates.cpp")
|
||||
create_single_source_cgal_program("test_pmp_collision_detection.cpp")
|
||||
|
||||
if( TBB_FOUND )
|
||||
CGAL_target_use_TBB(test_pmp_distance)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
#include <CGAL/Rigid_triangle_mesh_collision_detection.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef CGAL::Surface_mesh<K::Point_3> Surface_mesh;
|
||||
typedef CGAL::Polyhedron_3<K> Polyhedron_3;
|
||||
namespace params = CGAL::parameters;
|
||||
|
||||
void test_remove()
|
||||
{
|
||||
std::cout << "test_remove()" << std::endl;
|
||||
Surface_mesh sm;
|
||||
CGAL::Rigid_triangle_mesh_collision_detection<Surface_mesh> collision_detection;
|
||||
collision_detection.add_mesh(sm); // 0
|
||||
collision_detection.add_mesh(sm); // 1
|
||||
collision_detection.add_mesh(sm); // 2
|
||||
collision_detection.add_mesh(sm); // 3
|
||||
collision_detection.add_mesh(sm); // 4
|
||||
|
||||
assert( collision_detection.is_valid_index(0) );
|
||||
assert( collision_detection.is_valid_index(1) );
|
||||
assert( collision_detection.is_valid_index(2) );
|
||||
assert( collision_detection.is_valid_index(3) );
|
||||
assert( collision_detection.is_valid_index(4) );
|
||||
assert(!collision_detection.is_valid_index(5) );
|
||||
|
||||
assert(collision_detection.size() == 5);
|
||||
|
||||
collision_detection.remove_mesh(4);
|
||||
assert(collision_detection.size() == 4);
|
||||
assert(!collision_detection.is_valid_index(4));
|
||||
|
||||
std::size_t id = collision_detection.add_mesh(sm);
|
||||
assert(id == 4);
|
||||
|
||||
collision_detection.remove_mesh(2);
|
||||
assert(collision_detection.size() == 4);
|
||||
assert(!collision_detection.is_valid_index(2));
|
||||
id = collision_detection.add_mesh(sm);
|
||||
assert(id == 2);
|
||||
|
||||
assert( collision_detection.is_valid_index(0) );
|
||||
assert( collision_detection.is_valid_index(1) );
|
||||
assert( collision_detection.is_valid_index(2) );
|
||||
assert( collision_detection.is_valid_index(3) );
|
||||
assert( collision_detection.is_valid_index(4) );
|
||||
|
||||
collision_detection.remove_mesh(3);
|
||||
assert( collision_detection.size()==4);
|
||||
assert( collision_detection.size_of_garbage()==1);
|
||||
collision_detection.remove_mesh(3);
|
||||
assert( collision_detection.size()==4);
|
||||
assert( collision_detection.size_of_garbage()==1);
|
||||
collision_detection.remove_mesh(2);
|
||||
assert( collision_detection.size()==3);
|
||||
assert( collision_detection.size_of_garbage()==2);
|
||||
collision_detection.remove_mesh(1);
|
||||
assert( collision_detection.size()==2);
|
||||
assert( collision_detection.size_of_garbage()==3);
|
||||
collision_detection.remove_mesh(4);
|
||||
assert( collision_detection.size()==1);
|
||||
assert( collision_detection.size_of_garbage()==4);
|
||||
collision_detection.remove_mesh(0);
|
||||
assert( collision_detection.size()==0);
|
||||
assert( collision_detection.size_of_garbage()==5);
|
||||
}
|
||||
|
||||
template <class TriangleMesh, class Index>
|
||||
void test_intersections(Index index, const char* type)
|
||||
{
|
||||
std::cout << "test_intersections<"<<type<<">()" << std::endl;
|
||||
TriangleMesh tm1, tm2, tm3;
|
||||
std::ifstream input("data/small_spheres.off");
|
||||
assert(input);
|
||||
input >> tm1;
|
||||
input.close();
|
||||
input.open("data/blobby.off");
|
||||
assert(input);
|
||||
input >> tm2;
|
||||
input.close();
|
||||
input.open("data-coref/large_cube_coplanar.off");
|
||||
assert(input);
|
||||
input >> tm3;
|
||||
input.close();
|
||||
|
||||
CGAL::Rigid_triangle_mesh_collision_detection<TriangleMesh> collision_detection;
|
||||
collision_detection.add_mesh(tm1, params::face_index_map(get(index, tm1))); // 0
|
||||
// add tm1 using an external tree
|
||||
typename CGAL::Rigid_triangle_mesh_collision_detection<TriangleMesh>::AABB_tree
|
||||
tm1_tree(boost::begin(faces(tm1)), boost::end(faces(tm1)), tm1);
|
||||
collision_detection.add_mesh(tm1_tree, tm1, params::face_index_map(get(index, tm1))); // 1 small_spheres
|
||||
collision_detection.add_mesh(tm2, params::face_index_map(get(index, tm2))); // 2 blobby
|
||||
collision_detection.add_mesh(tm3, params::face_index_map(get(index, tm3))); // 3 large_cube_coplanar
|
||||
// pool is 0 1 2 3
|
||||
collision_detection.remove_mesh(0);
|
||||
// pool is now 3 1 2
|
||||
std::vector<std::size_t> inter_res;
|
||||
std::vector< std::pair<std::size_t, bool> > inter_and_inclus_res;
|
||||
|
||||
// spheres intersects both cube and blobby
|
||||
inter_res = collision_detection.get_all_intersections(1);
|
||||
assert(inter_res.size() == 2);
|
||||
assert(inter_res[0] == 3);
|
||||
assert(inter_res[1] == 2);
|
||||
|
||||
// blobby intersects only spheres
|
||||
inter_res = collision_detection.get_all_intersections(2);
|
||||
assert(inter_res.size() == 1);
|
||||
assert(inter_res[0] == 1);
|
||||
|
||||
// blobby is included into cube
|
||||
inter_and_inclus_res = collision_detection.get_all_intersections_and_inclusions(2);
|
||||
assert(inter_and_inclus_res.size() == 2);
|
||||
assert(inter_and_inclus_res[0].first == 3 && inter_and_inclus_res[0].second);
|
||||
assert(inter_and_inclus_res[1].first == 1 && !inter_and_inclus_res[1].second);
|
||||
|
||||
// set transformations
|
||||
K::Aff_transformation_3 tm1_transf(-0.22115682390903474, 0.97263618730220114, 0.071193443439028392,
|
||||
-2.3805504333121519, 0.37717228816945586, 0.017983434697950496,
|
||||
0.92596849898551192, -4.6543355030238258, 0.89935016777420218,
|
||||
0.23163644624001295, -0.37082857562196114, -5.4867495857613582);
|
||||
|
||||
K::Aff_transformation_3 tm2_transf(-0.10062050938738221, -0.92610032901754502, -0.36361200981845854,
|
||||
-2.1218726603809985, 0.98718082597554757, -0.13844084127856282,
|
||||
0.079423864753106477, -4.6627185424110094, -0.1238932198179533,
|
||||
-0.35095913445824267, 0.92815847570523291, -5.349009707055858);
|
||||
|
||||
K::Aff_transformation_3 tm3_transf(0.8523140340417823, -0.41651563577194606, -0.3163471392835962,
|
||||
-2.0549216027623891, 0.34883891716890358, 0.90335137983769587,
|
||||
-0.24953495629622252, -5.8394794922248607, 0.3897078357485903,
|
||||
0.10232795171810326, 0.91523592207328008, -5.2436990668816268);
|
||||
|
||||
collision_detection.set_transformation(1, tm1_transf);
|
||||
collision_detection.set_transformation(2, tm2_transf);
|
||||
collision_detection.set_transformation(3, tm3_transf);
|
||||
|
||||
// spheres intersects blobby
|
||||
inter_res = collision_detection.get_all_intersections(1);
|
||||
assert(inter_res.size() == 1);
|
||||
assert(inter_res[0] == 2);
|
||||
|
||||
// blobby intersect spheres and cube
|
||||
inter_res = collision_detection.get_all_intersections(2);
|
||||
assert(inter_res.size() == 2);
|
||||
assert(inter_res[0] == 3);
|
||||
assert(inter_res[1] == 1);
|
||||
|
||||
// cube contains one CC of spheres
|
||||
inter_and_inclus_res = collision_detection.get_all_intersections_and_inclusions(3);
|
||||
assert(inter_and_inclus_res.size() == 2);
|
||||
assert(inter_and_inclus_res[0].first == 1 && inter_and_inclus_res[0].second);
|
||||
assert(inter_and_inclus_res[1].first == 2 && !inter_and_inclus_res[1].second);
|
||||
|
||||
// one CC of spheres is contained by cube
|
||||
inter_and_inclus_res = collision_detection.get_all_intersections_and_inclusions(1);
|
||||
assert(inter_and_inclus_res.size() == 2);
|
||||
assert(inter_and_inclus_res[0].first == 3 && inter_and_inclus_res[0].second);
|
||||
assert(inter_and_inclus_res[1].first == 2 && !inter_and_inclus_res[1].second);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_remove();
|
||||
test_intersections<Surface_mesh>(boost::face_index, "Surface_mesh");
|
||||
test_intersections<Polyhedron_3>(boost::face_external_index, "Polyhedron_3");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -278,6 +278,8 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND )
|
|||
add_item(scene_sm_shortest_path_item Plugins/Surface_mesh/Scene_polyhedron_shortest_path_item.cpp)
|
||||
target_link_libraries(scene_sm_shortest_path_item PUBLIC scene_surface_mesh_item_decorator scene_surface_mesh_item scene_polylines_item)
|
||||
|
||||
add_item(scene_movable_sm_item Plugins/AABB_tree/Scene_movable_sm_item.cpp)
|
||||
|
||||
if(EIGEN3_FOUND )
|
||||
add_item(scene_textured_polyhedron_item Scene_textured_polyhedron_item.cpp texture.cpp)
|
||||
add_item(scene_textured_surface_mesh_item Scene_textured_surface_mesh_item.cpp texture.cpp)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
include( polyhedron_demo_macros )
|
||||
|
||||
polyhedron_demo_plugin(do_trees_intersect_plugin Do_trees_intersect_plugin)
|
||||
target_link_libraries(do_trees_intersect_plugin PUBLIC scene_surface_mesh_item scene_movable_sm_item)
|
||||
|
||||
polyhedron_demo_plugin(cut_plugin Cut_plugin )
|
||||
target_link_libraries(cut_plugin PUBLIC scene_polyhedron_item scene_surface_mesh_item scene_basic_objects scene_color_ramp)
|
||||
if(TBB_FOUND)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,348 @@
|
|||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include "Messages_interface.h"
|
||||
#include <CGAL/Three/Three.h>
|
||||
#include "Scene_surface_mesh_item.h"
|
||||
#include "Scene_movable_sm_item.h"
|
||||
#include <CGAL/Three/Scene_item_rendering_helper.h>
|
||||
#include <CGAL/Three/Triangle_container.h>
|
||||
#include <CGAL/Three/Edge_container.h>
|
||||
#include <CGAL/Three/Point_container.h>
|
||||
#include <CGAL/Rigid_triangle_mesh_collision_detection.h>
|
||||
#include "Scene.h"
|
||||
|
||||
class DoTreesIntersectplugin:
|
||||
public QObject,
|
||||
public CGAL::Three::Polyhedron_demo_plugin_interface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
|
||||
Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0")
|
||||
public:
|
||||
|
||||
bool eventFilter(QObject *, QEvent *event) Q_DECL_OVERRIDE
|
||||
{
|
||||
if(event->type() != QEvent::KeyPress)
|
||||
return false;
|
||||
QKeyEvent * e = static_cast<QKeyEvent*>(event);
|
||||
if (e->key()==Qt::Key_W){
|
||||
do_transparency = !do_transparency;
|
||||
change_display();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool applicable(QAction*) const Q_DECL_OVERRIDE
|
||||
{
|
||||
if(scene->selectionIndices().size() <2)
|
||||
return false;
|
||||
Q_FOREACH(Scene::Item_id i, scene->selectionIndices())
|
||||
{
|
||||
if(! qobject_cast<Scene_surface_mesh_item*>(scene->item(i)))
|
||||
return false;
|
||||
}
|
||||
return (! group_item);
|
||||
}
|
||||
|
||||
QList<QAction*> actions() const Q_DECL_OVERRIDE
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
|
||||
|
||||
void init(QMainWindow* mw, CGAL::Three::Scene_interface* sc, Messages_interface* mi) Q_DECL_OVERRIDE
|
||||
{
|
||||
this->messageInterface = mi;
|
||||
this->scene = sc;
|
||||
this->mw = mw;
|
||||
QAction *actionCreateTrees= new QAction(QString("Collision Detection"), mw);
|
||||
actionCreateTrees->setProperty("subMenuName", "Polygon Mesh Processing");
|
||||
actionCreateTrees->setProperty("submenuName", "AABB_tree");
|
||||
if(actionCreateTrees) {
|
||||
connect(actionCreateTrees, SIGNAL(triggered()),
|
||||
this, SLOT(start()));
|
||||
_actions << actionCreateTrees;
|
||||
}
|
||||
do_transparency = false;
|
||||
group_item = nullptr;
|
||||
}
|
||||
private Q_SLOTS:
|
||||
void start()
|
||||
{
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
Q_FOREACH(Scene::Item_id i, scene->selectionIndices())
|
||||
{
|
||||
Scene_surface_mesh_item* item=qobject_cast<Scene_surface_mesh_item*>(scene->item(i));
|
||||
if (!CGAL::is_triangle_mesh(*item->face_graph()))
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
QMessageBox::warning(mw, "Error", QString("%1 is not pure triangle. Aborting.").arg(item->name()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
group_item = new Scene_group_item("Test Items");
|
||||
connect(group_item, &Scene_group_item::aboutToBeDestroyed,
|
||||
this, [this](){
|
||||
items.clear();
|
||||
if(col_det)
|
||||
delete col_det;
|
||||
col_det = nullptr;
|
||||
group_item = nullptr;});
|
||||
group_item->setScene(scene);
|
||||
|
||||
scene->addItem(group_item);
|
||||
Q_FOREACH(Scene::Item_id i, scene->selectionIndices())
|
||||
{
|
||||
Scene_surface_mesh_item* item=qobject_cast<Scene_surface_mesh_item*>(scene->item(i));
|
||||
connect(item, &Scene_surface_mesh_item::aboutToBeDestroyed,
|
||||
this, &DoTreesIntersectplugin::cleanup);
|
||||
|
||||
CGAL::qglviewer::Vec pos((item->bbox().min(0) + item->bbox().max(0))/2.0,
|
||||
(item->bbox().min(1) + item->bbox().max(1))/2.0,
|
||||
(item->bbox().min(2) + item->bbox().max(2))/2.0);
|
||||
|
||||
Scene_movable_sm_item* mov_item = new Scene_movable_sm_item(pos,item->face_graph(),"");
|
||||
connect(mov_item->manipulatedFrame(), &CGAL::qglviewer::ManipulatedFrame::modified,
|
||||
this, &DoTreesIntersectplugin::update_trees);
|
||||
mov_item->setName(item->name());
|
||||
if(do_transparency)
|
||||
{
|
||||
mov_item->setRenderingMode(Flat);
|
||||
mov_item->setAlpha(120);
|
||||
}
|
||||
else
|
||||
{
|
||||
mov_item->setRenderingMode(Wireframe);
|
||||
}
|
||||
item->setVisible(false);
|
||||
items.push_back(mov_item);
|
||||
scene->addItem(mov_item);
|
||||
scene->changeGroup(mov_item, group_item);
|
||||
group_item->lockChild(mov_item);
|
||||
mov_item->redraw();
|
||||
}
|
||||
scene->setSelectedItem(group_item->getChildren().last());
|
||||
connect(static_cast<Scene*>(scene), &Scene::itemIndexSelected,
|
||||
this, &DoTreesIntersectplugin::update_trees);
|
||||
col_det = new CGAL::Rigid_triangle_mesh_collision_detection<SMesh>();
|
||||
col_det->reserve(items.size());
|
||||
Q_FOREACH(Scene_movable_sm_item* item, items)
|
||||
{
|
||||
col_det->add_mesh(*item->getFaceGraph());
|
||||
}
|
||||
init_trees();
|
||||
static_cast<CGAL::Three::Viewer_interface*>(
|
||||
CGAL::QGLViewer::QGLViewerPool().first())->installEventFilter(this);
|
||||
QApplication::restoreOverrideCursor();
|
||||
messageInterface->information("Press `W` to switch between Wireframe and Transparency mode.");
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void init_trees()
|
||||
{
|
||||
if(items.empty())
|
||||
return;
|
||||
Q_FOREACH(Scene_movable_sm_item* item, items)
|
||||
item->setColor(QColor(Qt::green));
|
||||
|
||||
CGAL::Three::Viewer_interface* viewer = static_cast<CGAL::Three::Viewer_interface*>(
|
||||
CGAL::QGLViewer::QGLViewerPool().first());
|
||||
Scene_movable_sm_item* sel_item = qobject_cast<Scene_movable_sm_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
if(!sel_item)
|
||||
return;
|
||||
|
||||
std::size_t mesh_id = 0;
|
||||
std::size_t sel_id = 0;
|
||||
Q_FOREACH(Scene_movable_sm_item* item, items)
|
||||
{
|
||||
if(item == sel_item)
|
||||
{
|
||||
sel_id = mesh_id;
|
||||
break;
|
||||
}
|
||||
++mesh_id;
|
||||
}
|
||||
mesh_id = 0;
|
||||
Q_FOREACH(Scene_movable_sm_item* item, items)
|
||||
{
|
||||
if(mesh_id == sel_id)
|
||||
{
|
||||
++mesh_id;
|
||||
item->setColor(QColor(255,184,61));
|
||||
prev_ids.push_back(sel_id);
|
||||
continue;
|
||||
}
|
||||
const double* matrix = item->manipulatedFrame()->matrix();
|
||||
item->setFMatrix(matrix);
|
||||
EPICK::Aff_transformation_3 translation(CGAL::TRANSLATION, -EPICK::Vector_3(item->center().x,
|
||||
item->center().y,
|
||||
item->center().z));
|
||||
EPICK::Aff_transformation_3 rota(
|
||||
matrix[0], matrix[4], matrix[8],matrix[12],
|
||||
matrix[1], matrix[5], matrix[9],matrix[13],
|
||||
matrix[2], matrix[6], matrix[10],matrix[14]);
|
||||
EPICK::Aff_transformation_3 transfo =
|
||||
rota*translation;
|
||||
|
||||
col_det->set_transformation(mesh_id++, transfo);
|
||||
|
||||
if(do_transparency)
|
||||
{
|
||||
item->setRenderingMode(Flat);
|
||||
item->setAlpha(120);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setRenderingMode(Wireframe);
|
||||
}
|
||||
item->itemChanged();
|
||||
}
|
||||
const double* matrix = sel_item->manipulatedFrame()->matrix();
|
||||
sel_item->setFMatrix(matrix);
|
||||
EPICK::Aff_transformation_3 translation(CGAL::TRANSLATION, -EPICK::Vector_3(sel_item->center().x,
|
||||
sel_item->center().y,
|
||||
sel_item->center().z));
|
||||
EPICK::Aff_transformation_3 rota(
|
||||
matrix[0], matrix[4], matrix[8],matrix[12],
|
||||
matrix[1], matrix[5], matrix[9],matrix[13],
|
||||
matrix[2], matrix[6], matrix[10],matrix[14]);
|
||||
EPICK::Aff_transformation_3 transfo =
|
||||
rota*translation;
|
||||
col_det->set_transformation(sel_id, transfo);
|
||||
std::vector<std::pair<std::size_t, bool> > inter_and_incl
|
||||
= col_det->get_all_intersections_and_inclusions(sel_id);
|
||||
for(std::size_t i=0; i<inter_and_incl.size(); ++i)
|
||||
{
|
||||
std::size_t id = inter_and_incl[i].first;
|
||||
bool including = inter_and_incl[i].second;
|
||||
if(including)
|
||||
items[id]->setColor(QColor(Qt::blue));
|
||||
else
|
||||
items[id]->setColor(QColor(Qt::red));
|
||||
prev_ids.push_back(id);
|
||||
}
|
||||
if(do_transparency)
|
||||
{
|
||||
sel_item->setRenderingMode(Flat);
|
||||
sel_item->setAlpha(120);
|
||||
}
|
||||
else
|
||||
{
|
||||
sel_item->setRenderingMode(Wireframe);
|
||||
}
|
||||
sel_item->itemChanged();
|
||||
viewer->update();
|
||||
}
|
||||
|
||||
void update_trees()
|
||||
{
|
||||
if(items.empty())
|
||||
return;
|
||||
CGAL::Three::Viewer_interface* viewer = static_cast<CGAL::Three::Viewer_interface*>(
|
||||
CGAL::QGLViewer::QGLViewerPool().first());
|
||||
Scene_movable_sm_item* sel_item = qobject_cast<Scene_movable_sm_item*>(scene->item(scene->mainSelectionIndex()));
|
||||
if(!sel_item)
|
||||
return;
|
||||
|
||||
std::size_t mesh_id = 0;
|
||||
std::size_t sel_id = 0;
|
||||
Q_FOREACH(Scene_movable_sm_item* item, items)
|
||||
{
|
||||
if(item == sel_item)
|
||||
{
|
||||
sel_id = mesh_id;
|
||||
++mesh_id;
|
||||
item->setColor(QColor(255,184,61));
|
||||
break;
|
||||
}
|
||||
++mesh_id;
|
||||
}
|
||||
for(std::size_t i = 0; i< prev_ids.size(); ++i)
|
||||
{
|
||||
std::size_t id = prev_ids[i];
|
||||
if(id == sel_id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Scene_movable_sm_item* item = items[id];
|
||||
item->setColor(QColor(Qt::green));
|
||||
item->itemChanged();
|
||||
}
|
||||
prev_ids.clear();
|
||||
const double* matrix = sel_item->manipulatedFrame()->matrix();
|
||||
sel_item->setFMatrix(matrix);
|
||||
|
||||
EPICK::Aff_transformation_3 translation(CGAL::TRANSLATION, -EPICK::Vector_3(sel_item->center().x,
|
||||
sel_item->center().y,
|
||||
sel_item->center().z));
|
||||
EPICK::Aff_transformation_3 rota(
|
||||
matrix[0], matrix[4], matrix[8],matrix[12],
|
||||
matrix[1], matrix[5], matrix[9],matrix[13],
|
||||
matrix[2], matrix[6], matrix[10],matrix[14]);
|
||||
EPICK::Aff_transformation_3 transfo =
|
||||
rota*translation;
|
||||
col_det->set_transformation(sel_id, transfo);
|
||||
std::vector<std::pair<std::size_t, bool> > inter_and_incl
|
||||
= col_det->get_all_intersections_and_inclusions(sel_id);
|
||||
for(std::size_t i=0; i<inter_and_incl.size(); ++i)
|
||||
{
|
||||
std::size_t id = inter_and_incl[i].first;
|
||||
bool including = inter_and_incl[i].second;
|
||||
if(including)
|
||||
items[id]->setColor(QColor(Qt::blue));
|
||||
else
|
||||
items[id]->setColor(QColor(Qt::red));
|
||||
prev_ids.push_back(id);
|
||||
}
|
||||
prev_ids.push_back(sel_id);
|
||||
sel_item->itemChanged();
|
||||
viewer->update();
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(!group_item)
|
||||
return;
|
||||
scene->erase(scene->item_id(group_item));
|
||||
group_item = nullptr;
|
||||
items.clear();
|
||||
prev_ids.clear();
|
||||
delete col_det;
|
||||
col_det = nullptr;
|
||||
}
|
||||
|
||||
//switch transparent/wireframe.
|
||||
void change_display()
|
||||
{
|
||||
for(Scene_movable_sm_item* item : items)
|
||||
{
|
||||
if(do_transparency)
|
||||
{
|
||||
item->setRenderingMode(Flat);
|
||||
item->setAlpha(120);
|
||||
}
|
||||
else
|
||||
{
|
||||
item->setRenderingMode(Wireframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QList<QAction*> _actions;
|
||||
Messages_interface* messageInterface;
|
||||
CGAL::Three::Scene_interface* scene;
|
||||
QMainWindow* mw;
|
||||
CGAL::Rigid_triangle_mesh_collision_detection<SMesh> *col_det;
|
||||
std::vector<Scene_movable_sm_item*> items;
|
||||
std::vector<std::size_t> prev_ids;
|
||||
Scene_group_item* group_item;
|
||||
bool do_transparency;
|
||||
};
|
||||
#include "Do_trees_intersect_plugin.moc"
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
#include <QApplication>
|
||||
#include "Scene_movable_sm_item.h"
|
||||
#include <CGAL/Polygon_mesh_processing/compute_normal.h>
|
||||
#include <CGAL/Three/Viewer_interface.h>
|
||||
#include <CGAL/Buffer_for_vao.h>
|
||||
#include <CGAL/Three/Triangle_container.h>
|
||||
#include <CGAL/Three/Edge_container.h>
|
||||
typedef CGAL::Three::Triangle_container Tri;
|
||||
typedef CGAL::Three::Viewer_interface VI;
|
||||
struct Scene_movable_sm_item_priv
|
||||
{
|
||||
Scene_movable_sm_item_priv(const CGAL::qglviewer::Vec& pos,SMesh* sm,
|
||||
const QString name, Scene_movable_sm_item *parent)
|
||||
: frame(new CGAL::Three::Scene_item::ManipulatedFrame()),
|
||||
facegraph(sm),
|
||||
center_(pos),
|
||||
item_name(name)
|
||||
{
|
||||
item = parent;
|
||||
const CGAL::qglviewer::Vec offset = static_cast<Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
||||
frame->setPosition(pos+offset);
|
||||
item->setTriangleContainer(0, new Triangle_container(VI::PROGRAM_WITH_LIGHT,
|
||||
false));
|
||||
item->setEdgeContainer(0, new Edge_container(VI::PROGRAM_NO_SELECTION,
|
||||
false));
|
||||
}
|
||||
~Scene_movable_sm_item_priv()
|
||||
{
|
||||
delete frame;
|
||||
}
|
||||
void initialize_buffers(Viewer_interface *viewer) const;
|
||||
void compute_elements() const;
|
||||
enum VAOs {
|
||||
Edges=0,
|
||||
NbOfVaos
|
||||
};
|
||||
enum VBOs {
|
||||
Vertices = 0,
|
||||
NbOfVbos
|
||||
};
|
||||
|
||||
CGAL::qglviewer::ManipulatedFrame* frame;
|
||||
SMesh* facegraph;
|
||||
CGAL::qglviewer::Vec center_;
|
||||
Scene_movable_sm_item *item;
|
||||
QMatrix4x4 f_matrix;
|
||||
const QString item_name;
|
||||
|
||||
mutable QOpenGLShaderProgram *program;
|
||||
mutable std::vector<float> flat_normals;
|
||||
mutable std::vector<float> flat_vertices;
|
||||
mutable std::vector<float> edges_vertices;
|
||||
|
||||
};
|
||||
|
||||
Scene_movable_sm_item::Scene_movable_sm_item(const CGAL::qglviewer::Vec& pos, SMesh* sm,
|
||||
const QString name)
|
||||
{
|
||||
d = new Scene_movable_sm_item_priv(pos,sm, name, this);
|
||||
}
|
||||
|
||||
|
||||
void Scene_movable_sm_item_priv::initialize_buffers(CGAL::Three::Viewer_interface *viewer = nullptr) const
|
||||
{
|
||||
item->getTriangleContainer(0)->initializeBuffers(viewer);
|
||||
item->getTriangleContainer(0)->setFlatDataSize(flat_vertices.size());
|
||||
item->getEdgeContainer(0)->initializeBuffers(viewer);
|
||||
item->getEdgeContainer(0)->setFlatDataSize(edges_vertices.size());
|
||||
flat_vertices.resize(0);
|
||||
flat_normals .resize(0);
|
||||
edges_vertices.resize(0);
|
||||
flat_vertices.shrink_to_fit();
|
||||
flat_normals.shrink_to_fit();
|
||||
edges_vertices.shrink_to_fit();
|
||||
|
||||
item->are_buffers_filled = true;
|
||||
}
|
||||
|
||||
|
||||
void Scene_movable_sm_item_priv::compute_elements() const
|
||||
{
|
||||
typedef EPICK::Point_3 Point;
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
SMesh::Property_map<face_descriptor, EPICK::Vector_3 > fnormals =
|
||||
facegraph->add_property_map<face_descriptor, EPICK::Vector_3 >("f:normal").first;
|
||||
CGAL::Polygon_mesh_processing::compute_face_normals(*facegraph,fnormals);
|
||||
const CGAL::qglviewer::Vec o = static_cast<CGAL::Three::Viewer_interface*>(CGAL::QGLViewer::QGLViewerPool().first())->offset();
|
||||
EPICK::Vector_3 offset(o.x, o.y, o.z);
|
||||
SMesh::Property_map<vertex_descriptor, SMesh::Point> positions =
|
||||
facegraph->points();
|
||||
typedef boost::graph_traits<SMesh>::face_descriptor face_descriptor;
|
||||
typedef boost::graph_traits<SMesh>::halfedge_descriptor halfedge_descriptor;
|
||||
typedef boost::graph_traits<SMesh>::edge_descriptor edge_descriptor;
|
||||
typedef CGAL::Buffer_for_vao<float, unsigned int> CPF;
|
||||
flat_vertices.clear();
|
||||
flat_normals.clear();
|
||||
edges_vertices.clear();
|
||||
//faces
|
||||
BOOST_FOREACH(face_descriptor fd, faces(*facegraph))
|
||||
{
|
||||
BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_face(halfedge(fd, *facegraph),*facegraph))
|
||||
{
|
||||
Point p = positions[source(hd, *facegraph)] + offset;
|
||||
EPICK::Point_3 pc(p.x() - center_.x,
|
||||
p.y() - center_.y,
|
||||
p.z() - center_.z);
|
||||
CPF::add_point_in_buffer(pc, flat_vertices);
|
||||
EPICK::Vector_3 n = fnormals[fd];
|
||||
CPF::add_normal_in_buffer(n, flat_normals);
|
||||
}
|
||||
}
|
||||
//edges
|
||||
BOOST_FOREACH(edge_descriptor ed, edges(*facegraph))
|
||||
{
|
||||
Point p = positions[source(ed, *facegraph)] + offset;
|
||||
EPICK::Point_3 pc(p.x() - center_.x,
|
||||
p.y() - center_.y,
|
||||
p.z() - center_.z);
|
||||
CPF::add_point_in_buffer(pc, edges_vertices);
|
||||
p = positions[target(ed, *facegraph)] + offset;
|
||||
pc=EPICK::Point_3(p.x() - center_.x,
|
||||
p.y() - center_.y,
|
||||
p.z() - center_.z);
|
||||
CPF::add_point_in_buffer(pc, edges_vertices);
|
||||
}
|
||||
|
||||
|
||||
|
||||
item->getTriangleContainer(0)->allocate(Tri::Flat_vertices, flat_vertices.data(),
|
||||
static_cast<int>(flat_vertices.size()*sizeof(float)));
|
||||
item->getTriangleContainer(0)->allocate(Tri::Flat_normals, flat_normals.data(),
|
||||
static_cast<int>(flat_normals.size()*sizeof(float)));
|
||||
item->getEdgeContainer(0)->allocate(Tri::Flat_vertices, edges_vertices.data(),
|
||||
static_cast<int>(edges_vertices.size()*sizeof(float)));
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void Scene_movable_sm_item::computeElements() const
|
||||
{
|
||||
d->compute_elements();
|
||||
compute_bbox();
|
||||
}
|
||||
void Scene_movable_sm_item::draw(CGAL::Three::Viewer_interface* viewer) const
|
||||
{
|
||||
if(!isInit() && viewer->context()->isValid())
|
||||
initGL();
|
||||
if(!are_buffers_filled)
|
||||
d->initialize_buffers(viewer);
|
||||
getTriangleContainer(0)->setColor(color());
|
||||
getTriangleContainer(0)->setAlpha(alpha());
|
||||
getTriangleContainer(0)->setFrameMatrix(d->f_matrix);
|
||||
|
||||
getTriangleContainer(0)->draw(viewer, true);
|
||||
}
|
||||
|
||||
void Scene_movable_sm_item::drawEdges(CGAL::Three::Viewer_interface* viewer) const
|
||||
{
|
||||
if(!isInit() && viewer->context()->isValid())
|
||||
initGL();
|
||||
if(!are_buffers_filled)
|
||||
d->initialize_buffers(viewer);
|
||||
getEdgeContainer(0)->setColor(color());
|
||||
getEdgeContainer(0)->setFrameMatrix(d->f_matrix);
|
||||
|
||||
getEdgeContainer(0)->draw(viewer, true);
|
||||
}
|
||||
|
||||
QString Scene_movable_sm_item::toolTip() const {
|
||||
return QObject::tr("<p>Manipulatable representation of <b>%1</b></p>"
|
||||
"<p>Keep <b>Ctrl</b> pressed and use the arcball to define an affine transformation.<br />")
|
||||
.arg(d->item_name);
|
||||
}
|
||||
|
||||
void
|
||||
Scene_movable_sm_item::compute_bbox() const {
|
||||
SMesh::Property_map<vertex_descriptor, Point_3> pprop = d->facegraph->points();
|
||||
CGAL::Bbox_3 bbox ;
|
||||
|
||||
BOOST_FOREACH(vertex_descriptor vd,vertices(*d->facegraph))
|
||||
{
|
||||
bbox = bbox + pprop[vd].bbox();
|
||||
}
|
||||
_bbox = Bbox(bbox.xmin(),bbox.ymin(),bbox.zmin(),
|
||||
bbox.xmax(),bbox.ymax(),bbox.zmax());
|
||||
is_bbox_computed = true;
|
||||
}
|
||||
|
||||
Scene_item::Bbox Scene_movable_sm_item::bbox() const {
|
||||
if(!is_bbox_computed)
|
||||
compute_bbox();
|
||||
is_bbox_computed = true;
|
||||
return _bbox;
|
||||
}
|
||||
|
||||
|
||||
void Scene_movable_sm_item::invalidateOpenGLBuffers()
|
||||
{
|
||||
d->compute_elements();
|
||||
is_bbox_computed = false;
|
||||
are_buffers_filled = false;
|
||||
}
|
||||
CGAL::Three::Scene_item::ManipulatedFrame* Scene_movable_sm_item::manipulatedFrame() { return d->frame; }
|
||||
const CGAL::qglviewer::Vec& Scene_movable_sm_item::center() const { return d->center_; }
|
||||
Scene_movable_sm_item::~Scene_movable_sm_item() { delete d; Q_EMIT killed(); }
|
||||
void Scene_movable_sm_item::setFMatrix(const GLdouble matrix[])
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
d->f_matrix.data()[i] = (float)matrix[i];
|
||||
}
|
||||
|
||||
SMesh *Scene_movable_sm_item::getFaceGraph()
|
||||
{
|
||||
return d->facegraph;
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef Scene_movable_sm_item_H
|
||||
#define Scene_movable_sm_item_H
|
||||
|
||||
#include "SMesh_type.h"
|
||||
|
||||
#include <CGAL/Surface_mesh/Surface_mesh_fwd.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Surface_mesh.h>
|
||||
#include <CGAL/Three/Scene_interface.h>
|
||||
#include <CGAL/Three/Scene_item.h>
|
||||
#include <CGAL/Three/Scene_item_rendering_helper.h>
|
||||
#include <CGAL/Qt/manipulatedFrame.h>
|
||||
#include <CGAL/Qt/qglviewer.h>
|
||||
|
||||
#include <QKeyEvent>
|
||||
|
||||
|
||||
#if defined( scene_movable_sm_item_EXPORTS)
|
||||
# define SCENE_MOVABLE_SM_ITEM_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define SCENE_MOVABLE_SM_ITEM_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
using namespace CGAL::Three;
|
||||
struct Scene_movable_sm_item_priv;
|
||||
// This class represents a polyhedron in the OpenGL scene
|
||||
class SCENE_MOVABLE_SM_ITEM_EXPORT Scene_movable_sm_item
|
||||
: public CGAL::Three::Scene_item_rendering_helper
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Scene_movable_sm_item(const CGAL::qglviewer::Vec& pos, SMesh *sm,
|
||||
const QString name);
|
||||
Scene_item* clone() const{return nullptr;}
|
||||
QString toolTip() const;
|
||||
void draw(CGAL::Three::Viewer_interface *) const;
|
||||
void drawEdges(CGAL::Three::Viewer_interface *) const;
|
||||
void compute_bbox() const;
|
||||
Scene_item::Bbox bbox() const ;
|
||||
~Scene_movable_sm_item();
|
||||
bool manipulatable() const { return true;}
|
||||
ManipulatedFrame* manipulatedFrame();
|
||||
const CGAL::qglviewer::Vec& center() const;
|
||||
virtual bool supportsRenderingMode(RenderingMode m) const { return m==Flat
|
||||
|| m==Wireframe; }
|
||||
virtual void invalidateOpenGLBuffers();
|
||||
void setFMatrix(const GLdouble matrix[16]);
|
||||
void computeElements() const;
|
||||
bool isEmpty() const {return false;}
|
||||
SMesh *getFaceGraph();
|
||||
protected:
|
||||
friend struct Scene_movable_sm_item_priv;
|
||||
Scene_movable_sm_item_priv* d;
|
||||
|
||||
Q_SIGNALS:
|
||||
void stop();
|
||||
void killed();
|
||||
}; // end class Scene_movable_sm_item
|
||||
|
||||
#endif // Scene_movable_sm_item_H
|
||||
|
|
@ -134,7 +134,6 @@ void Scene_item_rendering_helper::initGL() const
|
|||
void Scene_item_rendering_helper::processData(Gl_data_names )const
|
||||
{
|
||||
computeElements();
|
||||
//redraw();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ struct Tri_d{
|
|||
float shrink_factor;
|
||||
QVector4D plane;
|
||||
float alpha;
|
||||
QMatrix4x4 f_matrix;
|
||||
};
|
||||
|
||||
Triangle_container::Triangle_container(int program, bool indexed)
|
||||
|
|
@ -117,6 +118,8 @@ QOpenGLFramebufferObject* fbo = viewer->depthPeelingFbo();
|
|||
getVao(viewer)->bind();
|
||||
if(is_color_uniform)
|
||||
getVao(viewer)->program->setAttributeValue("colors", getColor());
|
||||
if(getVao(viewer)->program->property("hasFMatrix").toBool())
|
||||
getVao(viewer)->program->setUniformValue("f_matrix", getFrameMatrix());
|
||||
getVbo(Vertex_indices)->bind();
|
||||
if(getVao(viewer)->program->property("hasTransparency").toBool())
|
||||
{
|
||||
|
|
@ -142,6 +145,8 @@ QOpenGLFramebufferObject* fbo = viewer->depthPeelingFbo();
|
|||
getVao(viewer)->program->setUniformValue("cutplane", d->plane);
|
||||
if(is_color_uniform)
|
||||
getVao(viewer)->program->setAttributeValue("colors", getColor());
|
||||
if(getVao(viewer)->program->property("hasFMatrix").toBool())
|
||||
getVao(viewer)->program->setUniformValue("f_matrix", getFrameMatrix());
|
||||
if(getVao(viewer)->program->property("hasTransparency").toBool())
|
||||
{
|
||||
getVao(viewer)->program->setUniformValue("comparing", viewer->currentPass() > 0);
|
||||
|
|
@ -189,6 +194,8 @@ void Triangle_container::initializeBuffers(Viewer_interface *viewer)
|
|||
float Triangle_container::getShrinkFactor() { return d->shrink_factor ; }
|
||||
QVector4D Triangle_container::getPlane() { return d->plane; }
|
||||
float Triangle_container::getAlpha() { return d->alpha; }
|
||||
QMatrix4x4 Triangle_container::getFrameMatrix() const { return d->f_matrix; }
|
||||
|
||||
void Triangle_container::setShrinkFactor(const float& f) { d->shrink_factor = f; }
|
||||
void Triangle_container::setAlpha (const float& f) { d->alpha = f ; }
|
||||
void Triangle_container::setFrameMatrix(const QMatrix4x4& m) { d->f_matrix = m; }
|
||||
|
|
|
|||
|
|
@ -815,6 +815,9 @@ void Viewer::attribBuffers(int program_name) const {
|
|||
program->bind();
|
||||
program->setUniformValue("point_size", getGlPointSize());
|
||||
program->setUniformValue("mvp_matrix", mvp_mat);
|
||||
QMatrix4x4 id_mat;
|
||||
id_mat.setToIdentity();
|
||||
program->setUniformValue("f_matrix", id_mat);
|
||||
program->setUniformValue("is_clipbox_on", d->clipping);
|
||||
if(d->clipping)
|
||||
{
|
||||
|
|
@ -1068,6 +1071,7 @@ QOpenGLShaderProgram* Viewer::getShaderProgram(int name) const
|
|||
program->setProperty("hasLight", true);
|
||||
program->setProperty("hasNormals", true);
|
||||
program->setProperty("hasTransparency", true);
|
||||
program->setProperty("hasFMatrix", true);
|
||||
return program;
|
||||
}
|
||||
case PROGRAM_WITHOUT_LIGHT:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ in vec3 normals;
|
|||
in vec4 colors;
|
||||
uniform mat4 mvp_matrix;
|
||||
uniform mat4 mv_matrix;
|
||||
uniform mat4 f_matrix;
|
||||
out vec4 fP;
|
||||
out vec3 fN;
|
||||
out vec4 color;
|
||||
|
|
@ -38,11 +39,11 @@ void main(void)
|
|||
//
|
||||
if(is_clipbox_on)
|
||||
compute_distances();
|
||||
fP = mv_matrix * vertex;
|
||||
fP = mv_matrix * f_matrix * vertex;
|
||||
mat3 mv_matrix_3;
|
||||
mv_matrix_3[0] = mv_matrix[0].xyz;
|
||||
mv_matrix_3[1] = mv_matrix[1].xyz;
|
||||
mv_matrix_3[2] = mv_matrix[2].xyz;
|
||||
fN = mv_matrix_3* normals;
|
||||
gl_Position = mvp_matrix * vertex;
|
||||
gl_Position = mvp_matrix * f_matrix * vertex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,6 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
|||
polyhedron_demo_plugin(basic_item_plugin Basic_item_plugin)
|
||||
|
||||
# links the library containing the scene_plane_item with the plugin
|
||||
target_link_libraries(basic_item_plugin Polyhedron_scene_basic_objects)
|
||||
target_link_libraries(basic_item_plugin PUBLIC Polyhedron_scene_basic_objects)
|
||||
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ Once your code is written, you will need to link the item's library to your plug
|
|||
|
||||
polyhedron_demo_plugin(basic_item_plugin Basic_item_plugin)
|
||||
# links the library containing the scene_plane_item with the plugin
|
||||
target_link_libraries(basic_item_plugin scene_basic_objects)
|
||||
target_link_libraries(basic_item_plugin PUBLIC scene_basic_objects)
|
||||
|
||||
\subsubsection exampleCreatingANewTypeItem Creating a new type of item
|
||||
|
||||
|
|
@ -241,7 +241,7 @@ To display, you need to call the same program that got configured previously, an
|
|||
If you created your item in a specific file and you need to use it outside your plugin (like in another plugin), it is recommended to put it in the demo's root directory, and you will have to define your item in the general Polyhedron_demo's CMakeLists.txt by using the macro add_item :
|
||||
|
||||
add_item(scene_trivial_item Scene_trivial_item.cpp)
|
||||
target_link_libraries(scene_trivial_item scene_dependances_item)
|
||||
target_link_libraries(scene_trivial_item PUBLIC scene_dependances_item)
|
||||
|
||||
\subsection exampleUsingAGroupItem Using a Scene_group_item
|
||||
|
||||
|
|
@ -342,7 +342,7 @@ Finally, you can declare your plugin
|
|||
If you need targets from the Polyhedron_demo, you will have to add the prefix 'Polyhedron_' to the target's name, as the exported targets belong to the namespace Polyhedron_
|
||||
|
||||
polyhedron_demo_plugin(basic_item_plugin Basic_item_plugin)
|
||||
target_link_libraries(basic_item_plugin Polyhedron_scene_basic_objects)
|
||||
target_link_libraries(basic_item_plugin PUBLIC Polyhedron_scene_basic_objects)
|
||||
|
||||
Notice that an external plugin will not be automatically loaded in the Polyhedron demo. It must be built in its own project.
|
||||
|
||||
|
|
@ -380,7 +380,7 @@ Notice that an external plugin will not be automatically loaded in the Polyhedro
|
|||
|
||||
|
||||
\section example Examples
|
||||
All the examples have been constructed as external plugins in CGAL/Three/demo/Three/Example_plugin. You will have to use "Load plugin" in the File menu if you want to test it.
|
||||
All the examples have been constructed as external plugins in CGAL/Three/demo/Three/Example_plugin. You will have to use "Load plugin" in the File menu or set the environment variable POLYHEDRON_DEMO_PLUGINS_PATH if you want to test it.
|
||||
\subsection example1 Creating a Basic Plugin
|
||||
\cgalExample{Three/Example_plugin/Basic_plugin.cpp}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ using namespace CGAL::Three;
|
|||
# define DEMO_FRAMEWORK_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
struct Tri_d;
|
||||
class QMatrix4x4;
|
||||
namespace CGAL {
|
||||
namespace Three {
|
||||
|
||||
|
|
@ -95,12 +96,16 @@ struct DEMO_FRAMEWORK_EXPORT Triangle_container :public Primitive_container
|
|||
QVector4D getPlane();
|
||||
//! getter for the "alpha" parameter
|
||||
float getAlpha();
|
||||
//! getter for the "f_matrix" parameter
|
||||
QMatrix4x4 getFrameMatrix()const;
|
||||
//! setter for the "shrink_factor" parameter
|
||||
void setShrinkFactor(const float&);
|
||||
//! setter for the "plane" parameter
|
||||
void setPlane (const QVector4D&);
|
||||
//! setter for the "alpha" parameter
|
||||
void setAlpha (const float&);
|
||||
//! setter for the "f_matrix" parameter
|
||||
void setFrameMatrix(const QMatrix4x4&);
|
||||
///@}
|
||||
|
||||
//drawing variables
|
||||
|
|
|
|||
Loading…
Reference in New Issue