dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/Polygon_mesh_processing/intersection.h

1822 lines
72 KiB
C++
Executable File

// Copyright (c) 2016 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_POLYGON_MESH_PROCESSING_INTERSECTION_H
#define CGAL_POLYGON_MESH_PROCESSING_INTERSECTION_H
#include <CGAL/license/Polygon_mesh_processing/corefinement.h>
#include <CGAL/disable_warnings.h>
#include <CGAL/Polygon_mesh_processing/internal/Corefinement/intersection_impl.h>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/boost/iterator/counting_iterator.hpp>
#include <boost/mpl/if.hpp>
#include <CGAL/Polygon_mesh_processing/bbox.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Polygon_mesh_processing/connected_components.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/AABB_traits.h>
#include <CGAL/AABB_tree.h>
#include <CGAL/Side_of_triangle_mesh.h>
namespace CGAL {
namespace Polygon_mesh_processing{
namespace internal {
template<class TM,
class Kernel,
class Box,
class OutputIterator,
class VertexPointMap1,
class VertexPointMap2>
struct Intersect_faces
{
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Triangle_3 Triangle;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::property_map<TM, boost::vertex_point_t>::const_type Ppmap;
// members
const TM& m_tm1;
const VertexPointMap1 m_vpmap1;
const TM& m_tm2;
const VertexPointMap2 m_vpmap2;
mutable OutputIterator m_iterator;
typename Kernel::Construct_triangle_3 triangle_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_faces(const TM& tm1, const TM& tm2,
OutputIterator it,
VertexPointMap1 vpmap1, VertexPointMap2 vpmap2,
const Kernel& kernel)
:
m_tm1(tm1),
m_vpmap1(vpmap1),
m_tm2(tm2),
m_vpmap2(vpmap2),
m_iterator(it),
triangle_functor(kernel.construct_triangle_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
void operator()(const Box* b, const Box* c) const
{
halfedge_descriptor h = halfedge(b->info(), m_tm1);
halfedge_descriptor g = halfedge(c->info(), m_tm2);
// check for geometric intersection
Triangle t1 = triangle_functor( get(m_vpmap1, target(h,m_tm1)),
get(m_vpmap1, target(next(h,m_tm1),m_tm1)),
get(m_vpmap1, source(h,m_tm1)));
Triangle t2 = triangle_functor( get(m_vpmap2, target(g,m_tm2)),
get(m_vpmap2, target(next(g,m_tm2),m_tm2)),
get(m_vpmap2, source(g,m_tm2)));
if(do_intersect_3_functor(t1, t2)){
*m_iterator++ = std::make_pair(b->info(), c->info());
}
} // end operator ()
}; // end struct Intersect_faces
template<class TM,
class Kernel,
class Box,
class OutputIterator,
class Polyline,
class VertexPointMap>
struct Intersect_face_polyline
{
// wrapper to check whether anything is inserted to output iterator
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Triangle_3 Triangle;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename boost::property_map<TM, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
// members
const TM& m_tm;
const std::vector<face_descriptor>& faces;
const VertexPointMap m_vpmap;
const Polyline& polyline;
mutable OutputIterator m_iterator;
typename Kernel::Construct_segment_3 segment_functor;
typename Kernel::Construct_triangle_3 triangle_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_face_polyline(const TM& tm,
const std::vector<face_descriptor>& faces,
const Polyline& polyline,
OutputIterator it,
VertexPointMap vpmap,
const Kernel& kernel)
:
m_tm(tm),
faces(faces),
m_vpmap(vpmap),
polyline(polyline),
m_iterator(it),
segment_functor(kernel.construct_segment_3_object()),
triangle_functor(kernel.construct_triangle_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
void operator()(const Box* b, const Box* c) const
{
halfedge_descriptor h = halfedge(faces[b->info()], m_tm);
// check for geometric intersection
Triangle t = triangle_functor( get(m_vpmap, target(h,m_tm)),
get(m_vpmap, target(next(h,m_tm),m_tm)),
get(m_vpmap, source(h,m_tm)));
Segment s = segment_functor(polyline[c->info()], polyline[c->info() + 1]);
if(do_intersect_3_functor(t, s)){
*m_iterator++ = std::make_pair(b->info(), c->info());
}
} // end operator ()
}; // end struct Intersect_face_polyline
template<class TM,
class Kernel,
class Box,
class PolylineRange,
class OutputIterator,
class VertexPointMap>
struct Intersect_face_polylines
{
// wrapper to check whether anything is inserted to output iterator
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Triangle_3 Triangle;
typedef typename boost::graph_traits<TM>::halfedge_descriptor halfedge_descriptor;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename boost::property_map<TM, boost::vertex_point_t>::const_type Ppmap;
typedef typename boost::property_traits<Ppmap>::value_type Point;
// members
const TM& m_tm;
const std::vector<face_descriptor>& faces;
const VertexPointMap m_vpmap;
const PolylineRange& polylines;
mutable OutputIterator m_iterator;
typename Kernel::Construct_segment_3 segment_functor;
typename Kernel::Construct_triangle_3 triangle_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_face_polylines(const TM& tm,
const std::vector<face_descriptor>& faces,
const PolylineRange& polylines,
OutputIterator it,
VertexPointMap vpmap,
const Kernel& kernel)
:
m_tm(tm),
faces(faces),
m_vpmap(vpmap),
polylines(polylines),
m_iterator(it),
segment_functor(kernel.construct_segment_3_object()),
triangle_functor(kernel.construct_triangle_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
void operator()(const Box* b, const Box* c) const
{
halfedge_descriptor h = halfedge(faces[b->info().second], m_tm);
// check for geometric intersection
Triangle t = triangle_functor( get(m_vpmap, target(h,m_tm)),
get(m_vpmap, target(next(h,m_tm),m_tm)),
get(m_vpmap, source(h,m_tm)));
Segment s = segment_functor(polylines[c->info().first][c->info().second], polylines[c->info().first][c->info().second + 1]);
if(do_intersect_3_functor(t, s)){
*m_iterator++ = std::make_pair(b->info().second, c->info());
}
} // end operator ()
}; // end struct Intersect_face_polylines
template<class Polyline,
class Kernel,
class Box,
class OutputIterator>
struct Intersect_polylines
{
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Point_3 Point;
// members
const Polyline& polyline1;
const Polyline& polyline2;
mutable OutputIterator m_iterator;
typename Kernel::Construct_segment_3 segment_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_polylines(const Polyline& polyline1,
const Polyline& polyline2,
OutputIterator it,
const Kernel& kernel)
:
polyline1(polyline1),
polyline2(polyline2),
m_iterator(it),
segment_functor(kernel.construct_segment_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
void operator()(const Box* b, const Box* c) const
{
// check for geometric intersection
Segment s1 = segment_functor(polyline1[b->info()], polyline1[b->info() + 1]);
Segment s2 = segment_functor(polyline2[c->info()], polyline2[c->info() + 1]);
if(do_intersect_3_functor(s1, s2)){
*m_iterator++ = std::make_pair(b->info(), c->info());
}
} // end operator ()
}; // end struct Intersect_polylines
template<class PolylineRange,
class Kernel,
class Box,
class OutputIterator>
struct Intersect_polyline_ranges
{
// typedefs
typedef typename Kernel::Segment_3 Segment;
typedef typename Kernel::Point_3 Point;
// members
const PolylineRange& polyline1;
const PolylineRange& polyline2;
mutable OutputIterator m_iterator;
typename Kernel::Construct_segment_3 segment_functor;
typename Kernel::Do_intersect_3 do_intersect_3_functor;
Intersect_polyline_ranges(const PolylineRange& polyline1,
const PolylineRange& polyline2,
OutputIterator it,
const Kernel& kernel)
:
polyline1(polyline1),
polyline2(polyline2),
m_iterator(it),
segment_functor(kernel.construct_segment_3_object()),
do_intersect_3_functor(kernel.do_intersect_3_object())
{ }
void operator()(const Box* b, const Box* c) const
{
// check for geometric intersection
Segment s1 = segment_functor(polyline1[b->info().first][b->info().second], polyline1[b->info().first][b->info().second + 1]);
Segment s2 = segment_functor(polyline2[c->info().first][c->info().second], polyline2[c->info().first][c->info().second + 1]);
if(do_intersect_3_functor(s1, s2)){
*m_iterator++ = std::make_pair(b->info(), c->info());
}
} // end operator ()
}; // end struct Intersect_polyline_ranges
struct Throw_at_first_output {
class Throw_at_first_output_exception: public std::exception
{ };
template<class T>
void operator()(const T& /* t */) const {
throw Throw_at_first_output_exception();
}
};
// Note this is not officially documented
/*
* reports all the pairs of faces intersecting between two triangulated surface meshes.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \pre `CGAL::is_triangle_mesh(tm1)`
* \pre `CGAL::is_triangle_mesh(tm2)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
* model of `RandomAccessRange`.
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
* \tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* \param face_range1 the range of faces of `tm1` to check for intersections.
* \param face_range2 the range of faces of `tm2` to check for intersections.
* \param tm1 the first triangulated surface mesh.
* \param tm2 the second triangulated surface mesh.
* \param out output iterator to be filled with all pairs of faces that intersect.
* First and second element in the pairs correspond to faces of `tm1` and `tm2` respectively
* \param np1 optional sequence of \ref pmp_namedparameters for `tm1`, among the ones listed below
* \param np2 optional sequence of \ref pmp_namedparameters for `tm2`, among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
* \return `out`
*/
template <class TriangleMesh,
class FaceRange,
class OutputIterator,
class NamedParameters1,
class NamedParameters2>
OutputIterator
compute_face_face_intersection(const FaceRange& face_range1,
const FaceRange& face_range2,
const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator out,
const NamedParameters1& np1,
const NamedParameters2& np2)
{
using boost::get_param;
using boost::choose_param;
CGAL_precondition(CGAL::is_triangle_mesh(tm1));
CGAL_precondition(CGAL::is_triangle_mesh(tm2));
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, face_descriptor> Box;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range1), boost::end(face_range1) )
);
boxes2.reserve(
std::distance( boost::begin(face_range2), boost::end(face_range2) )
);
typedef typename GetVertexPointMap<TM, NamedParameters1>::const_type VertexPointMap1;
typedef typename GetVertexPointMap<TM, NamedParameters2>::const_type VertexPointMap2;
VertexPointMap1 vpmap1 = choose_param(get_param(np1, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm1));
VertexPointMap2 vpmap2 = choose_param(get_param(np2, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm2));
CGAL_static_assertion(
(boost::is_same<
typename boost::property_traits<VertexPointMap1>::value_type,
typename boost::property_traits<VertexPointMap2>::value_type
>::value) );
BOOST_FOREACH(face_descriptor f, face_range1)
{
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm1), f));
}
BOOST_FOREACH(face_descriptor f, face_range2)
{
boxes2.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm2), f));
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
typedef typename GetGeomTraits<TM, NamedParameters1>::type GeomTraits;
GeomTraits gt = choose_param(get_param(np1, internal_np::geom_traits), GeomTraits());
internal::Intersect_faces<TM,
GeomTraits,
Box,
OutputIterator,
VertexPointMap1,
VertexPointMap2> Intersect_faces(tm1, tm2,
out,
vpmap1, vpmap2,
gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
box2_ptr.begin(), box2_ptr.end(),
Intersect_faces,cutoff);
return Intersect_faces.m_iterator;
}
// Note this is not officially documented
/*
* reports all the pairs of segments and faces intersecting between
* a triangulated surface mesh and a polyline.
* \attention If a polyline vertex intersects a face, the intersection will
* be reported twice (even more if it is on a vertex, edge, or point).
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \pre `CGAL::is_triangle_mesh(tm)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
* model of `RandomAccessRange`.
* \tparam Polyline a `RandomAccessRange` of points. The point type of the range must be
* the same as the value type of the vertex point map.
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<std::size_t, std::size_t>`.This `OutputIterator` will hold the position of the
* elements in their respective range. In the case of the polyline, this position is the index of
* the segment intersecting the face (which is the index of the first point of the
* segment following the range order.)
* \tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* \param face_range the range of faces of `tm` to check for intersections.
* \param polyline the polyline to check for intersections.
* \param tm the triangulated surface mesh to check for intersections.
* \param out output iterator to be filled with all pairs of face-segment that intersect
* \param np optional sequence of \ref pmp_namedparameters for `tm`, 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{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
* \return `out`
*/
template <class TriangleMesh,
class FaceRange,
class Polyline,
class OutputIterator,
class NamedParameters>
OutputIterator
compute_face_polyline_intersection( const FaceRange& face_range,
const Polyline& polyline,
const TriangleMesh& tm,
OutputIterator out,
const NamedParameters& np)
{
using boost::choose_param;
using boost::get_param;
CGAL_precondition(CGAL::is_triangle_mesh(tm));
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VertexPointMap;
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm));
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
CGAL_static_assertion(
(boost::is_same<Point,
typename boost::range_value<Polyline>::type>::value));
std::vector<face_descriptor> faces;
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range), boost::end(face_range) )
);
boxes2.reserve(
std::distance( boost::begin(polyline), boost::end(polyline) ) - 1
);
BOOST_FOREACH(face_descriptor f, face_range)
{
faces.push_back(f);
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), faces.size()-1));
}
for(std::size_t i =0; i< polyline.size()-1; ++i)
{
Point p1 = polyline[i];
Point p2 = polyline[i+1];
boxes2.push_back(Box(p1.bbox() + p2.bbox(), i));
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
typedef typename GetGeomTraits<TM, NamedParameters>::type GeomTraits;
GeomTraits gt = choose_param(get_param(np, internal_np::geom_traits), GeomTraits());
internal::Intersect_face_polyline<TM,
GeomTraits,
Box,
OutputIterator,
Polyline,
VertexPointMap>
Intersect_face_polyline(tm,
faces,
polyline,
out,
vpmap,
gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
box2_ptr.begin(), box2_ptr.end(),
Intersect_face_polyline, cutoff);
return Intersect_face_polyline.m_iterator;
}
// Note this is not officially documented
/*
* reports all the pairs of segments and faces intersecting between
* a triangulated surface mesh and a range of polylines.
* \attention If a polyline vertex intersects a face, the intersection will
* be reported twice (even more if it is on a vertex, edge, or point).
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \pre `CGAL::is_triangle_mesh(tm)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
* model of `RandomAccessRange`.
* \tparam PolylineRange a `RandomAccessRange` of `RandomAccessRange` of points. The point type of the range must be
* the same as the value type of the vertex point map.
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<std::size_t, std::pair<std::size_t, std::size_t> >`.
* Each pair holds the index of the face and a pair containing the index of the polyline in the range and the index of
* the first point of the segment in the polyline.
* \tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* \param face_range the range of `tm` faces to check for intersections.
* \param polyline_range the range of polylines to check for intersections.
* \param tm the triangulated surface mesh to check for intersections.
* \param out output iterator to be filled with all pairs of face-segment that intersect
* \param np optional sequence of \ref pmp_namedparameters for `tm`, 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{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
* \return `out`
*/
template <class TriangleMesh,
class FaceRange,
class PolylineRange,
class OutputIterator,
class NamedParameters>
OutputIterator
compute_face_polylines_intersection(const FaceRange& face_range,
const PolylineRange& polyline_range,
const TriangleMesh& tm,
OutputIterator out,
const NamedParameters& np)
{
using boost::choose_param;
using boost::get_param;
CGAL_precondition(CGAL::is_triangle_mesh(tm));
typedef TriangleMesh TM;
typedef typename boost::graph_traits<TM>::face_descriptor face_descriptor;
typedef typename GetVertexPointMap<TM, NamedParameters>::const_type VertexPointMap;
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm));
typedef typename boost::property_traits<VertexPointMap>::value_type Point;
typedef typename boost::range_value<PolylineRange>::type Polyline;
CGAL_static_assertion(
(boost::is_same<Point,
typename boost::range_value<Polyline>::type>::value));
std::vector<face_descriptor> faces;
faces.reserve(std::distance( boost::begin(face_range), boost::end(face_range) ));
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(face_range), boost::end(face_range) )
);
std::size_t polylines_size = 0;
BOOST_FOREACH(Polyline poly, polyline_range)
{
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
}
boxes2.reserve( polylines_size );
BOOST_FOREACH(face_descriptor f, face_range)
{
faces.push_back(f);
boxes1.push_back(Box(Polygon_mesh_processing::face_bbox(f, tm), std::make_pair(0, faces.size()-1)));
}
std::size_t range_size = std::distance( boost::begin(polyline_range), boost::end(polyline_range) );
for(std::size_t j = 0; j < range_size; ++j)
{
Polyline poly = polyline_range[j];
std::size_t size = std::distance( boost::begin(poly), boost::end(poly) );
for(std::size_t i =0; i< size - 1; ++i)
{
Point p1 = poly[i];
Point p2 = poly[i+1];
boxes2.push_back(Box(p1.bbox() + p2.bbox(), std::make_pair(j, i)));
}
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
typedef typename GetGeomTraits<TM, NamedParameters>::type GeomTraits;
GeomTraits gt = choose_param(get_param(np, internal_np::geom_traits), GeomTraits());
internal::Intersect_face_polylines<TM,
GeomTraits,
Box,
PolylineRange,
OutputIterator,
VertexPointMap>
Intersect_face_polyline(tm,
faces,
polyline_range,
out,
vpmap,
gt);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
box2_ptr.begin(), box2_ptr.end(),
Intersect_face_polyline, cutoff);
return Intersect_face_polyline.m_iterator;
}
// Note this is not officially documented
/*
* detects and records intersections between two polylines.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
* \attention If a polyline vertex intersects another polyline, the intersection will
* be reported twice (even more if it is on a vertex).
* \tparam Polyline a `RandomAccessRange` of points.
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<std::size_t, std::size_t>`. This OutputIterator will hold the position of the
* elements in their respective range. This position is the index of the segment that holds the
* intersection, so it is the index of the first point of the segment following the range order.
* \tparam Kernel a model of `Kernel`
*
* \param polyline1 the first polyline to check for intersections.
* \param polyline2 the second polyline to check for intersections.
* \param out output iterator to be filled with all pairs of segments that intersect
* \param K an instance of `Kernel`
*
* \return `out`
*/
template < class Polyline,
class OutputIterator,
class Kernel>
OutputIterator
compute_polyline_polyline_intersection(const Polyline& polyline1,
const Polyline& polyline2,
OutputIterator out,
const Kernel& K)
{
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::size_t> Box;
typedef typename Kernel::Point_3 Point;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
boxes1.reserve(
std::distance( boost::begin(polyline1), boost::end(polyline1) ) - 1
);
boxes2.reserve(
std::distance( boost::begin(polyline2), boost::end(polyline2) ) - 1
);
for(std::size_t i =0; i< polyline1.size()-1; ++i)
{
const Point& p1 = polyline1[i];
const Point& p2 = polyline1[i+1];
boxes1.push_back(Box(p1.bbox() + p2.bbox(), i));
}
for(std::size_t i =0; i< polyline2.size()-1; ++i)
{
const Point& p1 = polyline2[i];
const Point& p2 = polyline2[i+1];
boxes2.push_back(Box(p1.bbox() + p2.bbox(), i));
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
internal::Intersect_polylines<Polyline,
Kernel,
Box,
OutputIterator>
intersect_polylines(polyline1,
polyline2,
out,
K);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
box2_ptr.begin(), box2_ptr.end(),
intersect_polylines, cutoff);
return intersect_polylines.m_iterator;
}
// Note this is not officially documented
/*
* detects and records intersections between two ranges of polylines.
* \attention If a polyline vertex intersects another polyline, the intersection will
* be reported twice (even more if it is on a vertex).
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \tparam PolylineRange a `RandomAccessRange` of `RandomAccessRange` of points.
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<std::pair<std::size_t, std::size_t>, std::pair<std::size_t, std::size_t> >`.
* Each pair holds the index of the face and a pair containing the index of the polyline in the range and the index of
* the first point of the segment in the polyline.
* \tparam Kernel a model of `Kernel`
*
* \param polylines1 the first range of polylines to check for intersections.
* \param polylines2 the second range of polylines to check for intersections.
* \param out output iterator to be filled with all pairs of segments that intersect
* \param K an instance of `Kernel`
*
* \return `out`
*/
template < class PolylineRange,
class OutputIterator,
class Kernel>
OutputIterator
compute_polylines_polylines_intersection(const PolylineRange& polylines1,
const PolylineRange& polylines2,
OutputIterator out,
const Kernel& K)
{
//info.first is the index of the polyline in the range, info.second is the index of the point in the polyline
typedef typename CGAL::Box_intersection_d::Box_with_info_d<double, 3, std::pair<std::size_t, std::size_t> > Box;
typedef typename Kernel::Point_3 Point;
typedef typename boost::range_value<PolylineRange>::type Polyline;
// make one box per facet
std::vector<Box> boxes1;
std::vector<Box> boxes2;
std::size_t polylines_size = 0;
BOOST_FOREACH(Polyline poly, polylines1)
{
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
}
boxes1.reserve( polylines_size );
polylines_size = 0;
BOOST_FOREACH(Polyline poly, polylines2)
{
polylines_size += std::distance( boost::begin(poly), boost::end(poly) ) -1;
}
boxes2.reserve(polylines_size);
std::size_t range_size = std::distance( boost::begin(polylines1), boost::end(polylines1) );
for(std::size_t j = 0; j < range_size; ++j)
{
Polyline poly = polylines1[j];
std::size_t size = std::distance( boost::begin(poly), boost::end(poly) );
for(std::size_t i =0; i< size - 1; ++i)
{
const Point& p1 = poly[i];
const Point& p2 = poly[i+1];
boxes1.push_back(Box(p1.bbox() + p2.bbox(), std::make_pair(j, i)));
}
}
range_size = std::distance( boost::begin(polylines2), boost::end(polylines2) );
for(std::size_t j = 0; j < range_size; ++j)
{
Polyline poly = polylines2[j];
std::size_t size = std::distance( boost::begin(poly), boost::end(poly) );
for(std::size_t i =0; i< size - 1; ++i)
{
const Point& p1 = poly[i];
const Point& p2 = poly[i+1];
boxes2.push_back(Box(p1.bbox() + p2.bbox(), std::make_pair(j, i)));
}
}
// generate box pointers
std::vector<const Box*> box1_ptr(boost::make_counting_iterator<const Box*>(&boxes1[0]),
boost::make_counting_iterator<const Box*>(&boxes1[0]+boxes1.size()));
std::vector<const Box*> box2_ptr(boost::make_counting_iterator<const Box*>(&boxes2[0]),
boost::make_counting_iterator<const Box*>(&boxes2[0]+boxes2.size()));
// compute intersections filtered out by boxes
internal::Intersect_polyline_ranges<PolylineRange,
Kernel,
Box,
OutputIterator>
intersect_polylines(polylines1,
polylines2,
out,
K);
std::ptrdiff_t cutoff = 2000;
CGAL::box_intersection_d(box1_ptr.begin(), box1_ptr.end(),
box2_ptr.begin(), box2_ptr.end(),
intersect_polylines, cutoff);
return intersect_polylines.m_iterator;
}
// Note this is not officially documented
/*
* reports all the pairs of faces intersecting between two triangulated surface meshes.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* @pre `CGAL::is_triangle_mesh(tm1)`
* @pre `CGAL::is_triangle_mesh(tm2)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<boost::graph_traits<TriangleMesh>::%face_descriptor, boost::graph_traits<TriangleMesh>::%face_descriptor>`
* \tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* \param tm1 the first triangulated surface mesh to check for intersections
* \param tm2 the second triangulated surface mesh to check for intersections
* \param out output iterator to be filled with all pairs of faces that intersect
* \param np1 optional sequence of \ref pmp_namedparameters for `tm1`, among the ones listed below
* \param np2 optional sequence of \ref pmp_namedparameters for `tm2`, among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
* \return `out`
*/
template <class TriangleMesh,
class OutputIterator,
class NamedParameters1,
class NamedParameters2>
OutputIterator
compute_face_face_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator out,
const NamedParameters1& np1,
const NamedParameters2& np2)
{
return compute_face_face_intersection(faces(tm1), faces(tm2),
tm1, tm2, out, np1, np2);
}
// Note this is not officially documented
/*
* detects and records intersections between a triangulated surface mesh
* and a polyline.
* \attention If a polyline vertex intersects a face or another polyline, the intersection will
* be reported twice (even more if it is on a vertex, edge, or point).
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \pre `CGAL::is_triangle_mesh(tm)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam Polyline a `RandomAccessRange` of points. The point type of the range must be the
* same as the value type of the vertex point map.
* \cgalDescribePolylineType
* \tparam OutputIterator a model of `OutputIterator` holding objects of type
* `std::pair<std::size_t, std::size_t>`. This OutputIterator will hold the position of the
* elements in their respective range. In the case of the polyline, this position is the index
* of the segment that holds the intersection, so it is the index of the first point of the
* segment following the range order.
* \tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* \param tm the triangulated surface mesh to check for intersections.
* \param polyline the polyline to check for intersections.
* \param out output iterator to be filled with all pairs of face-segment that intersect
* \param np optional sequence of \ref pmp_namedparameters for `tm`, among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
* \return `out`
*/
template <class TriangleMesh,
class Polyline,
class OutputIterator,
class NamedParameters>
OutputIterator
compute_face_polyline_intersection(const TriangleMesh& tm,
const Polyline& polyline,
OutputIterator out,
const NamedParameters& np)
{
return compute_face_polyline_intersection(faces(tm), polyline, tm, out, np);
}
// functions to check for overlap of meshes
template <class GT, class TriangleMesh, class VPM>
void get_one_point_per_cc(TriangleMesh& tm,
const VPM& vpm,
std::vector<typename GT::Point_3>& points_of_interest)
{
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
boost::unordered_map<face_descriptor, int> fid_map;
int id = 0;
BOOST_FOREACH(face_descriptor fd, faces(tm))
{
fid_map.insert(std::make_pair(fd,id++));
}
boost::associative_property_map< boost::unordered_map<face_descriptor, int> >
fid_pmap(fid_map);
boost::unordered_map<face_descriptor, int> fcc_map;
int nb_cc = Polygon_mesh_processing::connected_components(tm,
boost::make_assoc_property_map(fcc_map),
Polygon_mesh_processing::parameters::face_index_map(fid_pmap));
std::vector<bool> is_cc_treated(nb_cc, false);
points_of_interest.resize(nb_cc);
int cc_treated = 0;
BOOST_FOREACH(face_descriptor fd, faces(tm))
{
int cc=fcc_map[fd];
if(!is_cc_treated[cc])
{
points_of_interest[cc]=get(vpm, target(halfedge(fd, tm),tm));
is_cc_treated[cc] = true;
if(++cc_treated == nb_cc)
break;
}
}
}
//this assumes the meshes does not intersect
template <class TriangleMesh, class VPM, class GT, class AABB_tree>
bool is_mesh2_in_mesh1_impl(const AABB_tree& tree1,
const std::vector<typename GT::Point_3>& points_of_interest2,
const GT& gt)
{
//for each CC, take a point on it and test bounded side
Side_of_triangle_mesh<TriangleMesh, GT, VPM> sotm(tree1, gt);
BOOST_FOREACH(const typename GT::Point_3& p, points_of_interest2)
{
if(sotm(p) == CGAL::ON_BOUNDED_SIDE) // sufficient as we know meshes do not intersect
{
return true;
}
}
return false;
}
template <class TriangleMesh, class VPM1, class VPM2, class GT>
bool is_mesh2_in_mesh1(const TriangleMesh& tm1,
const TriangleMesh& tm2,
const VPM1& vpm1,
const VPM2& vpm2,
const GT& gt)
{
typedef CGAL::AABB_face_graph_triangle_primitive<TriangleMesh, VPM1> Primitive;
typedef CGAL::AABB_traits<GT, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> AABBTree;
AABBTree tree1(faces(tm1).begin(), faces(tm1).end(), tm1, vpm1);
std::vector<typename GT::Point_3> points_of_interest2;
get_one_point_per_cc<GT>(tm2, vpm2, points_of_interest2);
return is_mesh2_in_mesh1_impl<TriangleMesh, VPM1>(tree1, points_of_interest2, gt);
}
}// namespace internal
/**
* \ingroup PMP_predicates_grp
* returns `true` if any segment of any polyline of `polylines1` intersects
* any segment of any polyline of `polylines2`, and `false` otherwise.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \tparam PolylineRange a `RandomAccessRange` of `RandomAccessRange` of points.
* The point type must be from a 3D point from a \cgal Kernel.
* \cgalDescribePolylineType
*
* @param polylines1 the first range of polylines to check for intersections.
* @param polylines2 the second range of polylines to check for intersections.
*
*/
template <class PolylineRange>
bool do_intersect(const PolylineRange& polylines1,
const PolylineRange& polylines2
#ifndef DOXYGEN_RUNNING
, const typename boost::enable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<PolylineRange>,
boost::range_value<PolylineRange>,
boost::false_type >::type
>::type
>::type* = 0//end enable_if
#endif
)
{
typedef typename boost::range_value<PolylineRange>::type Polyline;
typedef typename boost::range_value<Polyline>::type Point;
typedef typename CGAL::Kernel_traits<Point>::Kernel K;
try
{
typedef boost::function_output_iterator<internal::Throw_at_first_output> OutputIterator;
internal::compute_polylines_polylines_intersection(polylines1, polylines2, OutputIterator(), K());
}
catch( internal::Throw_at_first_output::Throw_at_first_output_exception& )
{ return true; }
return false;
}
/**
* \ingroup PMP_predicates_grp
* returns `true` if any segment of `polyline1` intersects any segment of `polyline2`, and `false` otherwise.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \tparam Polyline a `RandomAccessRange` of points.
* The point type must be from a 3D point type from \cgal Kernel.
* \cgalDescribePolylineType
*
* @param polyline1 the first polyline to check for intersections.
* @param polyline2 the second polyline to check for intersections.
*
*/
template <class Polyline>
bool do_intersect(const Polyline& polyline1,
const Polyline& polyline2
#ifndef DOXYGEN_RUNNING
, const typename boost::enable_if<
typename boost::has_range_const_iterator<Polyline>::type
>::type* = 0,
const typename boost::disable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<Polyline>,
boost::range_value<Polyline>,
boost::false_type
>::type
>::type
>::type* = 0//end enable_if
#endif
)
{
typedef typename boost::range_value<Polyline>::type Point;
typedef typename CGAL::Kernel_traits<Point>::Kernel K;
try
{
typedef boost::function_output_iterator<internal::Throw_at_first_output> OutputIterator;
internal::compute_polyline_polyline_intersection(polyline1, polyline2, OutputIterator(), K());
}
catch( internal::Throw_at_first_output::Throw_at_first_output_exception& )
{ return true; }
return false;
}
/**
* \ingroup PMP_predicates_grp
* returns `true` if any face of `tm1` intersects any face of `tm2`, and `false` otherwise.
* If `do_overlap_test_of_bounded_sides` is set to `true`, the overlap of bounded sides are tested as well. In that case, the meshes must be closed.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* @pre `CGAL::is_triangle_mesh(tm1)`
* @pre `CGAL::is_triangle_mesh(tm2)`
* @pre `!do_overlap_test_of_bounded_sides || CGAL::is_closed(tm1)`
* @pre `!do_overlap_test_of_bounded_sides || CGAL::is_closed(tm2)`
*
* @tparam TriangleMesh a model of `FaceListGraph`
* @tparam NamedParameters1 a sequence of \ref pmp_namedparameters for `tm1`
* @tparam NamedParameters2 a sequence of \ref pmp_namedparameters for `tm2`
*
* @param tm1 the first triangulated surface mesh to check for intersections
* @param tm2 the second triangulated surface mesh to check for intersections
* @param np1 optional sequence of \ref pmp_namedparameters for `tm1`, among the ones listed below
* @param np2 optional sequence of \ref pmp_namedparameters for `tm2`, among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tm1` (tm2`).
* \attention The two property maps must have the same `value_type`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalParamBegin{do_overlap_test_of_bounded_sides} if set to `true` tests also the overlap of the bounded sides of `tm1` and `tm2`.
* If `false` (default), only the intersection of surface triangles are tested.
* \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
template <class TriangleMesh,
class NamedParameters1,
class NamedParameters2>
bool do_intersect(const TriangleMesh& tm1,
const TriangleMesh& tm2,
const NamedParameters1& np1,
const NamedParameters2& np2)
{
using boost::choose_param;
using boost::get_param;
bool test_overlap = choose_param(get_param(np1, internal_np::overlap_test),false) ||
choose_param(get_param(np2, internal_np::overlap_test),false);
CGAL_precondition(CGAL::is_triangle_mesh(tm1));
CGAL_precondition(CGAL::is_triangle_mesh(tm2));
CGAL_precondition(!test_overlap || CGAL::is_closed(tm1));
CGAL_precondition(!test_overlap || CGAL::is_closed(tm2));
try
{
typedef boost::function_output_iterator<internal::Throw_at_first_output> OutputIterator;
internal::compute_face_face_intersection(tm1,tm2, OutputIterator(), np1, np2);
}
catch( internal::Throw_at_first_output::Throw_at_first_output_exception& )
{ return true; }
if (test_overlap)
{
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters1>::const_type VertexPointMap1;
typedef typename GetVertexPointMap<TriangleMesh, NamedParameters2>::const_type VertexPointMap2;
VertexPointMap1 vpm1 = choose_param(get_param(np1, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm1));
VertexPointMap2 vpm2 = choose_param(get_param(np2, internal_np::vertex_point),
get_const_property_map(boost::vertex_point, tm2));
typedef typename GetGeomTraits<TriangleMesh, NamedParameters1>::type GeomTraits;
GeomTraits gt = choose_param(get_param(np1, internal_np::geom_traits), GeomTraits());
return internal::is_mesh2_in_mesh1(tm1, tm2, vpm1, vpm2, gt) ||
internal::is_mesh2_in_mesh1(tm2, tm1, vpm2, vpm1, gt);
}
return false;
}
//convenient overload
template <class TriangleMesh>
bool do_intersect(const TriangleMesh& tm1,
const TriangleMesh& tm2,
const typename boost::disable_if<
typename boost::has_range_const_iterator<TriangleMesh>::type
>::type* = 0)
{
CGAL_precondition(CGAL::is_triangle_mesh(tm1));
CGAL_precondition(CGAL::is_triangle_mesh(tm2));
return do_intersect(tm1, tm2, parameters::all_default(), parameters::all_default());
}
/**
* \ingroup PMP_predicates_grp
* returns `true` if any face of `tm` and any segment of any polyline of `polylines` intersects, and `false` otherwise.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
* @pre `CGAL::is_triangle_mesh(tm)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam PolylineRange a `RandomAccessRange` of `RandomAccessRange` of points. The point type of the range must be the
* same as the value type of the vertex point map.
* \cgalDescribePolylineType
* @tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* @param tm the triangulated surface mesh to check for intersections
* @param polylines the range of polylines to check for intersections.
* @param np optional sequence of \ref pmp_namedparameters 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{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
template <class TriangleMesh,
class PolylineRange,
class NamedParameters>
bool do_intersect(const TriangleMesh& tm,
const PolylineRange& polylines,
const NamedParameters& np
#ifndef DOXYGEN_RUNNING
, const typename boost::enable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<PolylineRange>,
boost::range_value<PolylineRange>,
boost::false_type
>::type
>::type
>::type* = 0//end enable_if
#endif
)
{
CGAL_precondition(CGAL::is_triangle_mesh(tm));
try
{
typedef boost::function_output_iterator<internal::Throw_at_first_output> OutputIterator;
internal::compute_face_polylines_intersection(faces(tm), polylines, tm, OutputIterator(), np);
}
catch( internal::Throw_at_first_output::Throw_at_first_output_exception& )
{ return true; }
return false;
}
/**
* \ingroup PMP_predicates_grp
* returns `true` if any face of `tm` and any segment of `polyline` intersects, and `false` otherwise.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
* @pre `CGAL::is_triangle_mesh(tm)`
*
* \tparam TriangleMesh a model of `FaceListGraph`
* \tparam Polyline a `RandomAccessRange` of points. The point type of the range must be the
* same as the value type of the vertex point map.
* \cgalDescribePolylineType
* @tparam NamedParameters a sequence of \ref pmp_namedparameters
*
* @param tm the triangulated surface mesh to check for intersections
* @param polyline the polyline to check for intersections.
* @param np optional sequence of \ref pmp_namedparameters among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `tn`.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in `TriangleMesh`\cgalParamEnd
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits` \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
template <class TriangleMesh,
class Polyline,
class NamedParameters>
bool do_intersect(const TriangleMesh& tm,
const Polyline& polyline,
const NamedParameters& np
#ifndef DOXYGEN_RUNNING
, const typename boost::disable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<Polyline>,
boost::range_value<Polyline>,
boost::false_type
>::type
>::type
>::type* = 0
#endif
)
{
CGAL_precondition(CGAL::is_triangle_mesh(tm));
try
{
typedef boost::function_output_iterator<internal::Throw_at_first_output> OutputIterator;
internal::compute_face_polyline_intersection(tm,polyline, OutputIterator(), np);
}
catch( internal::Throw_at_first_output::Throw_at_first_output_exception& )
{ return true; }
return false;
}
template <class TriangleMesh,
class PolylineRange>
bool do_intersect(const TriangleMesh& tm,
const PolylineRange& polylines,
const typename boost::enable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<PolylineRange>,
boost::range_value<PolylineRange>,
boost::false_type
>::type
>::type
>::type* = 0)
{
CGAL_precondition(CGAL::is_triangle_mesh(tm));
return do_intersect(tm, polylines, parameters::all_default());
}
template <class TriangleMesh,
class Polyline>
bool do_intersect(const TriangleMesh& tm,
const Polyline& polyline,
const typename boost::disable_if<
typename boost::has_range_const_iterator<TriangleMesh>::type
>::type* = 0,
const typename boost::disable_if<
typename boost::has_range_iterator<
typename boost::mpl::eval_if<
boost::has_range_iterator<Polyline>,
boost::range_value<Polyline>,
boost::false_type
>::type
>::type
>::type* = 0)
{
CGAL_precondition(CGAL::is_triangle_mesh(tm));
return do_intersect(tm, polyline, parameters::all_default());
}
namespace internal{
template<class TriangleMeshRange,
class GT,
typename OutputIterator,
class NamedParametersRange>
struct Mesh_callback
{
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
typedef typename boost::range_value<NamedParametersRange>::type NamedParameter;
typedef typename GetVertexPointMap<TriangleMesh, NamedParameter>::const_type VPM;
typedef CGAL::AABB_face_graph_triangle_primitive<TriangleMesh, VPM> Primitive;
typedef CGAL::AABB_traits<GT, Primitive> Traits;
typedef CGAL::AABB_tree<Traits> AABBTree;
typedef typename boost::graph_traits<TriangleMesh>::face_descriptor face_descriptor;
// fill them in the operator and test for inclusion with
// Side_of_triangle_mesh.
const TriangleMeshRange& meshes;
OutputIterator m_iterator;
const bool report_overlap;
const NamedParametersRange& nps;
std::vector<AABBTree*> trees;
GT gt;
std::vector<std::vector<CGAL::Point_3<GT> > > points_of_interest;
Mesh_callback(const TriangleMeshRange& meshes,
OutputIterator iterator,
const bool report_overlap,
const GT& gt,
const NamedParametersRange& nps)
: meshes(meshes), m_iterator(iterator),
report_overlap(report_overlap), nps(nps), gt(gt)
{
std::size_t size = std::distance(meshes.begin(), meshes.end());
trees = std::vector<AABBTree*>(size, NULL);
points_of_interest.resize(size);
}
~Mesh_callback()
{
BOOST_FOREACH(AABBTree* tree, trees)
{
delete tree;
}
}
template<class TriangleMesh,
class VPM>
bool is_mesh2_in_mesh1(const TriangleMesh& tm1,
const TriangleMesh& tm2,
const std::size_t mesh_id_1,
const std::size_t mesh_id_2,
const VPM& vpm1,
const VPM& vpm2)
{
//test if tm2 is included in tm1
//get AABB_tree for tm1
if(!trees[mesh_id_1])
{
trees[mesh_id_1] = new AABBTree(faces(tm1).begin(),
faces(tm1).end(),
tm1, vpm1);
}
//get a face-index map for tm2
if(points_of_interest[mesh_id_2].size() == 0)
get_one_point_per_cc<GT>(tm2, vpm2, points_of_interest[mesh_id_2]);
//test if tm2 is included in tm1:
return is_mesh2_in_mesh1_impl<TriangleMesh, VPM, GT>(
*trees[mesh_id_1], points_of_interest[mesh_id_2], gt);
}
template<class Mesh_box>
void operator()(const Mesh_box* b1, const Mesh_box* b2)
{
using boost::choose_param;
using boost::get_param;
std::size_t mesh_id_1 = std::distance(meshes.begin(), b1->info());
std::size_t mesh_id_2 = std::distance(meshes.begin(), b2->info());
VPM vpm1 = choose_param(get_param(*(nps.begin() + mesh_id_1), internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, *b1->info()));
VPM vpm2 = choose_param(get_param(*(nps.begin() + mesh_id_2), internal_np::vertex_point),
get_const_property_map(CGAL::vertex_point, *b2->info()));
//surfacic test
if(Polygon_mesh_processing::do_intersect(*b1->info(),
*b2->info(),
Polygon_mesh_processing::parameters::vertex_point_map(vpm1)
.geom_traits(gt),
Polygon_mesh_processing::parameters::vertex_point_map(vpm2)
.geom_traits(gt)))
{
*m_iterator++ = std::make_pair(mesh_id_1, mesh_id_2);
}
//volumic test
else if(report_overlap)
{
if(!CGAL::do_overlap(b1->bbox(), b2->bbox()))
return;
if(is_mesh2_in_mesh1(*b1->info(), *b2->info(), mesh_id_1, mesh_id_2, vpm1, vpm2))
*m_iterator++ = std::make_pair(mesh_id_1, mesh_id_2);
else if(is_mesh2_in_mesh1(*b2->info(), *b1->info(), mesh_id_2, mesh_id_1, vpm2, vpm1))
*m_iterator++ = std::make_pair(mesh_id_2, mesh_id_1);
}
}
};
}//end internal
/*!
* \ingroup PMP_predicates_grp
* detects and reports all the pairs of meshes intersecting in a range of triangulated surface meshes.
* A pair of meshes intersecting is put in the output iterator `out` as a `std::pair<std::size_t, std::size_t>`,
* each index refering to the index of the triangle mesh in the input range.
* If `do_overlap_test_of_bounded_sides` is `true`, the overlap of bounded sides are tested as well. In that case, the meshes must be closed.
* This function depends on the package \ref PkgBoxIntersectionDSummary.
*
* \tparam TriangleMeshRange a model of `RandomAccessRange` of triangulated surface meshes model of `FaceListGraph`.
* \tparam OutputIterator an output iterator in which `std::pair<std::size_t, std::size_t>` can be put.
* \tparam NamedParameters a sequence of \ref pmp_namedparameters for the algorithm
* \tparam NamedParametersRange a range of named parameters for the meshes.
*
* \param range the range of triangulated surface meshes to be checked for intersections.
* \param out output iterator used to collect pairs of intersecting meshes.
* \param np an optional sequence named parameters among the one listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{geom_traits} an instance of a geometric traits class, model of `PMPSelfIntersectionTraits`.
* The default value for `geom_traits` is `CGAL::Kernel_traits<Point>::Kernel`, where `Point` is the
* value type of the vertex point map of the meshes.
* \cgalParamEnd
* \cgalParamBegin{do_overlap_test_of_bounded_sides} if set to `true` reports also overlap of bounded sides of meshes.
* If `false` (default), only the intersection of surface triangles are tested.
* \cgalParamEnd
* \cgalNamedParamsEnd
* \param nps an optional range of `vertex_point_map` named parameters containing the `VertexPointMap` of each mesh in `range`, in the same order.
* If this parameter is omitted, then an internal property map for `CGAL::vertex_point_t` must be available for every mesh in the range.
* All the vertex point maps must be of the same type.
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of a mesh.
* If this parameter is omitted, an internal property map for
* `CGAL::vertex_point_t` must be available in the triangle mesh type used in the range
* \cgalParamEnd
* \cgalNamedParamsEnd
*/
template <class TriangleMeshRange,
class OutputIterator,
class NamedParameters,
class NamedParametersRange>
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
OutputIterator out,
NamedParameters np,
NamedParametersRange nps)
{
using boost::choose_param;
using boost::get_param;
typedef typename TriangleMeshRange::const_iterator TriangleMeshIterator;
bool report_overlap = choose_param(get_param(np, internal_np::overlap_test),false);
typedef CGAL::Box_intersection_d::Box_with_info_d<double, 3, TriangleMeshIterator> Mesh_box;
std::vector<Mesh_box> boxes;
boxes.reserve(std::distance(range.begin(), range.end()));
for(TriangleMeshIterator it = range.begin(); it != range.end(); ++it)
{
boxes.push_back( Mesh_box(Polygon_mesh_processing::bbox(*it), it) );
}
std::vector<Mesh_box*> boxes_ptr(
boost::make_counting_iterator(&boxes[0]),
boost::make_counting_iterator(&boxes[0]+boxes.size()));
typedef typename boost::range_value<NamedParametersRange>::type NP_rng;
typedef typename boost::range_value<TriangleMeshRange>::type TriangleMesh;
typedef typename GetGeomTraits<TriangleMesh, NamedParameters, NP_rng>::type GT;
GT gt = choose_param(get_param(np, internal_np::geom_traits), GT());
//get all the pairs of meshes intersecting (no strict inclusion test)
std::ptrdiff_t cutoff = 2000;
internal::Mesh_callback<TriangleMeshRange, GT, OutputIterator, NamedParametersRange> callback(range, out, report_overlap, gt, nps);
CGAL::box_self_intersection_d(boxes_ptr.begin(), boxes_ptr.end(),
callback, cutoff);
return callback.m_iterator;
}
template <class TriangleMeshRange, class NamedParameters, class OutputIterator>
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
OutputIterator out,
NamedParameters np)
{
std::vector<cgal_bgl_named_params<bool, internal_np::all_default_t> >nps(
std::distance(range.begin(), range.end()), parameters::all_default());
return intersecting_meshes(range, out, np, nps);
}
template <class TriangleMeshRange, class OutputIterator>
OutputIterator intersecting_meshes(const TriangleMeshRange& range,
OutputIterator out)
{
return intersecting_meshes(range, out, parameters::all_default());
}
/**
* \ingroup PMP_corefinement_grp
* computes the intersection of triangles of `tm1` and `tm2`. The output is a
* set of polylines with all vertices but endpoints being of degree 2.
*
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm1)` \endlink
* \pre \link CGAL::Polygon_mesh_processing::does_self_intersect() `!CGAL::Polygon_mesh_processing::does_self_intersect(tm2)` \endlink
*
* @tparam TriangleMesh a model of `MutableFaceGraph`, `HalfedgeListGraph` and `FaceListGraph`
* @tparam NamedParameters1 a sequence of \ref pmp_namedparameters "Named Parameters"
* @tparam NamedParameters2 a sequence of \ref pmp_namedparameters "Named Parameters"
* @tparam OutputIterator an output iterator in which `std::vector` of points
* can be put. The point type is the one from the
* vertex property map
*
* @param tm1 first input triangulated surface mesh
* @param tm2 second input triangulated surface mesh
* @param polyline_output output iterator of polylines. Each polyline will be
* given as a vector of points
* @param np1 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
* @param np2 optional sequence of \ref pmp_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map}
* a property map with the points associated to the vertices of `tm1`
* (`tm2`). The two property map types must be the same.
* \cgalParamEnd
* \cgalParamBegin{throw_on_self_intersection} if `true`, for each input triangle mesh,
* the set of triangles close to the intersection of `tm1` and `tm2` will be
* checked for self-intersection and `CGAL::Polygon_mesh_processing::Corefinement::Self_intersection_exception`
* will be thrown if at least one is found (`np1` only).
* \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
template <class OutputIterator,
class TriangleMesh,
class NamedParameters1,
class NamedParameters2 >
OutputIterator
surface_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator polyline_output,
const NamedParameters1& np1,
const NamedParameters2& np2)
{
const bool throw_on_self_intersection =
boost::choose_param(get_param(np1, internal_np::throw_on_self_intersection), false);
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters1>::const_type Vpm;
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters2>::const_type Vpm2;
CGAL_USE_TYPE(Vpm2);
CGAL_assertion_code(
static const bool same_vpm = (boost::is_same<Vpm,Vpm2>::value);)
CGAL_static_assertion(same_vpm);
Vpm vpm1 = choose_const_pmap(get_param(np1, internal_np::vertex_point),
tm1,
vertex_point);
Vpm vpm2 = choose_const_pmap(get_param(np2, internal_np::vertex_point),
tm2,
vertex_point);
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm>
functor(tm1, tm2, vpm1, vpm2);
return functor(polyline_output, throw_on_self_intersection, true);
}
namespace experimental {
/**
* \ingroup PMP_corefinement_grp
* computes the autointersection of triangles of `tm`. The output is a
* set of polylines with all vertices but endpoints being of degree 2.
*
*
* @tparam TriangleMesh a model of `HalfedgeListGraph` and `FaceListGraph`
* @tparam NamedParameters a sequence of \ref namedparameters
* @tparam OutputIterator an output iterator in which `std::vector` of points
* can be put. The point type is the one from the
* vertex property map
*
* @param tm input triangulated surface mesh
* @param polyline_output output iterator of polylines. Each polyline will be
* given as a vector of points
* @param np optional sequence of \ref namedparameters among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{vertex_point_map}
* a property map with the points associated to the vertices of `tm`
* \cgalParamEnd
* \cgalNamedParamsEnd
*
*/
template <class OutputIterator,
class TriangleMesh,
class NamedParameters >
OutputIterator
surface_self_intersection(const TriangleMesh& tm,
OutputIterator polyline_output,
const NamedParameters& np)
{
// Vertex point maps
typedef typename GetVertexPointMap<TriangleMesh,
NamedParameters>::const_type Vpm;
Vpm vpm = choose_const_pmap(get_param(np, internal_np::vertex_point),
tm,
vertex_point);
// surface intersection algorithm call
typedef Corefinement::Default_surface_intersection_visitor<TriangleMesh,
true> Visitor;
Corefinement::Intersection_of_triangle_meshes<TriangleMesh,Vpm, Visitor>
functor(tm, vpm);
polyline_output=functor(polyline_output, true);
return polyline_output;
}
} //end of namespace experimental
template <class OutputIterator,
class TriangleMesh >
OutputIterator
surface_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator polyline_output)
{
return surface_intersection(tm1, tm2, polyline_output,
CGAL::Polygon_mesh_processing::parameters::all_default(),
CGAL::Polygon_mesh_processing::parameters::all_default());
}
template <class OutputIterator,
class TriangleMesh,
class NamedParameters1>
OutputIterator
surface_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator polyline_output,
const NamedParameters1& np)
{
return surface_intersection(tm1, tm2, polyline_output, np,
CGAL::Polygon_mesh_processing::parameters::all_default());
}
#ifndef CGAL_NO_DEPRECATED_CODE
template <class OutputIterator,
class TriangleMesh,
class NamedParameters1,
class NamedParameters2 >
OutputIterator
surface_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator polyline_output,
const NamedParameters1& np1,
const NamedParameters2& np2,
const bool throw_on_self_intersection)
{
return surface_intersection(tm1, tm2, polyline_output,
np1.throw_on_self_intersection(throw_on_self_intersection), np2);
}
template <class OutputIterator,
class TriangleMesh >
OutputIterator
surface_intersection(const TriangleMesh& tm1,
const TriangleMesh& tm2,
OutputIterator polyline_output,
const bool throw_on_self_intersection)
{
return surface_intersection(tm1, tm2, polyline_output,
CGAL::Polygon_mesh_processing::parameters::throw_on_self_intersection(throw_on_self_intersection),
CGAL::Polygon_mesh_processing::parameters::all_default());
}
#endif
namespace experimental {
template <class OutputIterator,
class TriangleMesh >
OutputIterator
surface_self_intersection(const TriangleMesh& tm,
OutputIterator polyline_output)
{
return surface_self_intersection(tm, polyline_output,
CGAL::Polygon_mesh_processing::parameters::all_default()
);
}
} //end of namespace experimental
} } //end of namespace CGAL::Polygon_mesh_processing
#include <CGAL/enable_warnings.h>
#endif // CGAL_POLYGON_MESH_PROCESSING_INTERSECTION_H