mirror of https://github.com/CGAL/cgal
Merge pull request #4404 from MaelRL/CGAL-Optimal_bounding_box-GF
New Package: Optimal Bounding Box
This commit is contained in:
commit
a860a7ea5a
45
.travis.yml
45
.travis.yml
|
|
@ -30,28 +30,29 @@ env:
|
|||
- PACKAGE='Minkowski_sum_2 Minkowski_sum_3 Modifier '
|
||||
- PACKAGE='Modular_arithmetic Nef_2 Nef_3 '
|
||||
- PACKAGE='Nef_S2 NewKernel_d Number_types '
|
||||
- PACKAGE='OpenNL Optimal_transportation_reconstruction_2 Optimisation_basic '
|
||||
- PACKAGE='Partition_2 Periodic_2_triangulation_2 Periodic_3_mesh_3 '
|
||||
- PACKAGE='Periodic_3_triangulation_3 Periodic_4_hyperbolic_triangulation_2 Point_set_2 '
|
||||
- PACKAGE='Point_set_3 Point_set_processing_3 Poisson_surface_reconstruction_3 '
|
||||
- PACKAGE='Polygon Polygon_mesh_processing Polygonal_surface_reconstruction '
|
||||
- PACKAGE='Polyhedron Polyhedron_IO Polyline_simplification_2 '
|
||||
- PACKAGE='Polynomial Polytope_distance_d Principal_component_analysis '
|
||||
- PACKAGE='Principal_component_analysis_LGPL Profiling_tools Property_map '
|
||||
- PACKAGE='QP_solver Random_numbers Ridges_3 '
|
||||
- PACKAGE='STL_Extension Scale_space_reconstruction_3 Scripts '
|
||||
- PACKAGE='SearchStructures Segment_Delaunay_graph_2 Segment_Delaunay_graph_Linf_2 '
|
||||
- PACKAGE='Set_movable_separability_2 Shape_detection Skin_surface_3 '
|
||||
- PACKAGE='Snap_rounding_2 Solver_interface Spatial_searching '
|
||||
- PACKAGE='Spatial_sorting Straight_skeleton_2 Stream_lines_2 '
|
||||
- PACKAGE='Stream_support Subdivision_method_3 Surface_mesh '
|
||||
- PACKAGE='Surface_mesh_approximation Surface_mesh_deformation Surface_mesh_parameterization '
|
||||
- PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification '
|
||||
- PACKAGE='Surface_mesh_skeletonization Surface_mesh_topology Surface_mesher '
|
||||
- PACKAGE='Surface_sweep_2 TDS_2 TDS_3 '
|
||||
- PACKAGE='Testsuite Three Triangulation '
|
||||
- PACKAGE='Triangulation_2 Triangulation_3 Union_find '
|
||||
- PACKAGE='Visibility_2 Voronoi_diagram_2 wininst '
|
||||
- PACKAGE='OpenNL Optimal_bounding_box Optimal_transportation_reconstruction_2 '
|
||||
- PACKAGE='Optimisation_basic Partition_2 Periodic_2_triangulation_2 '
|
||||
- PACKAGE='Periodic_3_mesh_3 Periodic_3_triangulation_3 Periodic_4_hyperbolic_triangulation_2 '
|
||||
- PACKAGE='Point_set_2 Point_set_3 Point_set_processing_3 '
|
||||
- PACKAGE='Poisson_surface_reconstruction_3 Polygon Polygon_mesh_processing '
|
||||
- PACKAGE='Polygonal_surface_reconstruction Polyhedron Polyhedron_IO '
|
||||
- PACKAGE='Polyline_simplification_2 Polynomial Polytope_distance_d '
|
||||
- PACKAGE='Principal_component_analysis Principal_component_analysis_LGPL Profiling_tools '
|
||||
- PACKAGE='Property_map QP_solver Random_numbers '
|
||||
- PACKAGE='Ridges_3 STL_Extension Scale_space_reconstruction_3 '
|
||||
- PACKAGE='Scripts SearchStructures Segment_Delaunay_graph_2 '
|
||||
- PACKAGE='Segment_Delaunay_graph_Linf_2 Set_movable_separability_2 Shape_detection '
|
||||
- PACKAGE='Skin_surface_3 Snap_rounding_2 Solver_interface '
|
||||
- PACKAGE='Spatial_searching Spatial_sorting Straight_skeleton_2 '
|
||||
- PACKAGE='Stream_lines_2 Stream_support Subdivision_method_3 '
|
||||
- PACKAGE='Surface_mesh Surface_mesh_approximation Surface_mesh_deformation '
|
||||
- PACKAGE='Surface_mesh_parameterization Surface_mesh_segmentation Surface_mesh_shortest_path '
|
||||
- PACKAGE='Surface_mesh_simplification Surface_mesh_skeletonization Surface_mesh_topology '
|
||||
- PACKAGE='Surface_mesher Surface_sweep_2 TDS_2 '
|
||||
- PACKAGE='TDS_3 Testsuite Three '
|
||||
- PACKAGE='Triangulation Triangulation_2 Triangulation_3 '
|
||||
- PACKAGE='Union_find Visibility_2 Voronoi_diagram_2 '
|
||||
- PACKAGE='wininst '
|
||||
compiler: clang
|
||||
install:
|
||||
- echo "$PWD"
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ Nef_S2
|
|||
NewKernel_d
|
||||
Number_types
|
||||
OpenNL
|
||||
Optimal_bounding_box
|
||||
Optimal_transportation_reconstruction_2
|
||||
Optimisation_basic
|
||||
Partition_2
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <CGAL/Regular_triangulation_2.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Regular_triangulation_2.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/graph/kruskal_min_spanning_tree.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
|
@ -75,7 +75,7 @@ int main(int argc,char* argv[])
|
|||
std::list<edge_descriptor> mst;
|
||||
boost::kruskal_minimum_spanning_tree(tr, std::back_inserter(mst),
|
||||
vertex_index_map(vertex_index_pmap)
|
||||
.weight_map(CGAL::internal::boost_::make_function_property_map<
|
||||
.weight_map(boost::make_function_property_map<
|
||||
edge_descriptor, FT, Edge_weight_functor>(Edge_weight_functor(tr))));
|
||||
|
||||
std::cout << "The edges of the Euclidean mimimum spanning tree:" << std::endl;
|
||||
|
|
|
|||
|
|
@ -194,19 +194,6 @@ get_parameter(const Named_function_parameters<T, Tag, Base>& np, Query_tag tag)
|
|||
return internal_np::get_parameter_impl(static_cast<const internal_np::Named_params_impl<T, Tag, Base>&>(np), tag);
|
||||
}
|
||||
|
||||
// single parameter so that we can avoid a default construction
|
||||
template <typename D>
|
||||
D choose_parameter(const internal_np::Param_not_found&)
|
||||
{
|
||||
return D();
|
||||
}
|
||||
|
||||
template <typename D, typename T>
|
||||
const T& choose_parameter(const T& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
// Two parameters, non-trivial default value
|
||||
template <typename D>
|
||||
D choose_parameter(const internal_np::Param_not_found&, const D& d)
|
||||
|
|
@ -220,6 +207,19 @@ const T& choose_parameter(const T& t, const D&)
|
|||
return t;
|
||||
}
|
||||
|
||||
// single parameter so that we can avoid a default construction
|
||||
template <typename D>
|
||||
D choose_parameter(const internal_np::Param_not_found&)
|
||||
{
|
||||
return D();
|
||||
}
|
||||
|
||||
template <typename D, typename T>
|
||||
const T& choose_parameter(const T& t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
bool inline is_default_parameter(const internal_np::Param_not_found&)
|
||||
{
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ typename BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_
|
|||
CGAL::dynamic_##DTYPE##_property_t<STYPE>, \
|
||||
Graph, NamedParameters>::const_type \
|
||||
get_initialized_##DTYPE##_index_map(const Graph& g, \
|
||||
const NamedParameters& np) \
|
||||
const NamedParameters& np) \
|
||||
{ \
|
||||
typedef BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_t, \
|
||||
boost::DTYPE##_index_t, \
|
||||
|
|
@ -251,7 +251,7 @@ typename BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_
|
|||
CGAL::dynamic_##DTYPE##_property_t<STYPE>, \
|
||||
Graph, NamedParameters>::type \
|
||||
get_initialized_##DTYPE##_index_map(Graph& g, \
|
||||
const NamedParameters& np) \
|
||||
const NamedParameters& np) \
|
||||
{ \
|
||||
typedef BGL::internal::GetInitializedIndexMap<CGAL::internal_np::DTYPE##_index_t, \
|
||||
boost::DTYPE##_index_t, \
|
||||
|
|
|
|||
|
|
@ -155,6 +155,9 @@ CGAL_add_named_parameter(max_number_of_proxies_t, max_number_of_proxies, max_num
|
|||
CGAL_add_named_parameter(min_error_drop_t, min_error_drop, min_error_drop)
|
||||
CGAL_add_named_parameter(number_of_relaxations_t, number_of_relaxations, number_of_relaxations)
|
||||
|
||||
// List of named parameters used in Optimal_bounding_box package
|
||||
CGAL_add_named_parameter(use_convex_hull_t, use_convex_hull, use_convex_hull)
|
||||
|
||||
// meshing parameters
|
||||
CGAL_add_named_parameter(subdivision_ratio_t, subdivision_ratio, subdivision_ratio)
|
||||
CGAL_add_named_parameter(relative_to_chord_t, relative_to_chord, relative_to_chord)
|
||||
|
|
|
|||
|
|
@ -86,22 +86,25 @@ void test(const NamedParameters& np)
|
|||
assert(get_parameter(np, CGAL::internal_np::require_same_orientation).v == 49);
|
||||
assert(get_parameter(np, CGAL::internal_np::use_bool_op_to_clip_surface).v == 50);
|
||||
assert(get_parameter(np, CGAL::internal_np::face_size_map).v == 52);
|
||||
assert(get_parameter(np, CGAL::internal_np::snapping_tolerance).v == 57);
|
||||
assert(get_parameter(np, CGAL::internal_np::use_angle_smoothing).v == 53);
|
||||
assert(get_parameter(np, CGAL::internal_np::use_area_smoothing).v == 54);
|
||||
assert(get_parameter(np, CGAL::internal_np::use_Delaunay_flips).v == 55);
|
||||
assert(get_parameter(np, CGAL::internal_np::use_safety_constraints).v == 56);
|
||||
assert(get_parameter(np, CGAL::internal_np::area_threshold).v == 57);
|
||||
assert(get_parameter(np, CGAL::internal_np::volume_threshold).v == 58);
|
||||
assert(get_parameter(np, CGAL::internal_np::dry_run).v == 59);
|
||||
assert(get_parameter(np, CGAL::internal_np::do_lock_mesh).v == 60);
|
||||
assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 61);
|
||||
assert(get_parameter(np, CGAL::internal_np::snapping_tolerance).v == 59);
|
||||
assert(get_parameter(np, CGAL::internal_np::dry_run).v == 60);
|
||||
assert(get_parameter(np, CGAL::internal_np::do_lock_mesh).v == 61);
|
||||
assert(get_parameter(np, CGAL::internal_np::maximum_number_of_faces).v == 78910);
|
||||
assert(get_parameter(np, CGAL::internal_np::do_simplify_border).v == 62);
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
assert(get_parameter(np, CGAL::internal_np::get_cost_policy).v == 34);
|
||||
assert(get_parameter(np, CGAL::internal_np::get_placement_policy).v == 35);
|
||||
|
||||
// Named parameters that we use in the package 'Optimal_bounding_box'
|
||||
assert(get_parameter(np, CGAL::internal_np::use_convex_hull).v == 63);
|
||||
|
||||
// To-be-documented named parameters
|
||||
assert(get_parameter(np, CGAL::internal_np::face_normal).v == 36);
|
||||
assert(get_parameter(np, CGAL::internal_np::random_seed).v == 37);
|
||||
|
|
@ -176,7 +179,6 @@ void test(const NamedParameters& np)
|
|||
check_same_type<49>(get_parameter(np, CGAL::internal_np::require_same_orientation));
|
||||
check_same_type<50>(get_parameter(np, CGAL::internal_np::use_bool_op_to_clip_surface));
|
||||
check_same_type<52>(get_parameter(np, CGAL::internal_np::face_size_map));
|
||||
check_same_type<57>(get_parameter(np, CGAL::internal_np::snapping_tolerance));
|
||||
check_same_type<53>(get_parameter(np, CGAL::internal_np::use_angle_smoothing));
|
||||
check_same_type<54>(get_parameter(np, CGAL::internal_np::use_area_smoothing));
|
||||
check_same_type<55>(get_parameter(np, CGAL::internal_np::use_Delaunay_flips));
|
||||
|
|
@ -196,15 +198,19 @@ void test(const NamedParameters& np)
|
|||
|
||||
check_same_type<57>(get_parameter(np, CGAL::internal_np::area_threshold));
|
||||
check_same_type<58>(get_parameter(np, CGAL::internal_np::volume_threshold));
|
||||
check_same_type<59>(get_parameter(np, CGAL::internal_np::dry_run));
|
||||
check_same_type<60>(get_parameter(np, CGAL::internal_np::do_lock_mesh));
|
||||
check_same_type<61>(get_parameter(np, CGAL::internal_np::do_simplify_border));
|
||||
check_same_type<59>(get_parameter(np, CGAL::internal_np::snapping_tolerance));
|
||||
check_same_type<60>(get_parameter(np, CGAL::internal_np::dry_run));
|
||||
check_same_type<61>(get_parameter(np, CGAL::internal_np::do_lock_mesh));
|
||||
check_same_type<62>(get_parameter(np, CGAL::internal_np::do_simplify_border));
|
||||
check_same_type<78910>(get_parameter(np, CGAL::internal_np::maximum_number_of_faces));
|
||||
|
||||
// Named parameters that we use in the package 'Surface Mesh Simplification'
|
||||
check_same_type<34>(get_parameter(np, CGAL::internal_np::get_cost_policy));
|
||||
check_same_type<35>(get_parameter(np, CGAL::internal_np::get_placement_policy));
|
||||
|
||||
// Named parameters that we use in the package 'Optimal_bounding_box'
|
||||
check_same_type<63>(get_parameter(np, CGAL::internal_np::use_convex_hull));
|
||||
|
||||
// To-be-documented named parameters
|
||||
check_same_type<36>(get_parameter(np, CGAL::internal_np::face_normal));
|
||||
check_same_type<37>(get_parameter(np, CGAL::internal_np::random_seed));
|
||||
|
|
@ -322,7 +328,6 @@ int main()
|
|||
.use_bool_op_to_clip_surface(A<50>(50))
|
||||
.use_binary_mode(A<51>(51))
|
||||
.face_size_map(A<52>(52))
|
||||
.snapping_tolerance(A<57>(57))
|
||||
.use_angle_smoothing(A<53>(53))
|
||||
.use_area_smoothing(A<54>(54))
|
||||
.use_Delaunay_flips(A<55>(55))
|
||||
|
|
@ -340,9 +345,11 @@ int main()
|
|||
.i_used_for_volume_orientation(A<12350>(12350))
|
||||
.area_threshold(A<57>(57))
|
||||
.volume_threshold(A<58>(58))
|
||||
.dry_run(A<59>(59))
|
||||
.do_lock_mesh(A<60>(60))
|
||||
.do_simplify_border(A<61>(61))
|
||||
.snapping_tolerance(A<59>(59))
|
||||
.dry_run(A<60>(60))
|
||||
.do_lock_mesh(A<61>(61))
|
||||
.do_simplify_border(A<62>(62))
|
||||
.use_convex_hull(A<63>(63))
|
||||
.point_map(A<9000>(9000))
|
||||
.query_point_map(A<9001>(9001))
|
||||
.normal_map(A<9002>(9002))
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ is specified with each function.
|
|||
\cgalHasModel `CGAL::Convex_hull_traits_2<R>`
|
||||
\cgalHasModel `CGAL::Convex_hull_traits_adapter_2<R>`
|
||||
\cgalHasModel `CGAL::Projection_traits_xy_3<K>`
|
||||
\cgalHasModel `CGAL::Projection_traits_yz_3 <K>`
|
||||
\cgalHasModel `CGAL::Projection_traits_yz_3<K>`
|
||||
\cgalHasModel `CGAL::Projection_traits_xz_3<K>`
|
||||
|
||||
\sa `IsStronglyConvexTraits_3`
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <CGAL/algorithm.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <CGAL/convex_hull_3_to_polyhedron_3.h>
|
||||
#include <CGAL/convex_hull_3_to_face_graph.h>
|
||||
#include <CGAL/Delaunay_triangulation_3.h>
|
||||
#include <CGAL/convex_hull_incremental_3.h>
|
||||
#include <CGAL/Timer.h>
|
||||
|
|
@ -68,7 +68,7 @@ int main(int argc,char** argv)
|
|||
time.stop();
|
||||
std::cout << "Delaunay " << time.time() << std::endl;
|
||||
time.start();
|
||||
CGAL::convex_hull_3_to_polyhedron_3(T,poly);
|
||||
CGAL::convex_hull_3_to_face_graph(T,poly);
|
||||
time.stop();
|
||||
std::cout << "Delaunay+to_poly " << time.time() <<" "<< poly.size_of_vertices() << std::endl;
|
||||
poly.clear();
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgConvexHull3Functions
|
||||
|
||||
fills a polyhedron with the convex hull of a set of 3D points contained in a 3D triangulation of \cgal.
|
||||
|
||||
The polyhedron `P` is cleared and the convex hull of the set of 3D points is stored in `P`.
|
||||
|
||||
\deprecated since \cgal 4.10. Use `convex_hull_3_to_face_graph()` instead.
|
||||
|
||||
\attention This function does not compute the plane equations of the faces of `P`.
|
||||
|
||||
\attention This function works only for `CGAL::Polyhedron_3<Traits>`, and users who want
|
||||
to generate a `Surface_mesh` or any other model of a `FaceGraph` may use `convex_hull_3_to_face_graph()` instead.
|
||||
|
||||
\pre `T.dimension()`==3.
|
||||
|
||||
\tparam Triangulation is a \cgal 3D triangulation.
|
||||
\tparam Polyhedron is an instantiation of `CGAL::Polyhedron_3<Traits>`.
|
||||
|
||||
\sa `convex_hull_3()`
|
||||
\sa `link_to_face_graph()`
|
||||
|
||||
*/
|
||||
template <class Triangulation, class Polyhedron>
|
||||
void convex_hull_3_to_polyhedron_3(const Triangulation& T,Polyhedron& P);
|
||||
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
Requirements of the traits class of the function `CGAL::convex_hull_3()`.
|
||||
|
||||
\cgalHasModel `CGAL::Convex_hull_traits_3`
|
||||
\cgalHasModel All models of `Kernel`
|
||||
\cgalHasModel `CGAL::Convex_hull_traits_3<K>`
|
||||
\cgalHasModel `CGAL::Extreme_points_traits_adapter_3<PPM, GT>`
|
||||
|
||||
*/
|
||||
class ConvexHullTraits_3 {
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ namespace CGAL
|
|||
boost::optional<typename Kernel_traits<typename std::iterator_traits<PlaneIterator>::value_type>::Kernel::Point_3> const& origin = boost::none) {
|
||||
typedef typename Kernel_traits<typename std::iterator_traits<PlaneIterator>::value_type>::Kernel K;
|
||||
typedef typename K::Point_3 Point_3;
|
||||
typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
typedef typename Convex_hull_3::internal::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
|
||||
halfspace_intersection_with_constructions_3(pbegin, pend, P, origin, Traits());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,216 +24,254 @@
|
|||
#include <CGAL/convex_hull_3.h>
|
||||
#include <CGAL/result_of.h>
|
||||
|
||||
|
||||
|
||||
namespace CGAL {
|
||||
namespace Convex_hull_3 {
|
||||
namespace internal {
|
||||
|
||||
namespace Convex_hull_impl{
|
||||
template <class F, class PointPropertyMap>
|
||||
struct Forward_functor
|
||||
: public F
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
|
||||
Forward_functor(const PointPropertyMap& vpm,
|
||||
const F& f) : F(f), vpm_(vpm) {}
|
||||
|
||||
Forward_functor(const PointPropertyMap& vpm, const F& f) : F(f), vpm_(vpm) {}
|
||||
|
||||
template <class Vertex>
|
||||
typename cpp11::result_of<F(const Vertex&, const Vertex&)>::type
|
||||
operator() (const Vertex& p, const Vertex& q) const
|
||||
operator()(const Vertex& p, const Vertex& q) const
|
||||
{
|
||||
return static_cast<const F*>(this)->operator()(get(vpm_,p),get(vpm_,q));
|
||||
return static_cast<const F*>(this)->operator()(get(vpm_, p), get(vpm_, q));
|
||||
}
|
||||
|
||||
template <class Vertex>
|
||||
typename cpp11::result_of<F(const Vertex&, const Vertex&, const Vertex&)>::type
|
||||
operator() (const Vertex& p, const Vertex& q, const Vertex& r) const
|
||||
operator()(const Vertex& p, const Vertex& q, const Vertex& r) const
|
||||
{
|
||||
return static_cast<const F*>(this)->operator()(
|
||||
get(vpm_,p),
|
||||
get(vpm_,q),
|
||||
get(vpm_,r));
|
||||
return static_cast<const F*>(this)->operator()(get(vpm_, p),
|
||||
get(vpm_, q),
|
||||
get(vpm_, r));
|
||||
}
|
||||
|
||||
template <class Vertex>
|
||||
typename cpp11::result_of<F(const Vertex&, const Vertex&, const Vertex&, const Vertex&)>::type
|
||||
operator() (const Vertex& p, const Vertex& q, const Vertex& r, const Vertex& s) const
|
||||
operator()(const Vertex& p, const Vertex& q, const Vertex& r, const Vertex& s) const
|
||||
{
|
||||
return static_cast<const F*>(this)->operator()(
|
||||
get(vpm_,p),
|
||||
get(vpm_,q),
|
||||
get(vpm_,r),
|
||||
get(vpm_,s));
|
||||
return static_cast<const F*>(this)->operator()(get(vpm_, p),
|
||||
get(vpm_, q),
|
||||
get(vpm_, r),
|
||||
get(vpm_, s));
|
||||
}
|
||||
};
|
||||
}//end Convex_hull_impl
|
||||
template<
|
||||
class PointPropertyMap,
|
||||
class Base_traits=typename internal::Convex_hull_3::Default_traits_for_Chull_3<
|
||||
typename boost::property_traits<PointPropertyMap>::value_type>::type
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Convex_hull_3
|
||||
|
||||
template<class PointPropertyMap,
|
||||
class Base_traits = typename Convex_hull_3::internal::Default_traits_for_Chull_3<
|
||||
typename boost::property_traits<PointPropertyMap>::value_type>::type
|
||||
>
|
||||
class Extreme_points_traits_adapter_3
|
||||
:public Base_traits
|
||||
: public Base_traits
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
|
||||
|
||||
public:
|
||||
Extreme_points_traits_adapter_3(const PointPropertyMap& vpmap, Base_traits base=Base_traits())
|
||||
:Base_traits(base), vpm_(vpmap)
|
||||
{}
|
||||
typedef typename boost::property_traits<PointPropertyMap>::key_type Vertex;
|
||||
typedef Vertex Point_3;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Base_traits::Equal_3, PointPropertyMap> Equal_3;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Base_traits::Collinear_3, PointPropertyMap> Collinear_3;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Base_traits::Coplanar_3, PointPropertyMap> Coplanar_3;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Base_traits::Less_distance_to_point_3, PointPropertyMap> Less_distance_to_point_3;
|
||||
Extreme_points_traits_adapter_3(const PointPropertyMap& vpmap,
|
||||
Base_traits base = Base_traits())
|
||||
:
|
||||
Base_traits(base), vpm_(vpmap)
|
||||
{ }
|
||||
|
||||
typedef typename boost::property_traits<PointPropertyMap>::key_type Vertex;
|
||||
typedef Vertex Point_3;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Base_traits::Equal_3, PointPropertyMap> Equal_3;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Base_traits::Collinear_3, PointPropertyMap> Collinear_3;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Base_traits::Coplanar_3, PointPropertyMap> Coplanar_3;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Base_traits::Less_distance_to_point_3, PointPropertyMap> Less_distance_to_point_3;
|
||||
|
||||
class Less_signed_distance_to_plane_3
|
||||
:public Base_traits::Less_signed_distance_to_plane_3
|
||||
: public Base_traits::Less_signed_distance_to_plane_3
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
const typename Base_traits::Less_signed_distance_to_plane_3& base;
|
||||
|
||||
public:
|
||||
typedef typename Base_traits::Plane_3 Plane_3;
|
||||
typedef typename Base_traits::Plane_3 Plane_3;
|
||||
typedef bool result_type;
|
||||
|
||||
typedef bool result_type;
|
||||
Less_signed_distance_to_plane_3(const PointPropertyMap& map,
|
||||
const typename Base_traits::Less_signed_distance_to_plane_3& base)
|
||||
: Base_traits::Less_signed_distance_to_plane_3(base), vpm_(map), base(base)
|
||||
{ }
|
||||
|
||||
Less_signed_distance_to_plane_3(
|
||||
const PointPropertyMap& map,
|
||||
const typename Base_traits::Less_signed_distance_to_plane_3& base):
|
||||
Base_traits::Less_signed_distance_to_plane_3(base),vpm_(map), base(base){}
|
||||
|
||||
bool
|
||||
operator()( const Plane_3& h, const Vertex& p, const Vertex& q) const
|
||||
bool operator()(const Plane_3& h, const Vertex& p, const Vertex& q) const
|
||||
{
|
||||
return base(h, get(vpm_,p), get(vpm_,q));
|
||||
return base(h, get(vpm_, p), get(vpm_, q));
|
||||
}
|
||||
};
|
||||
|
||||
Equal_3 equal_3_object() const
|
||||
{ return Equal_3(vpm_, static_cast<const Base_traits*>(this)->equal_3_object()); }
|
||||
Collinear_3 collinear_3_object() const
|
||||
{ return Collinear_3(vpm_, static_cast<const Base_traits*>(this)->collinear_3_object()); }
|
||||
Coplanar_3 coplanar_3_object() const
|
||||
{ return Coplanar_3(vpm_, static_cast<const Base_traits*>(this)->coplanar_3_object()); }
|
||||
Less_distance_to_point_3 less_distance_to_point_3_object() const
|
||||
{ return Less_distance_to_point_3(vpm_, static_cast<const Base_traits*>(this)->less_distance_to_point_3_object()); }
|
||||
Less_signed_distance_to_plane_3 less_signed_distance_to_plane_3_object() const
|
||||
{ return Less_signed_distance_to_plane_3(vpm_, static_cast<const Base_traits*>(this)->less_signed_distance_to_plane_3_object()); }
|
||||
|
||||
Equal_3 equal_3_object () const {return Equal_3(vpm_,static_cast<const Base_traits*>(this)->equal_3_object() );}
|
||||
Collinear_3 collinear_3_object () const {return Collinear_3(vpm_,static_cast<const Base_traits*>(this)->collinear_3_object() );}
|
||||
Coplanar_3 coplanar_3_object () const {return Coplanar_3(vpm_,static_cast<const Base_traits*>(this)->coplanar_3_object() );}
|
||||
Less_distance_to_point_3 less_distance_to_point_3_object() const {
|
||||
return Less_distance_to_point_3(vpm_,static_cast<const Base_traits*>(this)->less_distance_to_point_3_object() );}
|
||||
Less_signed_distance_to_plane_3 less_signed_distance_to_plane_3_object() const {
|
||||
return Less_signed_distance_to_plane_3(
|
||||
vpm_,static_cast<const Base_traits*>(this)->less_signed_distance_to_plane_3_object() );
|
||||
}
|
||||
|
||||
class Construct_plane_3:public Base_traits::Construct_plane_3
|
||||
class Construct_plane_3
|
||||
: public Base_traits::Construct_plane_3
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
const typename Base_traits::Construct_plane_3& base;
|
||||
|
||||
public:
|
||||
Construct_plane_3(const PointPropertyMap& map, const typename Base_traits::Construct_plane_3& base):
|
||||
Base_traits::Construct_plane_3(base),vpm_(map), base(base){}
|
||||
typename Base_traits::Plane_3 operator()(const Vertex& p, const Vertex& q, const Vertex& r)const
|
||||
Construct_plane_3(const PointPropertyMap& map,
|
||||
const typename Base_traits::Construct_plane_3& base)
|
||||
: Base_traits::Construct_plane_3(base), vpm_(map), base(base)
|
||||
{ }
|
||||
|
||||
typename Base_traits::Plane_3 operator()(const Vertex& p, const Vertex& q, const Vertex& r) const
|
||||
{
|
||||
return base(get(vpm_,p),get(vpm_,q),get(vpm_,r));
|
||||
return base(get(vpm_, p), get(vpm_, q), get(vpm_, r));
|
||||
}
|
||||
};
|
||||
Construct_plane_3 construct_plane_3_object() const
|
||||
{return Construct_plane_3(vpm_,static_cast<const Base_traits*>(this)->construct_plane_3_object());}
|
||||
|
||||
class Has_on_positive_side_3:public Base_traits::Has_on_positive_side_3
|
||||
Construct_plane_3 construct_plane_3_object() const
|
||||
{return Construct_plane_3(vpm_, static_cast<const Base_traits*>(this)->construct_plane_3_object());}
|
||||
|
||||
class Has_on_positive_side_3
|
||||
: public Base_traits::Has_on_positive_side_3
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
const typename Base_traits::Has_on_positive_side_3& base;
|
||||
public:
|
||||
Has_on_positive_side_3(const PointPropertyMap& map,const typename Base_traits::Has_on_positive_side_3& base):
|
||||
Base_traits::Has_on_positive_side_3(base),vpm_(map), base(base){}
|
||||
|
||||
typedef typename Base_traits::Plane_3 Plane_3;
|
||||
public:
|
||||
typedef bool result_type;
|
||||
Has_on_positive_side_3(const PointPropertyMap& map,
|
||||
const typename Base_traits::Has_on_positive_side_3& base)
|
||||
: Base_traits::Has_on_positive_side_3(base), vpm_(map), base(base)
|
||||
{ }
|
||||
|
||||
result_type
|
||||
operator()( const Plane_3& pl, const Vertex& p) const
|
||||
typedef typename Base_traits::Plane_3 Plane_3;
|
||||
public:
|
||||
typedef bool result_type;
|
||||
|
||||
result_type operator()( const Plane_3& pl, const Vertex& p) const
|
||||
{
|
||||
return base(pl, get(vpm_, p));
|
||||
}
|
||||
};
|
||||
Has_on_positive_side_3 has_on_positive_side_3_object() const {return Has_on_positive_side_3(
|
||||
vpm_,static_cast<const Base_traits*>(this)->has_on_positive_side_3_object() );}
|
||||
|
||||
Has_on_positive_side_3 has_on_positive_side_3_object() const
|
||||
{ return Has_on_positive_side_3(vpm_, static_cast<const Base_traits*>(this)->has_on_positive_side_3_object()); }
|
||||
|
||||
template<class Base_proj_traits>
|
||||
class Proj_traits_3:public Base_proj_traits
|
||||
class Proj_traits_3
|
||||
: public Base_proj_traits
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
typedef Base_proj_traits Btt;
|
||||
public:
|
||||
Proj_traits_3(const PointPropertyMap& map,const Btt& base):
|
||||
Base_proj_traits(base),vpm_(map){}
|
||||
typedef Point_3 Point_2;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Btt::Equal_2, PointPropertyMap> Equal_2;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Btt::Less_xy_2, PointPropertyMap> Less_xy_2;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Btt::Less_yx_2, PointPropertyMap> Less_yx_2;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Btt::Less_signed_distance_to_line_2, PointPropertyMap> Less_signed_distance_to_line_2;
|
||||
typedef Convex_hull_impl::Forward_functor<typename Btt::Left_turn_2, PointPropertyMap> Left_turn_2;
|
||||
|
||||
class Less_rotate_ccw_2:public Btt::Less_rotate_ccw_2
|
||||
public:
|
||||
Proj_traits_3(const PointPropertyMap& map, const Btt& base)
|
||||
: Base_proj_traits(base), vpm_(map)
|
||||
{ }
|
||||
|
||||
typedef Point_3 Point_2;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Btt::Equal_2, PointPropertyMap> Equal_2;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Btt::Less_xy_2, PointPropertyMap> Less_xy_2;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Btt::Less_yx_2, PointPropertyMap> Less_yx_2;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Btt::Less_signed_distance_to_line_2, PointPropertyMap> Less_signed_distance_to_line_2;
|
||||
typedef Convex_hull_3::internal::Forward_functor<
|
||||
typename Btt::Left_turn_2, PointPropertyMap> Left_turn_2;
|
||||
|
||||
class Less_rotate_ccw_2
|
||||
: public Btt::Less_rotate_ccw_2
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
const typename Btt::Less_rotate_ccw_2& base;
|
||||
|
||||
public:
|
||||
Less_rotate_ccw_2(const PointPropertyMap& map,const typename Btt::Less_rotate_ccw_2& base):
|
||||
Btt::Less_rotate_ccw_2(base),vpm_(map), base(base){}
|
||||
Less_rotate_ccw_2(const PointPropertyMap& map,
|
||||
const typename Btt::Less_rotate_ccw_2& base)
|
||||
: Btt::Less_rotate_ccw_2(base), vpm_(map), base(base)
|
||||
{ }
|
||||
|
||||
public:
|
||||
bool operator()(Point_2 e, Point_2 p,Point_2 q) const
|
||||
bool operator()(const Point_2& e, const Point_2& p, const Point_2& q) const
|
||||
{
|
||||
return base(get(vpm_, e), get(vpm_, p), get(vpm_, q));
|
||||
}
|
||||
};
|
||||
|
||||
Equal_2 equal_2_object () const {return Equal_2(vpm_,static_cast<const Btt*>(this)->equal_2_object() );}
|
||||
Less_xy_2 less_xy_2_object ()const{return Less_xy_2(vpm_,static_cast<const Btt*>(this)->less_xy_2_object() );}
|
||||
Less_yx_2 less_yx_2_object ()const{return Less_yx_2(vpm_,static_cast<const Btt*>(this)->less_yx_2_object() );}
|
||||
Less_signed_distance_to_line_2 less_signed_distance_to_line_2_object ()const
|
||||
{return Less_signed_distance_to_line_2(vpm_,static_cast<const Btt*>(this)->Less_signed_distance_to_line_2() );}
|
||||
Less_rotate_ccw_2 less_rotate_ccw_2_object ()const
|
||||
{return Less_rotate_ccw_2(vpm_,static_cast<const Btt*>(this)->less_rotate_ccw_2_object() );}
|
||||
Left_turn_2 left_turn_2_object ()const{return Left_turn_2(vpm_,static_cast<const Btt*>(this)->left_turn_2_object() );}
|
||||
Equal_2 equal_2_object() const
|
||||
{ return Equal_2(vpm_, static_cast<const Btt*>(this)->equal_2_object()); }
|
||||
Less_xy_2 less_xy_2_object() const
|
||||
{ return Less_xy_2(vpm_, static_cast<const Btt*>(this)->less_xy_2_object()); }
|
||||
Less_yx_2 less_yx_2_object() const
|
||||
{ return Less_yx_2(vpm_, static_cast<const Btt*>(this)->less_yx_2_object()); }
|
||||
Less_signed_distance_to_line_2 less_signed_distance_to_line_2_object() const
|
||||
{ return Less_signed_distance_to_line_2(vpm_, static_cast<const Btt*>(this)->Less_signed_distance_to_line_2()); }
|
||||
Less_rotate_ccw_2 less_rotate_ccw_2_object() const
|
||||
{ return Less_rotate_ccw_2(vpm_, static_cast<const Btt*>(this)->less_rotate_ccw_2_object()); }
|
||||
Left_turn_2 left_turn_2_object() const
|
||||
{ return Left_turn_2(vpm_, static_cast<const Btt*>(this)->left_turn_2_object()); }
|
||||
|
||||
class Orientation_2:public Btt::Orientation_2
|
||||
class Orientation_2
|
||||
: public Btt::Orientation_2
|
||||
{
|
||||
PointPropertyMap vpm_;
|
||||
const typename Btt::Orientation_2& base;
|
||||
public:
|
||||
Orientation_2(const PointPropertyMap& map,const typename Btt::Orientation_2& base):
|
||||
Btt::Orientation_2(base),vpm_(map), base(base){}
|
||||
|
||||
typename CGAL::Orientation operator()(Point_2 e,Point_2 p, Point_2 q) const
|
||||
public:
|
||||
Orientation_2(const PointPropertyMap& map,
|
||||
const typename Btt::Orientation_2& base)
|
||||
: Btt::Orientation_2(base), vpm_(map), base(base)
|
||||
{ }
|
||||
|
||||
typename CGAL::Orientation operator()(const Point_2& e, const Point_2& p, const Point_2& q) const
|
||||
{
|
||||
return base(get(vpm_, e), get(vpm_, p), get(vpm_, q));
|
||||
}
|
||||
};
|
||||
Orientation_2 orientation_2_object ()const{return Orientation_2(vpm_,static_cast<const Btt*>(this)->orientation_2_object() );}
|
||||
|
||||
Orientation_2 orientation_2_object() const
|
||||
{ return Orientation_2(vpm_, static_cast<const Btt*>(this)->orientation_2_object()); }
|
||||
};
|
||||
|
||||
typedef internal::Convex_hull_3::Projection_traits<Base_traits> Base_PTraits;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_xy_3> Traits_xy_3;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_yz_3> Traits_yz_3;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_xz_3> Traits_xz_3;
|
||||
typedef Convex_hull_3::internal::Projection_traits<Base_traits> Base_PTraits;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_xy_3> Traits_xy_3;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_yz_3> Traits_yz_3;
|
||||
typedef Proj_traits_3<typename Base_PTraits::Traits_xz_3> Traits_xz_3;
|
||||
|
||||
Traits_xy_3 construct_traits_xy_3_object()const
|
||||
{return Traits_xy_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_xy_3_object());}
|
||||
Traits_yz_3 construct_traits_yz_3_object()const
|
||||
{return Traits_yz_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_yz_3_object());}
|
||||
Traits_xz_3 construct_traits_xz_3_object()const
|
||||
{return Traits_xz_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_xz_3_object());}
|
||||
Traits_xy_3 construct_traits_xy_3_object() const
|
||||
{ return Traits_xy_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_xy_3_object()); }
|
||||
Traits_yz_3 construct_traits_yz_3_object() const
|
||||
{ return Traits_yz_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_yz_3_object()); }
|
||||
Traits_xz_3 construct_traits_xz_3_object() const
|
||||
{ return Traits_xz_3(vpm_, Base_PTraits(static_cast<const Base_traits&>(*this)).construct_traits_xz_3_object()); }
|
||||
|
||||
typename boost::property_traits<PointPropertyMap>::reference
|
||||
get_point(const typename boost::property_traits<PointPropertyMap>::key_type& k) const
|
||||
{
|
||||
return get(vpm_, k);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<class PointPropertyMap,class Base_traits>
|
||||
Extreme_points_traits_adapter_3<PointPropertyMap, Base_traits>
|
||||
make_extreme_points_traits_adapter(const PointPropertyMap& pmap, Base_traits traits = Base_traits())
|
||||
make_extreme_points_traits_adapter(const PointPropertyMap& pmap,
|
||||
Base_traits traits = Base_traits())
|
||||
{
|
||||
return Extreme_points_traits_adapter_3<PointPropertyMap, Base_traits>(pmap, traits);
|
||||
}
|
||||
|
|
@ -245,9 +283,6 @@ make_extreme_points_traits_adapter(const PointPropertyMap& pmap)
|
|||
return Extreme_points_traits_adapter_3<PointPropertyMap>(pmap);
|
||||
}
|
||||
|
||||
|
||||
//helper function
|
||||
|
||||
}//end CGAL
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_EXTREME_POINTS_TRAITS_ADAPTER_3_H
|
||||
|
|
|
|||
|
|
@ -31,21 +31,10 @@
|
|||
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#include <CGAL/internal/Exact_type_selector.h>
|
||||
#include <CGAL/boost/graph/copy_face_graph.h>
|
||||
#include <CGAL/boost/graph/Named_function_parameters.h>
|
||||
#include <CGAL/boost/graph/graph_traits_Triangulation_data_structure_2.h>
|
||||
#include <CGAL/boost/graph/properties_Triangulation_data_structure_2.h>
|
||||
#include <CGAL/Polyhedron_3_fwd.h>
|
||||
|
|
@ -54,12 +43,24 @@
|
|||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
#include <CGAL/is_iterator.h>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/next_prior.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
|
||||
#ifndef CGAL_CH_NO_POSTCONDITIONS
|
||||
#include <CGAL/convexity_check_3.h>
|
||||
#endif // CGAL_CH_NO_POSTCONDITIONS
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// first some internal stuff to avoid using a true Face_graph model for extreme_points_3
|
||||
namespace CGAL {
|
||||
|
|
@ -67,7 +68,8 @@ namespace CGAL {
|
|||
// Forward declaration
|
||||
template<class VertexPointMap,class Base_traits> class Extreme_points_traits_adapter_3;
|
||||
|
||||
namespace internal{ namespace Convex_hull_3{
|
||||
namespace Convex_hull_3 {
|
||||
namespace internal {
|
||||
|
||||
// wrapper used as a MutableFaceGraph to extract extreme points
|
||||
template <class OutputIterator>
|
||||
|
|
@ -81,29 +83,30 @@ struct Output_iterator_wrapper
|
|||
|
||||
template <class Point_3, class OutputIterator>
|
||||
void add_isolated_points(const Point_3& point,
|
||||
internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator>& w)
|
||||
Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator>& w)
|
||||
{
|
||||
*w.out++ = point;
|
||||
}
|
||||
|
||||
template <class Point_3, class Polyhedron_3>
|
||||
void add_isolated_points(const Point_3& point, Polyhedron_3& P)
|
||||
template <class Point_3, class PolygonMesh>
|
||||
void add_isolated_points(const Point_3& point, PolygonMesh& P)
|
||||
{
|
||||
put(get(CGAL::vertex_point, P), add_vertex(P), point);
|
||||
}
|
||||
|
||||
template <class Point_3, class OutputIterator>
|
||||
void copy_ch2_to_face_graph(const std::list<Point_3>& CH_2,
|
||||
internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator>& w)
|
||||
Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator>& w)
|
||||
{
|
||||
for(const Point_3& p : CH_2)
|
||||
*w.out++ = p;
|
||||
}
|
||||
|
||||
} } // internal::Convex_hull_3
|
||||
} // namespace internal
|
||||
} // namespace Convex_hull_3
|
||||
|
||||
template <class TDS, class OutputIterator>
|
||||
void copy_face_graph(const TDS& tds, internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator>& wrapper)
|
||||
void copy_face_graph(const TDS& tds, Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator>& wrapper)
|
||||
{
|
||||
typedef typename boost::graph_traits<TDS>::vertex_descriptor vertex_descriptor;
|
||||
typename boost::property_map<TDS, boost::vertex_point_t >::const_type vpm = get(boost::vertex_point, tds);
|
||||
|
|
@ -114,12 +117,12 @@ void copy_face_graph(const TDS& tds, internal::Convex_hull_3::Output_iterator_wr
|
|||
}
|
||||
|
||||
template <class OutputIterator>
|
||||
void clear(internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator>&)
|
||||
void clear(Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator>&)
|
||||
{}
|
||||
|
||||
template <class Point, class OutputIterator>
|
||||
void make_tetrahedron(const Point& p0, const Point& p1, const Point& p2, const Point& p3,
|
||||
internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator>& w)
|
||||
Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator>& w)
|
||||
{
|
||||
*w.out++ = p0;
|
||||
*w.out++ = p1;
|
||||
|
|
@ -129,19 +132,20 @@ void make_tetrahedron(const Point& p0, const Point& p1, const Point& p2, const P
|
|||
|
||||
} // CGAL
|
||||
|
||||
namespace boost{
|
||||
namespace boost {
|
||||
|
||||
// needed so that the regular make_tetrahedron of CGAL does not complain when tried to be instantiated
|
||||
template <class OutputIterator>
|
||||
struct graph_traits<CGAL::internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator> >
|
||||
struct graph_traits<CGAL::Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator> >
|
||||
{
|
||||
typedef void* halfedge_descriptor;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
|
||||
namespace internal{ namespace Convex_hull_3{
|
||||
namespace Convex_hull_3 {
|
||||
namespace internal {
|
||||
|
||||
//struct to select the default traits class for computing convex hull
|
||||
template< class Point_3,
|
||||
|
|
@ -407,12 +411,12 @@ struct Projection_traits<T,true>{
|
|||
{return traits.construct_traits_xz_3_object();}
|
||||
};
|
||||
|
||||
template <class Point_3, class Polyhedron_3>
|
||||
void copy_ch2_to_face_graph(const std::list<Point_3>& CH_2, Polyhedron_3& P)
|
||||
template <class Point_3, class PolygonMesh>
|
||||
void copy_ch2_to_face_graph(const std::list<Point_3>& CH_2, PolygonMesh& P)
|
||||
{
|
||||
typename boost::property_map<Polyhedron_3, CGAL::vertex_point_t>::type vpm
|
||||
typename boost::property_map<PolygonMesh, CGAL::vertex_point_t>::type vpm
|
||||
= get(CGAL::vertex_point, P);
|
||||
typedef boost::graph_traits<Polyhedron_3> Graph_traits;
|
||||
typedef boost::graph_traits<PolygonMesh> Graph_traits;
|
||||
typedef typename Graph_traits::vertex_descriptor vertex_descriptor;
|
||||
typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor;
|
||||
typedef typename Graph_traits::face_descriptor face_descriptor;
|
||||
|
|
@ -435,12 +439,12 @@ void copy_ch2_to_face_graph(const std::list<Point_3>& CH_2, Polyhedron_3& P)
|
|||
}
|
||||
|
||||
|
||||
template <class InputIterator, class Point_3, class Polyhedron_3, class Traits>
|
||||
template <class InputIterator, class Point_3, class PolygonMesh, class Traits>
|
||||
void coplanar_3_hull(InputIterator first, InputIterator beyond,
|
||||
const Point_3& p1, const Point_3& p2, const Point_3& p3,
|
||||
Polyhedron_3& P, const Traits& traits )
|
||||
PolygonMesh& P, const Traits& traits )
|
||||
{
|
||||
typedef typename internal::Convex_hull_3::Projection_traits<Traits> PTraits;
|
||||
typedef typename Convex_hull_3::internal::Projection_traits<Traits> PTraits;
|
||||
typedef typename PTraits::Traits_xy_3 Traits_xy_3;
|
||||
typedef typename PTraits::Traits_yz_3 Traits_yz_3;
|
||||
typedef typename PTraits::Traits_xz_3 Traits_xz_3;
|
||||
|
|
@ -758,12 +762,12 @@ void non_coplanar_quickhull_3(std::list<typename Traits::Point_3>& points,
|
|||
// CGAL_ch_postcondition(is_strongly_convex_3(P, traits));
|
||||
}
|
||||
|
||||
template <class InputIterator, class Polyhedron_3, class Traits>
|
||||
template <class InputIterator, class PolygonMesh, class Traits>
|
||||
void
|
||||
ch_quickhull_polyhedron_3(std::list<typename Traits::Point_3>& points,
|
||||
InputIterator point1_it, InputIterator point2_it,
|
||||
InputIterator point3_it, Polyhedron_3& P,
|
||||
const Traits& traits)
|
||||
ch_quickhull_face_graph(std::list<typename Traits::Point_3>& points,
|
||||
InputIterator point1_it, InputIterator point2_it, InputIterator point3_it,
|
||||
PolygonMesh& P,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Point_3 Point_3;
|
||||
typedef typename Traits::Plane_3 Plane_3;
|
||||
|
|
@ -848,12 +852,14 @@ ch_quickhull_polyhedron_3(std::list<typename Traits::Point_3>& points,
|
|||
|
||||
}
|
||||
|
||||
} } //namespace internal::Convex_hull_3
|
||||
} // namespace internal
|
||||
} // namespace Convex_hull_3
|
||||
|
||||
template <class InputIterator, class Traits>
|
||||
void
|
||||
convex_hull_3(InputIterator first, InputIterator beyond,
|
||||
Object& ch_object, const Traits& traits)
|
||||
Object& ch_object,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Point_3 Point_3;
|
||||
typedef std::list<Point_3> Point_3_list;
|
||||
|
|
@ -936,7 +942,7 @@ convex_hull_3(InputIterator first, InputIterator beyond,
|
|||
}
|
||||
|
||||
// result will be a polyhedron
|
||||
typedef typename internal::Convex_hull_3::Default_polyhedron_for_Chull_3<Traits>::type Polyhedron;
|
||||
typedef typename Convex_hull_3::internal::Default_polyhedron_for_Chull_3<Traits>::type Polyhedron;
|
||||
Polyhedron P;
|
||||
|
||||
P3_iterator minx, maxx, miny, it;
|
||||
|
|
@ -948,9 +954,9 @@ convex_hull_3(InputIterator first, InputIterator beyond,
|
|||
if(it->y() < miny->y()) miny = it;
|
||||
}
|
||||
if(! collinear(*minx, *maxx, *miny) ){
|
||||
internal::Convex_hull_3::ch_quickhull_polyhedron_3(points, minx, maxx, miny, P, traits);
|
||||
Convex_hull_3::internal::ch_quickhull_face_graph(points, minx, maxx, miny, P, traits);
|
||||
} else {
|
||||
internal::Convex_hull_3::ch_quickhull_polyhedron_3(points, point1_it, point2_it, point3_it, P, traits);
|
||||
Convex_hull_3::internal::ch_quickhull_face_graph(points, point1_it, point2_it, point3_it, P, traits);
|
||||
}
|
||||
CGAL_assertion(num_vertices(P)>=3);
|
||||
typename boost::graph_traits<Polyhedron>::vertex_iterator b,e;
|
||||
|
|
@ -973,18 +979,18 @@ convex_hull_3(InputIterator first, InputIterator beyond,
|
|||
|
||||
|
||||
template <class InputIterator>
|
||||
void convex_hull_3(InputIterator first, InputIterator beyond, Object& ch_object)
|
||||
void convex_hull_3(InputIterator first, InputIterator beyond,
|
||||
Object& ch_object)
|
||||
{
|
||||
typedef typename std::iterator_traits<InputIterator>::value_type Point_3;
|
||||
typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
typedef typename Convex_hull_3::internal::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
convex_hull_3(first, beyond, ch_object, Traits());
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class InputIterator, class Polyhedron_3, class Traits>
|
||||
template <class InputIterator, class PolygonMesh, class Traits>
|
||||
void convex_hull_3(InputIterator first, InputIterator beyond,
|
||||
Polyhedron_3& polyhedron, const Traits& traits)
|
||||
PolygonMesh& polyhedron,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Point_3 Point_3;
|
||||
typedef std::list<Point_3> Point_3_list;
|
||||
|
|
@ -1009,7 +1015,7 @@ void convex_hull_3(InputIterator first, InputIterator beyond,
|
|||
// if there is only one point or all points are equal
|
||||
if(point2_it == points.end())
|
||||
{
|
||||
internal::Convex_hull_3::add_isolated_points(*point1_it, polyhedron);
|
||||
Convex_hull_3::internal::add_isolated_points(*point1_it, polyhedron);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1028,39 +1034,38 @@ void convex_hull_3(InputIterator first, InputIterator beyond,
|
|||
min_max_element(points.begin(), points.end(),
|
||||
boost::bind(less_dist, *points.begin(), _1, _2),
|
||||
boost::bind(less_dist, *points.begin(), _1, _2));
|
||||
internal::Convex_hull_3::add_isolated_points(*endpoints.first, polyhedron);
|
||||
internal::Convex_hull_3::add_isolated_points(*endpoints.second, polyhedron);
|
||||
Convex_hull_3::internal::add_isolated_points(*endpoints.first, polyhedron);
|
||||
Convex_hull_3::internal::add_isolated_points(*endpoints.second, polyhedron);
|
||||
return;
|
||||
}
|
||||
|
||||
internal::Convex_hull_3::ch_quickhull_polyhedron_3(points, point1_it, point2_it, point3_it,
|
||||
Convex_hull_3::internal::ch_quickhull_face_graph(points, point1_it, point2_it, point3_it,
|
||||
polyhedron, traits);
|
||||
}
|
||||
|
||||
|
||||
template <class InputIterator, class Polyhedron_3>
|
||||
template <class InputIterator, class PolygonMesh>
|
||||
void convex_hull_3(InputIterator first, InputIterator beyond,
|
||||
Polyhedron_3& polyhedron,
|
||||
typename std::enable_if<
|
||||
CGAL::is_iterator<InputIterator>::value
|
||||
>::type* =0) //workaround to avoid ambiguity with next overload.
|
||||
PolygonMesh& polyhedron,
|
||||
// workaround to avoid ambiguity with next overload.
|
||||
typename std::enable_if<CGAL::is_iterator<InputIterator>::value>::type* = 0)
|
||||
{
|
||||
typedef typename std::iterator_traits<InputIterator>::value_type Point_3;
|
||||
typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3<Point_3, Polyhedron_3>::type Traits;
|
||||
convex_hull_3(first, beyond, polyhedron, Traits());
|
||||
typedef typename std::iterator_traits<InputIterator>::value_type Point_3;
|
||||
typedef typename Convex_hull_3::internal::Default_traits_for_Chull_3<Point_3, PolygonMesh>::type Traits;
|
||||
convex_hull_3(first, beyond, polyhedron, Traits());
|
||||
}
|
||||
|
||||
|
||||
template <class VertexListGraph, class PolygonMesh, class NamedParameters>
|
||||
void convex_hull_3(const VertexListGraph& g,
|
||||
PolygonMesh& pm,
|
||||
const NamedParameters& np)
|
||||
{
|
||||
using CGAL::parameters::choose_parameter;
|
||||
using CGAL::parameters::get_parameter;
|
||||
|
||||
typedef typename GetVertexPointMap<VertexListGraph, NamedParameters>::const_type Vpmap;
|
||||
typedef CGAL::Property_map_to_unary_function<Vpmap> Vpmap_fct;
|
||||
Vpmap vpm = CGAL::parameters::choose_parameter(
|
||||
CGAL::parameters::get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, g));
|
||||
Vpmap vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(boost::vertex_point, g));
|
||||
|
||||
Vpmap_fct v2p(vpm);
|
||||
convex_hull_3(boost::make_transform_iterator(vertices(g).begin(), v2p),
|
||||
|
|
@ -1080,7 +1085,7 @@ extreme_points_3(const InputRange& range,
|
|||
OutputIterator out,
|
||||
const Traits& traits)
|
||||
{
|
||||
internal::Convex_hull_3::Output_iterator_wrapper<OutputIterator> wrapper(out);
|
||||
Convex_hull_3::internal::Output_iterator_wrapper<OutputIterator> wrapper(out);
|
||||
convex_hull_3(range.begin(), range.end(), wrapper, traits);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -1091,7 +1096,7 @@ extreme_points_3(const InputRange& range, OutputIterator out)
|
|||
{
|
||||
typedef typename InputRange::const_iterator Iterator_type;
|
||||
typedef typename std::iterator_traits<Iterator_type>::value_type Point_3;
|
||||
typedef typename internal::Convex_hull_3::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
typedef typename Convex_hull_3::internal::Default_traits_for_Chull_3<Point_3>::type Traits;
|
||||
|
||||
return extreme_points_3(range, out, Traits());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (c) 2011 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Sebastien Loriot
|
||||
//
|
||||
|
||||
#ifndef CGAL_CONVEX_HULL_3_TO_POLYHEDRON_3_H
|
||||
#define CGAL_CONVEX_HULL_3_TO_POLYHEDRON_3_H
|
||||
|
||||
#include <CGAL/license/Convex_hull_3.h>
|
||||
|
||||
|
||||
#define CGAL_DEPRECATED_HEADER "<CGAL/convex_hull_3_to_polyhedron_3.h>"
|
||||
#define CGAL_REPLACEMENT_HEADER "<CGAL/convex_hull_3_to_face_graph.h>"
|
||||
#include <CGAL/internal/deprecation_warning.h>
|
||||
|
||||
|
||||
#include <CGAL/Polyhedron_3_fwd.h>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
template<class Triangulation_3,class Polyhedron_3>
|
||||
CGAL_DEPRECATED void convex_hull_3_to_polyhedron_3(const Triangulation_3& T,Polyhedron_3& P){
|
||||
clear(P);
|
||||
link_to_face_graph(T,T.infinite_vertex(), P);
|
||||
}
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif //CGAL_CONVEX_HULL_3_TO_POLYHEDRON_3_H
|
||||
|
|
@ -19,7 +19,7 @@ typedef CGAL::Simple_cartesian<double> SCD;
|
|||
typedef CGAL::Simple_homogeneous<double> SHD;
|
||||
typedef CGAL::Simple_cartesian<Exact_rational> SCR;
|
||||
|
||||
using namespace CGAL::internal::Convex_hull_3;
|
||||
using namespace CGAL::Convex_hull_3::internal;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ void test_triangulated_cube(const char* fname)
|
|||
std::ifstream input(fname);
|
||||
SurfaceMesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ void test_extreme_vertices(const char* fname)
|
|||
std::ifstream input(fname);
|
||||
Polyhedron_3 P;
|
||||
if (!input || !(input >> P) || P.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
/*CGAL::Extreme_points_traits_adapter_3<
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@
|
|||
\package_listing{Box_intersection_d}
|
||||
\package_listing{AABB_tree}
|
||||
\package_listing{Spatial_sorting}
|
||||
\package_listing{Optimal_bounding_box}
|
||||
|
||||
\cgalPackageSection{PartGeometricOptimization,Geometric Optimization}
|
||||
|
||||
|
|
|
|||
|
|
@ -363,6 +363,17 @@ Boissonnat}
|
|||
,pages = {350--355}
|
||||
}
|
||||
|
||||
@article{cgal:cgm-fobbo-11,
|
||||
title={Fast Oriented Bounding Box Optimization on the Rotation Group $\SO(3, \mathrm{R})$},
|
||||
author={Chang, Chia-Tche and Gorissen, Bastien and Melchior, Samuel},
|
||||
journal={ACM Transactions on Graphics (TOG)},
|
||||
volume={30},
|
||||
number={5},
|
||||
pages={1--16},
|
||||
year={2011},
|
||||
publisher={ACM New York, NY, USA}
|
||||
}
|
||||
|
||||
@article{cgal:cdeft-slive-00,
|
||||
author = {Cheng, Siu-Wing and Dey, Tamal K. and Edelsbrunner, Herbert and Facello, Michael A. and Teng, Shang-Hua},
|
||||
title = {Sliver exudation},
|
||||
|
|
@ -1710,6 +1721,17 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
|
|||
,update = "97.04 kettner"
|
||||
}
|
||||
|
||||
@article{cgal:nm-smfm-65,
|
||||
title={A Simplex Method for Function Minimization},
|
||||
author={Nelder, John A and Mead, Roger},
|
||||
journal={The computer journal},
|
||||
volume={7},
|
||||
number={4},
|
||||
pages={308--313},
|
||||
year={1965},
|
||||
publisher={Oxford University Press}
|
||||
}
|
||||
|
||||
@book{ cgal:ns-gsn-07
|
||||
,author = {G. Narasimhan and M. Smid}
|
||||
,title = {Geometric Spanner Networks}
|
||||
|
|
@ -1852,6 +1874,17 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
|
|||
,pages = {743--750}
|
||||
}
|
||||
|
||||
@article{cgal:or-fmeb-85,
|
||||
title={Finding Minimal Enclosing Boxes},
|
||||
author={O'Rourke, Joseph},
|
||||
journal={International journal of computer \& information sciences},
|
||||
volume={14},
|
||||
number={3},
|
||||
pages={183--199},
|
||||
year={1985},
|
||||
publisher={Springer}
|
||||
}
|
||||
|
||||
@article{ cgal:r-lomom-94
|
||||
,author = {James Rumbaugh}
|
||||
,title = {The Life of an Object Model: How the Object-Model
|
||||
|
|
@ -2164,6 +2197,14 @@ location = {Salt Lake City, Utah, USA}
|
|||
, x-international-audience = {yes}
|
||||
}
|
||||
|
||||
@inproceedings{cgal:t-sgprc-83,
|
||||
title={Solving geometric problems with the rotating calipers},
|
||||
author={Toussaint, Godfried T},
|
||||
booktitle={Proc. IEEE Melecon},
|
||||
volume={83},
|
||||
pages={A10},
|
||||
year={1983}
|
||||
}
|
||||
|
||||
@proceedings{ cgal:v-ea-09,
|
||||
editor = {Jan Vahrenhold},
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ Release History
|
|||
|
||||
[Release 5.1] (https://github.com/CGAL/cgal/releases/tag/releases%2FCGAL-5.1)
|
||||
|
||||
### Optimal Bounding Box (new package)
|
||||
- This package implements an optimization algorithm that aims to construct a close approximation
|
||||
of the *optimal bounding box* of a mesh or a point set, which is defined as the smallest
|
||||
(in terms of volume) bounding box that contains a given mesh or point set.
|
||||
|
||||
### 2D and 3D Linear Geometry Kernel
|
||||
- Add `CompareSignedDistanceToLine_2` in the 2D/3D Kernel concept to compare
|
||||
the signed distance of two points to a line, or the line passing through two given points.
|
||||
|
|
@ -14,6 +19,9 @@ Release History
|
|||
from a soup of disconnected segments that should first be split
|
||||
into polylines.
|
||||
|
||||
### 3D Convex Hulls
|
||||
- The long-deprecated function `CGAL::convex_hull_3_to_polyhedron_3()` has been removed.
|
||||
The function `CGAL::convex_hull_3_to_face_graph()` should be used instead.
|
||||
|
||||
Release 5.0
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2016 GeometryFactory SARL (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org)
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
//
|
||||
// Warning: this file is generated, see include/CGAL/licence/README.md
|
||||
|
||||
#ifndef CGAL_LICENSE_OPTIMAL_BOUNDING_BOX_H
|
||||
#define CGAL_LICENSE_OPTIMAL_BOUNDING_BOX_H
|
||||
|
||||
#include <CGAL/config.h>
|
||||
#include <CGAL/license.h>
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE
|
||||
|
||||
# if CGAL_OPTIMAL_BOUNDING_BOX_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 Optimal Bounding Box package.")
|
||||
# endif
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "Your commercial license for CGAL does not cover this release \
|
||||
of the Optimal Bounding Box package. \
|
||||
You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
# endif // CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
#else // no CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
CGAL_pragma_warning("\nThe macro CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE is not defined."
|
||||
"\nYou use the CGAL Optimal Bounding Box package under "
|
||||
"the terms of the GPLv3+.")
|
||||
# endif // CGAL_LICENSE_WARNING
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "The macro CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE is not defined.\
|
||||
You use the CGAL Optimal Bounding Box package under the terms of \
|
||||
the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
#endif // no CGAL_OPTIMAL_BOUNDING_BOX_COMMERCIAL_LICENSE
|
||||
|
||||
#endif // CGAL_LICENSE_OPTIMAL_BOUNDING_BOX_H
|
||||
|
|
@ -32,6 +32,7 @@ Minkowski_sum_3 3D Minkowski Sum of Polyhedra
|
|||
Nef_2 2D Boolean Operations on Nef Polygons
|
||||
Nef_3 3D Boolean Operations on Nef Polyhedra
|
||||
Nef_S2 2D Boolean Operations on Nef Polygons Embedded on the Sphere
|
||||
Optimal_bounding_box Optimal Bounding Box
|
||||
Optimal_transportation_reconstruction_2 Optimal Transportation Curve Reconstruction
|
||||
Partition_2 2D Polygon Partitioning
|
||||
Periodic_2_triangulation_2 2D Periodic Triangulations
|
||||
|
|
|
|||
|
|
@ -521,7 +521,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -550,7 +550,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -577,7 +577,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -614,7 +614,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -659,7 +659,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -697,7 +697,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
@ -739,7 +739,7 @@ public:
|
|||
|
||||
Weighted_point_2 project(const Weighted_point_3& wp) const
|
||||
{
|
||||
Point_3 p = R().construct_point_3_object()(wp);
|
||||
const Point_3& p = R().construct_point_3_object()(wp);
|
||||
return Weighted_point_2(Point_2(x(p), y(p)), wp.weight());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1...3.15)
|
||||
project( Optimal_bounding_box_Benchmark )
|
||||
|
||||
# CGAL and its components
|
||||
find_package( CGAL QUIET )
|
||||
|
||||
if ( NOT CGAL_FOUND )
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# include helper file
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
|
||||
if (NOT EIGEN3_FOUND)
|
||||
message(STATUS "This project requires the Eigen library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
create_single_source_cgal_program("bench_obb.cpp")
|
||||
CGAL_target_use_Eigen(bench_obb)
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/oriented_bounding_box.h>
|
||||
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <CGAL/Timer.h>
|
||||
|
||||
#include <CGAL/IO/OFF_reader.h>
|
||||
#include <CGAL/IO/STL_reader.h>
|
||||
#include <CGAL/IO/OBJ_reader.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point_3;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
|
||||
typedef typename boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
template <typename Point>
|
||||
bool read_mesh(const std::string filename,
|
||||
std::vector<Point>& points)
|
||||
{
|
||||
std::ifstream in(filename.c_str());
|
||||
if(!in.good())
|
||||
{
|
||||
// std::cerr << "Error: can't read file at " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::size_t> > unused_faces;
|
||||
|
||||
std::string fn(filename);
|
||||
if(fn.substr(fn.find_last_of(".") + 1) == "stl")
|
||||
{
|
||||
if(!CGAL::read_STL(in, points, unused_faces))
|
||||
return false;
|
||||
}
|
||||
else if(fn.substr(fn.find_last_of(".") + 1) == "obj")
|
||||
{
|
||||
if(!CGAL::read_OBJ(in, points, unused_faces))
|
||||
return false;
|
||||
}
|
||||
else if(fn.substr(fn.find_last_of(".") + 1) == "off")
|
||||
{
|
||||
if(!CGAL::read_OFF(in, points, unused_faces))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// std::cerr << "Error: unsupported file format: " << filename << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void bench_finding_obb(const std::string filename,
|
||||
const int iter)
|
||||
{
|
||||
CGAL::Timer timer;
|
||||
|
||||
std::vector<Point_3> points;
|
||||
read_mesh(filename, points);
|
||||
|
||||
std::vector<Point_3> ch_points;
|
||||
std::array<Point_3, 8> obb_points1;
|
||||
std::array<Point_3, 8> obb_points2;
|
||||
|
||||
double ch_time = 0.;
|
||||
double obb_time = 0.;
|
||||
double total_time_ch = 0.;
|
||||
double total_time_no_ch = 0.;
|
||||
|
||||
for(int i=0; i<iter; ++i)
|
||||
{
|
||||
// std::cout << "Iter #" << i << std::endl;
|
||||
// std::cout << points.size() << std::endl;
|
||||
|
||||
// 1) measure convex hull calculation
|
||||
timer.reset();
|
||||
ch_points.clear();
|
||||
|
||||
timer.start();
|
||||
extreme_points_3(points, std::back_inserter(ch_points));
|
||||
timer.stop();
|
||||
ch_time += timer.time();
|
||||
|
||||
// 2) using convex hull
|
||||
timer.reset();
|
||||
|
||||
timer.start();
|
||||
CGAL::oriented_bounding_box(ch_points, obb_points1, CGAL::parameters::use_convex_hull(false));
|
||||
timer.stop();
|
||||
obb_time += timer.time();
|
||||
|
||||
// 2bis) using convex hull in one go
|
||||
timer.reset();
|
||||
|
||||
timer.start();
|
||||
CGAL::oriented_bounding_box(points, obb_points1, CGAL::parameters::use_convex_hull(true));
|
||||
timer.stop();
|
||||
total_time_ch += timer.time();
|
||||
|
||||
// 3) without convex hull
|
||||
timer.reset();
|
||||
|
||||
timer.start();
|
||||
CGAL::oriented_bounding_box(points, obb_points2, CGAL::parameters::use_convex_hull(false));
|
||||
timer.stop();
|
||||
total_time_no_ch += timer.time();
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
|
||||
Surface_mesh result_mesh1;
|
||||
CGAL::make_hexahedron(obb_points1[0], obb_points1[1], obb_points1[2], obb_points1[3],
|
||||
obb_points1[4], obb_points1[5], obb_points1[6], obb_points1[7],
|
||||
result_mesh1);
|
||||
|
||||
Surface_mesh result_mesh2;
|
||||
CGAL::make_hexahedron(obb_points2[0], obb_points2[1], obb_points2[2], obb_points2[3],
|
||||
obb_points2[4], obb_points2[5], obb_points2[6], obb_points2[7],
|
||||
result_mesh2);
|
||||
|
||||
std::stringstream oss1;
|
||||
oss1 << "data/obb_result1_iter_" << i << std::ends;
|
||||
std::ofstream out1(oss1.str().c_str());
|
||||
out1 << result_mesh1;
|
||||
|
||||
std::stringstream oss2;
|
||||
oss2 << "data/obb_result2_iter_" << i << std::ends;
|
||||
std::ofstream out2(oss2.str().c_str());
|
||||
out2 << result_mesh2;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 1 // only outputs the core stuff
|
||||
std::cout << points.size() << " "
|
||||
<< ch_points.size() << " "
|
||||
<< ch_time / iter << " "
|
||||
<< obb_time / iter << " "
|
||||
<< total_time_ch / iter << " "
|
||||
<< total_time_no_ch / iter << std::endl;
|
||||
#else
|
||||
std::cout << "Average of " << iter << " iterations" << std::endl;
|
||||
std::cout << points.size() << " vertices in the mesh" << std::endl;
|
||||
std::cout << ch_points.size() << " vertices on the convex hull" << std::endl;
|
||||
std::cout << ch_time / iter << " seconds to find the convex hull" << std::endl;
|
||||
std::cout << obb_time / iter << " seconds to find the best rotation" << std::endl;
|
||||
std::cout << total_time_ch / iter << " seconds to compute and find. "
|
||||
<< "Should be about equal to: " << (ch_time + obb_time) / iter << std::endl;
|
||||
std::cout << total_time_no_ch / iter << " seconds to find the best rotation (NO CH)" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const int iter = (argc > 2) ? std::atoi(argv[2]) : 5;
|
||||
bench_finding_obb((argc > 1) ? argv[1] : "data/elephant.off", iter);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*!
|
||||
\ingroup PkgOptimalBoundingBoxConcepts
|
||||
\cgalConcept
|
||||
|
||||
The concept `OrientedBoundingBoxTraits_3` describes the requirements of the traits class
|
||||
used in the function `CGAL::oriented_bounding_box()`, and in particular the need for
|
||||
a 3x3 matrix type.
|
||||
|
||||
\cgalRefines `Kernel`
|
||||
|
||||
\cgalHasModel `CGAL::Oriented_bounding_box_traits_3`
|
||||
|
||||
*/
|
||||
class OrientedBoundingBoxTraits_3
|
||||
{
|
||||
public:
|
||||
/// The field number type; must be a model of the concept `FieldNumberType`
|
||||
typedef unspecified_type FT;
|
||||
|
||||
/// The 3D affine transformation type; the template parameter `K` must be a model of `Kernel`
|
||||
/// and be compatible with the type `Point_3`
|
||||
typedef CGAL::Aff_transformation_3<K> Aff_transformation_3;
|
||||
|
||||
/// A 3x3 matrix type; model of the concept `SvdTraits::Matrix` and which supports
|
||||
/// matrix-matrix and scalar-matrix multiplication, as well as matrix-matrix addition
|
||||
typedef unspecified_type Matrix;
|
||||
|
||||
/// A 3 dimensional vector type; model of the concept `SvdTraits::Vector` and which supports
|
||||
/// matrix-vector and multiplication
|
||||
typedef unspecified_type Vector;
|
||||
|
||||
/// Returns the unitary matrix `Q` obtained in the QR-decomposition of the matrix `m`
|
||||
Matrix get_Q(const Matrix& m) const;
|
||||
};
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Optimal Bounding Box"
|
||||
EXTRACT_ALL = false
|
||||
HIDE_UNDOC_CLASSES = true
|
||||
WARN_IF_UNDOCUMENTED = true
|
||||
|
||||
# macros to be used inside the code
|
||||
ALIASES += "cgalNamedParamsBegin=<dl class=\"params\"><dt>Named Parameters</dt><dd> <table class=\"params\">"
|
||||
ALIASES += "cgalNamedParamsEnd=</table> </dd> </dl>"
|
||||
ALIASES += "cgalParamBegin{1}=<tr><td class=\"paramname\">\ref OBB_\1 \"\1\"</td><td>"
|
||||
ALIASES += "cgalParamEnd=</td></tr>"
|
||||
|
||||
#macros for NamedParameters.txt
|
||||
ALIASES += "cgalNPTableBegin=<dl class=\"params\"><dt></dt><dd> <table class=\"params\">"
|
||||
ALIASES += "cgalNPTableEnd=</table> </dd> </dl>"
|
||||
ALIASES += "cgalNPBegin{1}=<tr><td class=\"paramname\">\1 </td><td>"
|
||||
ALIASES += "cgalNPEnd=</td></tr>"
|
||||
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
EXPAND_AS_DEFINED = CGAL_BGL_NP_TEMPLATE_PARAMETERS \
|
||||
CGAL_BGL_NP_CLASS
|
||||
EXCLUDE = ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Optimal_bounding_box/internal
|
||||
EXCLUDE_SYMBOLS += experimental
|
||||
|
||||
HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/aabb_vs_obb.jpg \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/obb_chess.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/obb_time.png \
|
||||
${CGAL_PACKAGE_DOC_DIR}/fig/ch_speedup.png
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*!
|
||||
\defgroup obb_namedparameters Named Parameters for the package Optimal Bounding Box
|
||||
\ingroup PkgOptimalBoundingBoxRef
|
||||
|
||||
In this package, the optional parameters of all functions are implemented as BGL optional
|
||||
named parameters (see \ref BGLNamedParameters for more information on how to use them).
|
||||
Since the parameters of the various functions defined in this package are redundant,
|
||||
their long descriptions are centralized below.
|
||||
The sequence of named parameters should start with `CGAL::parameters::`.
|
||||
`CGAL::parameters::all_default()` can be used to indicate
|
||||
that default values of optional named parameters must be used.
|
||||
|
||||
In the following, we assume that the following types are provided as template parameters
|
||||
of functions and classes. Note that, for some of these functions,
|
||||
the type is more specific:
|
||||
<ul>
|
||||
<li>`PolygonMesh` is a model of the concept `FaceGraph`</li>.
|
||||
<li>`GeomTraits` a geometric traits class in which constructions are performed and
|
||||
predicates evaluated. Everywhere in this package, a \cgal `Kernel` fulfills the requirements.</li>
|
||||
</ul>
|
||||
|
||||
The following named parameters, offered by the package \ref PkgBGL
|
||||
(see \ref bgl_namedparameters), are used in this package:
|
||||
|
||||
\cgalNPTableBegin
|
||||
\cgalNPBegin{vertex_point_map} \anchor OBB_vertex_point_map
|
||||
is the property map with the points associated to the vertices of the polygon mesh `pmesh`.\n
|
||||
<b>Type:</b> a class model of `ReadablePropertyMap` with
|
||||
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
|
||||
`GeomTraits::Point_3` as value type. \n
|
||||
<b>Default:</b> \code boost::get(CGAL::vertex_point, pmesh) \endcode
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{point_map} \anchor OBB_point_map
|
||||
is the property map containing the points associated to the elements of the point range `points`.\n
|
||||
<b>Type:</b> a class model of `ReadablePropertyMap` with `PointRange::iterator::value_type` as key type
|
||||
and `geom_traits::Point_3` as value type. \n
|
||||
<b>Default:</b> \code CGAL::Identity_property_map<geom_traits::Point_3>\endcode
|
||||
\cgalNPEnd
|
||||
\cgalNPTableEnd
|
||||
|
||||
In addition to these named parameters, this package offers the following named parameters:
|
||||
|
||||
\cgalNPTableBegin
|
||||
\cgalNPBegin{geom_traits} \anchor OBB_geom_traits
|
||||
is the geometric traits instance in which the mesh processing operation should be performed.\n
|
||||
<b>Type:</b> a Geometric traits class.\n
|
||||
<b>Default:</b>
|
||||
\code typename CGAL::Kernel_traits<
|
||||
typename boost::property_traits<
|
||||
typename boost::property_map<PolygonMesh, CGAL::vertex_point_t>::type>::value_type>::Kernel \endcode
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPBegin{use_convex_hull} \anchor OBB_use_convex_hull
|
||||
Parameter used in the construction of oriented bounding box to indicate whether the algorithm should
|
||||
first extract the extreme points (points that are on the 3D convex hull) of the input data range
|
||||
to accelerate the computation of the bounding box.
|
||||
\n
|
||||
<b>Type:</b> `bool` \n
|
||||
<b>Default:</b> `true`
|
||||
\cgalNPEnd
|
||||
|
||||
\cgalNPTableEnd
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_Building_Optimal_Bounding_Box
|
||||
\cgalAutoToc
|
||||
|
||||
\cgalFigureAnchor{OBBBanner}
|
||||
<center>
|
||||
<img src="obb_chess.png" style="max-width:70%;"/>
|
||||
</center>
|
||||
<!-- chess pieces from https://www.myminifactory.com/object/3d-print-chess-game-set-26114 -->
|
||||
|
||||
\authors Konstantinos Katrioplas, Mael Rouxel-Labbé
|
||||
|
||||
\section OBBIntro Introduction
|
||||
|
||||
Encompassing a model within a volume is a common approach to accelerate
|
||||
a number of applications such as collision detection or visibility testing:
|
||||
the proxy volume provides a rapid way to test a configuration or filter results,
|
||||
with the real model only being used when required.
|
||||
Typical coarser volumes that can be used to approximate a more complex
|
||||
model are simplified meshes (for example using the package \ref PkgSurfaceMeshSimplification),
|
||||
convex hulls, or simple rectangular boxes. Within this last
|
||||
category, the axis-aligned bounding box (AABB) has obvious advantages:
|
||||
it is extremely simple to compute and one may build a hierarchical
|
||||
structure of successively tighter volumes to further speed up intersection and distance computations.
|
||||
One such example of structure is the \cgal AABB tree (\ref PkgAABBTree).
|
||||
The disadvantage is also clear: the box is usually poorly fitting most models.
|
||||
A good compromise between the good approximation offered by convex hulls or simplified meshes
|
||||
and the speed offered by axis-aligned bounding boxes are <em>Optimal Bounding Boxes</em>.
|
||||
Contrary to the AABB, the optimal bounding box of a model is not necessarily axis-aligned,
|
||||
but provides a tight approximation.
|
||||
|
||||
\cgalFigureAnchor{obb_aabb_vs_obb}
|
||||
<center>
|
||||
<img src="aabb_vs_obb.jpg" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{obb_aabb_vs_obb}
|
||||
Left: the axis-aligned bounding box. Right: the optimal bounding box, a much better fit.
|
||||
<!-- source and license of the model: https://www.myminifactory.com/object/3d-print-chinese-new-year-dragon-incense-holder-5476 -->
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
In 2D, the optimal bounding rectangle of an input can be computed in linear time
|
||||
using the technique of <em>rotating calipers</em>, first introduced
|
||||
by Toussaint \cgalCite{cgal:t-sgprc-83} (see also the \cgal package \ref PkgBoundingVolumes).
|
||||
An algorithm to compute the optimal oriented bounding box in 3D was proposed
|
||||
by O’Rourke \cgalCite{cgal:or-fmeb-85}, but its cubic complexity in the number
|
||||
of points makes it unusable in practice. The implementation proposed
|
||||
in this package is based on the paper of Chang et al.\cgalCite{cgal:cgm-fobbo-11},
|
||||
who introduced an algorithm to compute a close approximation of the optimal
|
||||
bounding box. As this is but an approximation of the optimal bounding box,
|
||||
we call the resulting box, the <em>Oriented Bounding Box</em>.
|
||||
|
||||
\section OBBOrientedBoundingBox Oriented Bounding Box
|
||||
|
||||
The algorithm introduced by Chang et al. formulates the computation
|
||||
of the optimal bounding box as an unconstrained optimization problem
|
||||
on the 3D matrix rotation group. The function to optimize is defined
|
||||
as the volume of the box. Because this function is non-differentiable,
|
||||
in particular near local optima, traditional optimization methods
|
||||
might encounter convergence issues.
|
||||
Consequently, Chang et al.'s algorithm employs a combination
|
||||
of a derivative-free optimization method, the Nelder-Mead
|
||||
simplex method \cgalCite{cgal:nm-smfm-65}, and a metaheuristics method based on
|
||||
biological evolution principles to maintain and evolve a population of tentative
|
||||
rotation matrices. The purpose of this evolution is to oppose
|
||||
a global approach to the local Nelder-Mead optimization,
|
||||
enabling the algorithm to explore the search space as much as possible,
|
||||
and to find not only a local minimum, but a global optimum.
|
||||
|
||||
\subsection OBBOptimality Missing the Optimality
|
||||
|
||||
In theory, the genetic algorithms used by Chang et al. enable - given enough time - the algorithm
|
||||
to explore the complete search space. In practice, an algorithm does not have
|
||||
infinite time at its disposal. In addition, there is no simple way
|
||||
to check if the current-best solution is optimal. Thus, an implementation
|
||||
of the algorithm cannot provide the same guarantees that the theoretical algorithm offers.
|
||||
However, we observe that in practice the algorithm constructs a close approximation
|
||||
of the optimal bounding box most of the time.
|
||||
|
||||
\subsection OBBConvexHull Convex Hull Computation as Preprocessing
|
||||
|
||||
As the bounding box only depends on the convex hull of the object,
|
||||
computing its convex hull as a preprocessing step is a good way to reduce
|
||||
the number of points in subsequent computations. The computational trade-off
|
||||
is developed in more details in Section \ref OBBComplexityPerformance.
|
||||
|
||||
\section OBBImplementation Design and Implementation
|
||||
|
||||
The computation of the oriented bounding box can be performed by calling the free function
|
||||
`CGAL::oriented_bounding_box()`. Convex hull computation is performed using the package \ref PkgConvexHull3,
|
||||
and is enabled by default.
|
||||
|
||||
\subsection OBBInnOut Input and Output
|
||||
|
||||
The input can be a range of 3D points, or a mesh, with a variety of \ref obb_namedparameters "Named Parameters"
|
||||
enabling using further custom inputs.
|
||||
|
||||
The result of the algorithm can be retrieved as:
|
||||
- the best affine transformation \f${\mathcal R}_b\f$ that the algorithm has found;
|
||||
- an array of eight points, representing the best oriented bounding box that
|
||||
the algorithm has constructed, which is related to \f$ {\mathcal R}_b\f$ as it is
|
||||
the inverse transformation of the axis-aligned bounding box of the transformed input object.
|
||||
The order of the points in the array is the same as in the function
|
||||
\link PkgBGLHelperFct `CGAL::make_hexahedron()` \endlink,
|
||||
which can be used to construct a mesh from these points.
|
||||
- a model of `MutableFaceGraph`, a quadrangular mesh representing the oriented bounding box.
|
||||
|
||||
\subsection OBBTraitsnKernels Traits and Kernel Choice
|
||||
|
||||
The requirements on geometric objects and operations on these objects are described in the traits
|
||||
class concept `OrientedBoundingBoxTraits_3`. A model of this concept is provided:
|
||||
`CGAL::Oriented_bounding_box_traits_3`.
|
||||
|
||||
If the approach using the convex hull is chosen, a kernel offering exact predicates must be
|
||||
used to ensure a correct hull. In addition, the eight bounding vertices are constructed
|
||||
using the best found affine transformation; consequently, a kernel providing exact construction
|
||||
may also be useful.
|
||||
|
||||
\section OBBComplexityPerformance Complexity and Performance
|
||||
|
||||
A major drawback of the exact algorithm of O’Rourke is its cubic complexity
|
||||
and consequent large runtimes. In this section, we investigate the speedup gained
|
||||
by preprocessing the input data with a convex hull computation, and show that
|
||||
the oriented bounding box algorithm exhibits linear complexity.
|
||||
|
||||
Models from the <a href="https://ten-thousand-models.appspot.com/">Thingi10k</a> data set are used
|
||||
with speeds being averaged over 100 runs for each model. The machine used is a laptop running Fedora 30
|
||||
64-bits, with two 6-core Intel(R) i9-8950HK CPU clocked at 2.90GHz, and with 32GB of RAM. The \cgal
|
||||
kernel used is `CGAL::Exact_predicates_inexact_constructions_kernel`.
|
||||
|
||||
\subsection OBBConvexHullComplexity Cost and Gain of Convex Hull Computations
|
||||
|
||||
Computing the convex hull as a preliminary step provides a significant speed advantage.
|
||||
|
||||
\cgalFigureAnchor{ch_speed_up}
|
||||
<center>
|
||||
<img src="ch_speedup.png" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{ch_speed_up}
|
||||
Computation of the speedup achieved on the total runtime of the algorithm when the convex hull is computed
|
||||
and used afterwards. Note that the total runtime includes the construction of the convex hull (when it is used).
|
||||
The color and size of the dots represent the number of vertices in the input data (larger, bluer points
|
||||
having more input vertices than greener, smaller points).
|
||||
Computing the convex hull is beneficial for all but a handful of cases.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
\subsection OBBOrientedBoundingBoxComplexity Performance of the Oriented Bounding Box Algorithm
|
||||
|
||||
We analyze in this section the computation time of the algorithm based on the number of vertices
|
||||
on the convex hull.
|
||||
|
||||
\cgalFigureAnchor{obb_timings}
|
||||
<center>
|
||||
<img src="obb_time.png" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{obb_timings}
|
||||
Running times for the oriented bounding box construction of the convex hull of models
|
||||
of the <a href="https://ten-thousand-models.appspot.com/">Thingi10k</a> data set.
|
||||
The color and size of the dots represent the number of vertices in the input data (larger, bluer points
|
||||
having more input vertices than greener, smaller points).
|
||||
The algorithm exhibits linear complexity in practice.
|
||||
For visibility reasons, the few models whose convex hull has more than 10000 vertices
|
||||
are excluded from this graph, but consistent results are observed.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
\section OBBexamples Examples
|
||||
|
||||
\subsection OBBBasicExample Basic Example
|
||||
|
||||
The following example illustrates a basic usage of the algorithm: an input mesh is read,
|
||||
its oriented bounding box is computed using an array as output, and a mesh is constructed
|
||||
from the eight points.
|
||||
|
||||
\cgalExample{Optimal_bounding_box/obb_example.cpp}
|
||||
|
||||
\subsection OBBExampleNP Using Named Parameters
|
||||
|
||||
The following example illustrates how to use \ref obb_namedparameters "Named Parameters"
|
||||
to efficiently compute the oriented bounding box of a mesh whose vertices' positions are
|
||||
modified on the fly.
|
||||
|
||||
\cgalExample{Optimal_bounding_box/obb_with_point_maps_example.cpp}
|
||||
|
||||
\subsection OBBRotatedTree Rotated AABB Tree
|
||||
|
||||
The following example uses the affine transformation, which is the affine transformation such
|
||||
that the axis-aligned bounding box of the transformed vertices of the mesh has minimum volume,
|
||||
returned by the algorithm to build a custom vertex point property map. An AABB tree of the (on the fly)
|
||||
rotated faces of the mesh is then constructed.
|
||||
|
||||
\cgalExample{Optimal_bounding_box/rotated_aabb_tree_example.cpp}
|
||||
|
||||
\section OBBHistory Implementation History
|
||||
|
||||
A prototype was created by Konstantinos Katrioplas in 2018.
|
||||
Mael Rouxel-Labbé worked to speed up and robustify the implementation,
|
||||
and to submit the first version of this package.
|
||||
|
||||
*/
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
/// \defgroup PkgOptimalBoundingBoxRef Optimal Bounding Box Reference
|
||||
|
||||
/// \defgroup PkgOptimalBoundingBoxConcepts Concepts
|
||||
/// \ingroup PkgOptimalBoundingBoxRef
|
||||
|
||||
/// \defgroup PkgOptimalBoundingBoxClasses Optimal Bounding Box Classes
|
||||
/// \ingroup PkgOptimalBoundingBoxRef
|
||||
|
||||
/// \defgroup PkgOptimalBoundingBoxFunctions Optimal Bounding Box Functions
|
||||
/// \ingroup PkgOptimalBoundingBoxRef
|
||||
|
||||
/// \defgroup PkgOptimalBoundingBox_Oriented_bounding_box Oriented Bounding Box Functions
|
||||
/// \ingroup PkgOptimalBoundingBoxFunctions
|
||||
|
||||
/*!
|
||||
\addtogroup PkgOptimalBoundingBoxRef
|
||||
\cgalPkgDescriptionBegin{Optimal Bounding Box,PkgOptimalBoundingBox}
|
||||
\cgalPkgPicture{optimal_bounding_box.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthor{Konstantinos Katrioplas, Mael Rouxel-Labbé}
|
||||
\cgalPkgDesc{This package provides functions to compute tight oriented bounding boxes around a point set or a polygon mesh.}
|
||||
\cgalPkgManuals{Chapter_Building_Optimal_Bounding_Box,PkgOptimalBoundingBoxRef}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{5.1}
|
||||
\cgalPkgDependsOn{\ref PkgConvexHull3}
|
||||
\cgalPkgBib{cgal:obb}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgDemo{Polyhedron demo, polyhedron_3.zip}
|
||||
\cgalPkgShortInfoEnd
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
\cgalCRPSection{Parameters}
|
||||
|
||||
Optional parameters of the functions of this package are implemented as \ref BGLNamedParameters.
|
||||
The page \ref obb_namedparameters describes their usage and provides a list of the parameters
|
||||
that are used in this package.
|
||||
|
||||
\cgalCRPSection{Concepts}
|
||||
|
||||
- `OrientedBoundingBoxTraits_3`
|
||||
|
||||
\cgalCRPSection{Classes}
|
||||
|
||||
- `CGAL::Oriented_bounding_box_traits_3`
|
||||
|
||||
\cgalCRPSection{Methods}
|
||||
|
||||
- \link PkgOptimalBoundingBox_Oriented_bounding_box `CGAL::oriented_bounding_box()` \endlink
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
STL_Extension
|
||||
Algebraic_foundations
|
||||
Circulator
|
||||
Stream_support
|
||||
Polyhedron
|
||||
BGL
|
||||
Solver_interface
|
||||
Surface_mesh
|
||||
AABB_tree
|
||||
Property_map
|
||||
Surface_mesh_simplification
|
||||
Convex_hull_3
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/*!
|
||||
|
||||
\example Optimal_bounding_box/obb_example.cpp
|
||||
\example Optimal_bounding_box/obb_with_point_maps_example.cpp
|
||||
\example Optimal_bounding_box/rotated_aabb_tree_example.cpp
|
||||
*/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 158 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
|
|
@ -0,0 +1,31 @@
|
|||
# Created by the script cgal_create_cmake_script
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1...3.15)
|
||||
project( Optimal_bounding_box_Examples )
|
||||
|
||||
find_package(CGAL QUIET)
|
||||
|
||||
if (NOT CGAL_FOUND)
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
|
||||
if (NOT EIGEN3_FOUND)
|
||||
message(STATUS "This project requires the Eigen library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
create_single_source_cgal_program("obb_example.cpp")
|
||||
create_single_source_cgal_program("obb_with_point_maps_example.cpp")
|
||||
create_single_source_cgal_program("rotated_aabb_tree_example.cpp")
|
||||
|
||||
foreach(target
|
||||
obb_example
|
||||
obb_with_point_maps_example
|
||||
rotated_aabb_tree_example)
|
||||
CGAL_target_use_Eigen(${target})
|
||||
endforeach()
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,50 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
|
||||
#include <CGAL/Real_timer.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Surface_mesh;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::ifstream input((argc > 1) ? argv[1] : "data/pig.off");
|
||||
Surface_mesh sm;
|
||||
if(!input || !(input >> sm) || sm.is_empty())
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
|
||||
// Compute the extreme points of the mesh, and then a tightly fitted oriented bounding box
|
||||
std::array<Point, 8> obb_points;
|
||||
CGAL::oriented_bounding_box(sm, obb_points,
|
||||
CGAL::parameters::use_convex_hull(true));
|
||||
|
||||
std::cout << "Elapsed time: " << timer.time() << std::endl;
|
||||
|
||||
// Make a mesh out of the oriented bounding box
|
||||
Surface_mesh obb_sm;
|
||||
CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3],
|
||||
obb_points[4], obb_points[5], obb_points[6], obb_points[7], obb_sm);
|
||||
std::ofstream("obb.off") << obb_sm;
|
||||
|
||||
PMP::triangulate_faces(obb_sm);
|
||||
std::cout << "Volume: " << PMP::volume(obb_sm) << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point;
|
||||
typedef K::Vector_3 Vector;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Surface_mesh;
|
||||
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
namespace CP = CGAL::parameters;
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::ifstream input((argc > 1) ? argv[1] : "data/pig.off");
|
||||
Surface_mesh sm;
|
||||
if (!input || !(input >> sm) || sm.is_empty())
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// a typical call
|
||||
std::array<Point, 8> obb_points;
|
||||
CGAL::oriented_bounding_box(sm, obb_points);
|
||||
|
||||
// one can associate positions to the vertices of the mesh without changing the mesh
|
||||
std::unordered_map<vertex_descriptor, Point> translated_positions;
|
||||
for(const vertex_descriptor v : vertices(sm))
|
||||
translated_positions[v] = sm.point(v) + Vector(1, 2, 3);
|
||||
|
||||
CGAL::oriented_bounding_box(sm, obb_points,
|
||||
CP::vertex_point_map(boost::make_assoc_property_map(translated_positions)));
|
||||
|
||||
// using a range of points
|
||||
std::vector<Point> points;
|
||||
for(const vertex_descriptor v : vertices(sm))
|
||||
points.push_back(sm.point(v));
|
||||
CGAL::oriented_bounding_box(points, obb_points);
|
||||
|
||||
// one can associate positions to the range without changing the range
|
||||
std::map<Point, Point> scaled_positions;
|
||||
for(const Point& p : points)
|
||||
scaled_positions[p] = p + (p - CGAL::ORIGIN);
|
||||
|
||||
CGAL::oriented_bounding_box(points, obb_points,
|
||||
CP::point_map(boost::make_assoc_property_map(scaled_positions)));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/AABB_tree.h>
|
||||
#include <CGAL/AABB_traits.h>
|
||||
#include <CGAL/AABB_face_graph_triangle_primitive.h>
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::Point_3 Point;
|
||||
typedef K::Aff_transformation_3 Aff_transformation;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Surface_mesh;
|
||||
typedef boost::graph_traits<Surface_mesh>::vertex_descriptor vertex_descriptor;
|
||||
|
||||
struct Aff_tr_fct
|
||||
{
|
||||
Aff_tr_fct() : m_at(nullptr), m_sm(nullptr) { }
|
||||
Aff_tr_fct(const Aff_transformation& at, const Surface_mesh& sm) : m_at(&at), m_sm(&sm) { }
|
||||
|
||||
Point operator()(const vertex_descriptor v) const { return m_at->transform(m_sm->point(v)); }
|
||||
|
||||
private:
|
||||
const Aff_transformation* m_at;
|
||||
const Surface_mesh* m_sm;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::ifstream input((argc > 1) ? argv[1] : "data/pig.off");
|
||||
Surface_mesh sm;
|
||||
if (!input || !(input >> sm) || sm.is_empty())
|
||||
{
|
||||
std::cerr << "Invalid input file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// get the transformation that yields the optimal bounding box
|
||||
Aff_transformation at;
|
||||
CGAL::oriented_bounding_box(sm, at);
|
||||
|
||||
// functor to apply the affine transformation to a vertex of the mesh
|
||||
Aff_tr_fct aff_tr_fct(at, sm);
|
||||
auto aff_tr_vpm = boost::make_function_property_map<vertex_descriptor>(aff_tr_fct);
|
||||
|
||||
// rotated AABB tree
|
||||
typedef CGAL::AABB_face_graph_triangle_primitive<Surface_mesh, decltype(aff_tr_vpm)> AABB_face_graph_primitive;
|
||||
typedef CGAL::AABB_traits<K, AABB_face_graph_primitive> AABB_face_graph_traits;
|
||||
|
||||
CGAL::AABB_tree<AABB_face_graph_traits> tree(faces(sm).begin(), faces(sm).end(), sm, aff_tr_vpm);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_BOUNDING_BOX_TRAITS_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_BOUNDING_BOX_TRAITS_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/Aff_transformation_3.h>
|
||||
|
||||
#ifdef CGAL_EIGEN3_ENABLED
|
||||
#include <CGAL/Eigen_matrix.h>
|
||||
#include <CGAL/Eigen_vector.h>
|
||||
#include <Eigen/QR>
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
#if defined(CGAL_EIGEN3_ENABLED) || defined(DOXYGEN_RUNNING)
|
||||
|
||||
/// \ingroup PkgOptimalBoundingBoxClasses
|
||||
///
|
||||
/// The class `CGAL::Oriented_bounding_box_traits_3` is a traits type
|
||||
/// to be used with the overloads of the function `CGAL::oriented_bounding_box()`.
|
||||
///
|
||||
/// \attention This class requires the \ref thirdpartyEigen "Eigen" library.
|
||||
///
|
||||
/// \tparam K must be a model of `Kernel`
|
||||
///
|
||||
/// \cgalModels `OrientedBoundingBoxTraits_3`
|
||||
///
|
||||
template <typename K>
|
||||
class Oriented_bounding_box_traits_3
|
||||
: public K
|
||||
{
|
||||
public:
|
||||
/// The field number type
|
||||
typedef typename K::FT FT;
|
||||
|
||||
/// The affine transformation type
|
||||
typedef typename CGAL::Aff_transformation_3<K> Aff_transformation_3;
|
||||
|
||||
/// The matrix type
|
||||
typedef CGAL::Eigen_matrix<FT, 3, 3> Matrix;
|
||||
|
||||
/// The matrix type
|
||||
typedef CGAL::Eigen_vector<FT, 3> Vector;
|
||||
|
||||
private:
|
||||
typedef typename Matrix::EigenType EigenType;
|
||||
|
||||
public:
|
||||
/// Performs the QR-decomposition of the matrix `m` to a unitary matrix and an upper triagonal
|
||||
/// and returns the unitary matrix
|
||||
static Matrix get_Q(const Matrix& m)
|
||||
{
|
||||
Eigen::HouseholderQR<EigenType> qr(m.eigen_object());
|
||||
return Matrix(EigenType(qr.householderQ()));
|
||||
}
|
||||
};
|
||||
#endif // defined(CGAL_EIGEN3_ENABLED) || defined(DOXYGEN_RUNNING)
|
||||
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_BOUNDING_BOX_TRAITS_H
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
// Konstantinos Katrioplas
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/internal/fitness_function.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/helper.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/nelder_mead_functions.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/optimize_2.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/population.h>
|
||||
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/number_utils.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template <typename PointRange, typename Traits>
|
||||
class Evolution
|
||||
{
|
||||
public:
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
|
||||
typedef internal::Population<Traits> Population;
|
||||
typedef typename Population::Simplex Simplex;
|
||||
typedef typename Population::Vertex Vertex;
|
||||
|
||||
Evolution(const PointRange& points,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits)
|
||||
:
|
||||
m_best_v(nullptr),
|
||||
m_population(traits),
|
||||
m_rng(rng),
|
||||
m_points(points),
|
||||
m_traits(traits)
|
||||
{ }
|
||||
|
||||
void genetic_algorithm()
|
||||
{
|
||||
// This evolves an existing population
|
||||
CGAL_precondition(m_population.size() != 0);
|
||||
|
||||
//groups 1,2 : size = floor(m/2) groups 3,4 : size = ceil(m/2).
|
||||
const std::size_t m = m_population.size();
|
||||
const std::size_t first_group_size = m / 2;
|
||||
const std::size_t second_group_size = m - first_group_size;
|
||||
|
||||
std::vector<std::size_t> group1(first_group_size), group2(first_group_size);
|
||||
std::vector<std::size_t> group3(second_group_size), group4(second_group_size);
|
||||
|
||||
int im = static_cast<int>(m);
|
||||
std::generate(group1.begin(), group1.end(), [&]{ return m_rng.get_int(0, im); });
|
||||
std::generate(group2.begin(), group2.end(), [&]{ return m_rng.get_int(0, im); });
|
||||
std::generate(group3.begin(), group3.end(), [&]{ return m_rng.get_int(0, im); });
|
||||
std::generate(group4.begin(), group4.end(), [&]{ return m_rng.get_int(0, im); });
|
||||
|
||||
// crossover I, pick A or B
|
||||
constexpr FT lweight = 0.4, uweight = 0.6;
|
||||
|
||||
std::vector<Simplex> new_simplices(m);
|
||||
|
||||
for(std::size_t i=0; i<first_group_size; ++i)
|
||||
{
|
||||
Simplex offspring;
|
||||
for(int j=0; j<4; ++j)
|
||||
{
|
||||
const FT r{m_rng.get_double()};
|
||||
const FT fitnessA = m_population[group1[i]][j].fitness();
|
||||
const FT fitnessB = m_population[group2[i]][j].fitness();
|
||||
const FT threshold = (fitnessA < fitnessB) ? uweight : lweight;
|
||||
|
||||
if(r < threshold)
|
||||
offspring[j] = m_population[group1[i]][j];
|
||||
else
|
||||
offspring[j] = m_population[group2[i]][j];
|
||||
}
|
||||
|
||||
new_simplices[i] = std::move(offspring);
|
||||
}
|
||||
|
||||
// crossover II, combine information from A and B
|
||||
for(std::size_t i=0; i<second_group_size; ++i)
|
||||
{
|
||||
Simplex offspring;
|
||||
for(int j=0; j<4; ++j)
|
||||
{
|
||||
const FT fitnessA = m_population[group3[i]][j].fitness();
|
||||
const FT fitnessB = m_population[group4[i]][j].fitness();
|
||||
const FT lambda = (fitnessA < fitnessB) ? uweight : lweight;
|
||||
const FT rambda = FT(1) - lambda; // because the 'l' in 'lambda' stands for left
|
||||
|
||||
const Matrix& lm = m_population[group3[i]][j].matrix();
|
||||
const Matrix& rm = m_population[group4[i]][j].matrix();
|
||||
|
||||
offspring[j] = Vertex{m_traits.get_Q(lambda*lm + rambda*rm), m_points, m_traits};
|
||||
}
|
||||
|
||||
new_simplices[first_group_size + i] = std::move(offspring);
|
||||
}
|
||||
|
||||
m_population.simplices() = std::move(new_simplices);
|
||||
}
|
||||
|
||||
// @todo re-enable random mutations as it is -on theory- useful, but don't allow them to override
|
||||
// the best (current) candidates
|
||||
void evolve(const std::size_t max_generations,
|
||||
const std::size_t population_size,
|
||||
const std::size_t nelder_mead_iterations,
|
||||
const std::size_t max_random_mutations = 0)
|
||||
{
|
||||
// stopping criteria prameters
|
||||
FT prev_fit_value = 0;
|
||||
const FT tolerance = 1e-10;
|
||||
int stale = 0;
|
||||
|
||||
m_population.initialize(population_size, m_points, m_rng);
|
||||
|
||||
std::size_t gen_iter = 0;
|
||||
for(;;)
|
||||
{
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "- - - - generation #" << gen_iter << "\n";
|
||||
#endif
|
||||
|
||||
genetic_algorithm();
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "population after genetic" << std::endl;
|
||||
pop.show_population();
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
for(std::size_t s=0; s<population_size; ++s)
|
||||
nelder_mead(m_population[s], nelder_mead_iterations, m_points, m_traits);
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "population after nelder mead: " << std::endl;
|
||||
pop.show_population();
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
// optimize the current best rotation by using the exact OBB 2D algorithm
|
||||
// along the axes of the current best OBB
|
||||
m_best_v = &(m_population.get_best_vertex());
|
||||
Matrix& best_m = m_best_v->matrix();
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "new best matrix: " << std::endl << best_m << std::endl;
|
||||
std::cout << "fitness: " << m_best_v->fitness() << std::endl;
|
||||
#endif
|
||||
|
||||
optimize_along_OBB_axes(best_m, m_points, m_traits);
|
||||
m_best_v->fitness() = compute_fitness(best_m, m_points, m_traits);
|
||||
|
||||
// stopping criteria
|
||||
const FT new_fit_value = m_best_v->fitness();
|
||||
const FT difference = new_fit_value - prev_fit_value;
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "post 2D optimization matrix: " << std::endl << best_m << std::endl;
|
||||
std::cout << "new fit value: " << new_fit_value << std::endl;
|
||||
std::cout << "difference: " << difference << std::endl;
|
||||
#endif
|
||||
|
||||
if(CGAL::abs(difference) < tolerance * new_fit_value)
|
||||
++stale;
|
||||
|
||||
if(stale == 5 || gen_iter++ >= max_generations)
|
||||
break;
|
||||
|
||||
prev_fit_value = new_fit_value;
|
||||
|
||||
// random mutations, swap #random_mutations random simplices with a new, random simplex
|
||||
if(max_random_mutations <= 0)
|
||||
continue;
|
||||
|
||||
CGAL_warning(max_random_mutations <= population_size);
|
||||
const int random_mutations = m_rng.get_int(0, static_cast<int>(max_random_mutations+1));
|
||||
for(int i=0; i<random_mutations; ++i)
|
||||
{
|
||||
const int random_pos = m_rng.get_int(0, static_cast<int>(population_size));
|
||||
m_population[random_pos] = m_population.create_simplex(m_points, m_rng);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Vertex& get_best_vertex() const
|
||||
{
|
||||
CGAL_assertion(m_best_v != nullptr);
|
||||
return *m_best_v;
|
||||
}
|
||||
|
||||
private:
|
||||
Vertex* m_best_v;
|
||||
Population m_population;
|
||||
|
||||
CGAL::Random& m_rng;
|
||||
const PointRange& m_points;
|
||||
const Traits& m_traits;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
// Konstantinos Katrioplas
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template <typename Traits, typename PointRange>
|
||||
typename Traits::FT
|
||||
compute_fitness(const typename Traits::Matrix& R, // rotation matrix
|
||||
const PointRange& points,
|
||||
const Traits& /*traits*/)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_3 Point;
|
||||
typedef typename Traits::Vector Vector;
|
||||
|
||||
CGAL_assertion(R.number_of_rows() == 3 && R.number_of_columns() == 3);
|
||||
CGAL_assertion(points.size() >= 3);
|
||||
|
||||
FT xmin, ymin, zmin, xmax, ymax, zmax;
|
||||
xmin = ymin = zmin = FT{std::numeric_limits<double>::max()};
|
||||
xmax = ymax = zmax = FT{std::numeric_limits<double>::lowest()};
|
||||
|
||||
for(const Point& pt : points)
|
||||
{
|
||||
Vector pv(3);
|
||||
pv.set(0, pt.x());
|
||||
pv.set(1, pt.y());
|
||||
pv.set(2, pt.z());
|
||||
pv = R * pv;
|
||||
|
||||
xmin = (std::min)(xmin, pv(0));
|
||||
ymin = (std::min)(ymin, pv(1));
|
||||
zmin = (std::min)(zmin, pv(2));
|
||||
xmax = (std::max)(xmax, pv(0));
|
||||
ymax = (std::max)(ymax, pv(1));
|
||||
zmax = (std::max)(zmax, pv(2));
|
||||
}
|
||||
|
||||
// volume
|
||||
return ((xmax - xmin) * (ymax - ymin) * (zmax - zmin));
|
||||
}
|
||||
|
||||
// In this function, we only care about the fitness if it is smaller.
|
||||
// Since it likely to not be smaller, we compute the volume and the value
|
||||
// that is interesting from time to time.
|
||||
// Since the volume only grows, we exit early if greater.
|
||||
template <typename Traits, typename PointRange>
|
||||
std::pair<typename Traits::FT, bool>
|
||||
compute_fitness_if_smaller(const typename Traits::Matrix& R, // rotation matrix
|
||||
const PointRange& points,
|
||||
const typename Traits::FT cmp_val,
|
||||
const Traits& /*traits*/)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_3 Point;
|
||||
typedef typename Traits::Vector Vector;
|
||||
|
||||
CGAL_assertion(R.number_of_rows() == 3 && R.number_of_columns() == 3);
|
||||
CGAL_assertion(points.size() >= 3);
|
||||
|
||||
FT xmin, ymin, zmin, xmax, ymax, zmax;
|
||||
xmin = ymin = zmin = FT{std::numeric_limits<double>::max()};
|
||||
xmax = ymax = zmax = FT{std::numeric_limits<double>::lowest()};
|
||||
|
||||
// compute every 1%, with a minimum of 1000 iterations
|
||||
const std::size_t pn = points.size();
|
||||
const std::size_t mpn = (std::max)(pn / 10, std::size_t(1000));
|
||||
std::size_t next_check = mpn; // to avoid a costly modulo
|
||||
|
||||
// std::cout << "pn, mpn, next_check: " << pn << " " << mpn << std::endl;
|
||||
|
||||
std::size_t i = 0;
|
||||
for(const Point& pt : points)
|
||||
{
|
||||
Vector pv(3);
|
||||
pv.set(0, pt.x());
|
||||
pv.set(1, pt.y());
|
||||
pv.set(2, pt.z());
|
||||
pv = R * pv;
|
||||
|
||||
xmin = (std::min)(xmin, pv(0));
|
||||
ymin = (std::min)(ymin, pv(1));
|
||||
zmin = (std::min)(zmin, pv(2));
|
||||
xmax = (std::max)(xmax, pv(0));
|
||||
ymax = (std::max)(ymax, pv(1));
|
||||
zmax = (std::max)(zmax, pv(2));
|
||||
|
||||
if(i++ == next_check)
|
||||
{
|
||||
if((xmax - xmin) * (ymax - ymin) * (zmax - zmin) > cmp_val)
|
||||
return std::make_pair(FT(0), false);
|
||||
|
||||
next_check += mpn;
|
||||
}
|
||||
}
|
||||
|
||||
// volume
|
||||
return std::make_pair((xmax - xmin) * (ymax - ymin) * (zmax - zmin), true);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Konstantinos Katrioplas
|
||||
// Mael Rouxel-Labbé
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_HELPER_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_HELPER_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template <typename Matrix>
|
||||
Matrix transpose(const Matrix& m)
|
||||
{
|
||||
Matrix tm;
|
||||
|
||||
tm.set(0, 0, m(0, 0)); tm.set(0, 1, m(1, 0)); tm.set(0, 2, m(2, 0));
|
||||
tm.set(1, 0, m(0, 1)); tm.set(1, 1, m(1, 1)); tm.set(1, 2, m(2, 1));
|
||||
tm.set(2, 0, m(0, 2)); tm.set(2, 1, m(1, 2)); tm.set(2, 2, m(2, 2));
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_HELPER_H
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
// Konstantinos Katrioplas
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_NEALDER_MEAD_FUNCTIONS_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_NEALDER_MEAD_FUNCTIONS_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/internal/fitness_function.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/helper.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template <typename Matrix>
|
||||
Matrix reflection(const Matrix& S_centroid,
|
||||
const Matrix& S_worst)
|
||||
{
|
||||
return S_centroid * transpose(S_worst) * S_centroid;
|
||||
}
|
||||
|
||||
template <typename Matrix>
|
||||
Matrix expansion(const Matrix& S_centroid,
|
||||
const Matrix& S_worst,
|
||||
const Matrix& S_reflection)
|
||||
{
|
||||
return S_centroid * transpose(S_worst) * S_reflection;
|
||||
}
|
||||
|
||||
template <typename Matrix, typename Traits>
|
||||
Matrix mean(const Matrix& m1,
|
||||
const Matrix& m2,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
|
||||
const FT half = FT(1) / FT(2);
|
||||
const Matrix reduction = half * (m1 + m2);
|
||||
|
||||
return traits.get_Q(reduction);
|
||||
}
|
||||
|
||||
template <typename Matrix, typename Traits>
|
||||
const Matrix nm_centroid(const Matrix& S1,
|
||||
const Matrix& S2,
|
||||
const Matrix& S3,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
|
||||
const FT third = FT(1) / FT(3);
|
||||
const Matrix mean = third * (S1 + S2 + S3);
|
||||
|
||||
return traits.get_Q(mean);
|
||||
}
|
||||
|
||||
// It's a 3D simplex with 4 rotation matrices as vertices
|
||||
template <typename Simplex, typename PointRange, typename Traits>
|
||||
void nelder_mead(Simplex& simplex,
|
||||
const std::size_t nelder_mead_iterations,
|
||||
const PointRange& points,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Simplex::value_type Vertex;
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
|
||||
for(std::size_t t=0; t<nelder_mead_iterations; ++t)
|
||||
{
|
||||
std::sort(simplex.begin(), simplex.end(),
|
||||
[](const Vertex& vi, const Vertex& vj) -> bool
|
||||
{ return vi.fitness() < vj.fitness(); });
|
||||
|
||||
// centroid
|
||||
const Matrix centroid_m = nm_centroid(simplex[0].matrix(),
|
||||
simplex[1].matrix(),
|
||||
simplex[2].matrix(), traits);
|
||||
|
||||
// find worst's vertex reflection
|
||||
const Matrix& worst_m = simplex[3].matrix();
|
||||
const Matrix refl_m = reflection(centroid_m, worst_m);
|
||||
const FT second_worst_fitness = simplex[2].fitness();
|
||||
|
||||
// we are only interested in the reflection vertex if it's better than the second worst,
|
||||
// so compute the fitness, but exit early if the volume grows too big.
|
||||
const std::pair<FT, bool> refl_fb = compute_fitness_if_smaller(refl_m, points, second_worst_fitness, traits);
|
||||
|
||||
// if the reflected point is better than the second worst
|
||||
if(refl_fb.second && refl_fb.first < second_worst_fitness)
|
||||
{
|
||||
const FT refl_f = refl_fb.first;
|
||||
|
||||
// if the reflected point is not better than the best
|
||||
if(refl_f >= simplex[0].fitness())
|
||||
{
|
||||
// reflection
|
||||
simplex[3] = Vertex{refl_m, refl_f};
|
||||
}
|
||||
else
|
||||
{
|
||||
// expansion
|
||||
const Matrix expand_m = expansion(centroid_m, worst_m, refl_m);
|
||||
const std::pair<FT, bool> expand_fb = compute_fitness_if_smaller(expand_m, points, refl_f, traits);
|
||||
if(expand_fb.second && expand_fb.first < refl_f)
|
||||
simplex[3] = Vertex{expand_m, expand_fb.first};
|
||||
else
|
||||
simplex[3] = Vertex{refl_m, refl_f};
|
||||
}
|
||||
}
|
||||
else // the reflected vertex is worse
|
||||
{
|
||||
const Matrix mean_m = mean(centroid_m, worst_m, traits);
|
||||
const FT worst_fitness = simplex[3].fitness();
|
||||
const std::pair<FT, bool> mean_fb = compute_fitness_if_smaller(mean_m, points, worst_fitness, traits);
|
||||
|
||||
if(mean_fb.second && mean_fb.first <= worst_fitness)
|
||||
{
|
||||
// contraction of worst
|
||||
simplex[3] = Vertex{mean_m, mean_fb.first};
|
||||
}
|
||||
else
|
||||
{
|
||||
// reduction: move all vertices towards the best
|
||||
for(std::size_t i=1; i<4; ++i)
|
||||
simplex[i] = Vertex{mean(simplex[i].matrix(), simplex[0].matrix(), traits), points, traits};
|
||||
}
|
||||
}
|
||||
} // nelder mead iterations
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
// Copyright (c) 2020 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_OPTIMIZE_2_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_OPTIMIZE_2_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/ch_akl_toussaint.h>
|
||||
#include <CGAL/min_quadrilateral_2.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/number_type_config.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
enum PROJECTION_DIRECTION
|
||||
{
|
||||
ALONG_X = 0,
|
||||
ALONG_Y,
|
||||
ALONG_Z
|
||||
};
|
||||
|
||||
// Now, we would like to do all of this with projection traits... Unfortunately, it's missing
|
||||
// a couple of functors (Has_on_negative_side_2, for example), which are necessary in
|
||||
// CGAL::Min_quadrilateral_default_traits_2. And while we know we have a generic case here,
|
||||
// it's a bit tedious to get something well-defined in the generic case: for example,
|
||||
// what should Has_on_negative_side_2 do if the Line_3 is orthogonal to the projection plane?
|
||||
//
|
||||
// So, easier to just bail out to real 2D...
|
||||
template <typename Traits, typename PointRange>
|
||||
std::pair<typename Traits::FT, typename Traits::FT>
|
||||
compute_2D_deviation(const PointRange& points,
|
||||
const PROJECTION_DIRECTION dir,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_2 Point_2;
|
||||
typedef typename Traits::Vector_2 Vector_2;
|
||||
typedef typename Traits::Point_3 Point_3;
|
||||
|
||||
std::vector<Point_2> points_2D;
|
||||
points_2D.reserve(points.size());
|
||||
for(const Point_3& pt : points)
|
||||
{
|
||||
if(dir == ALONG_X)
|
||||
points_2D.emplace_back(pt.y(), pt.z());
|
||||
else if(dir == ALONG_Y)
|
||||
points_2D.emplace_back(pt.x(), pt.z());
|
||||
else if(dir == ALONG_Z)
|
||||
points_2D.emplace_back(pt.x(), pt.y());
|
||||
}
|
||||
|
||||
std::vector<Point_2> extreme_points;
|
||||
ch_akl_toussaint(points_2D.begin(), points_2D.end(), std::back_inserter(extreme_points), traits);
|
||||
|
||||
CGAL::Polygon_2<Traits> pol;
|
||||
CGAL::Min_quadrilateral_default_traits_2<Traits> mrt;
|
||||
CGAL::min_rectangle_2(extreme_points.begin(), extreme_points.end(), std::back_inserter(pol), mrt);
|
||||
|
||||
if(pol.size() == 4 || !pol.is_simple() || pol.is_clockwise_oriented())
|
||||
return std::make_pair(0., 0.);
|
||||
|
||||
// Compute the angle between the angle necessary to rotate the rectangle onto the reference frame
|
||||
auto bot_pos = pol.bottom_vertex();
|
||||
auto next_pos = bot_pos;
|
||||
++next_pos;
|
||||
if(next_pos == pol.vertices_end())
|
||||
next_pos = pol.begin();
|
||||
|
||||
const Point_2& p = *bot_pos;
|
||||
const Point_2& q = *next_pos;
|
||||
|
||||
const Vector_2 pq = traits.construct_vector_2_object()(p, q);
|
||||
double n = sqrt(to_double(traits.compute_squared_length_2_object()(pq)));
|
||||
|
||||
if(n == 0.) // degenerate input, maybe? Let's just not do anything
|
||||
return std::make_pair(pol.area(), 0.);
|
||||
|
||||
const double dot = pq.x(); // that's the scalar product of PQ with V(1, 0) (Ox)
|
||||
double cosine = dot / n;
|
||||
|
||||
if(cosine > 1.)
|
||||
cosine = 1.;
|
||||
if(cosine < -1.)
|
||||
cosine = -1.;
|
||||
|
||||
double theta = std::acos(cosine);
|
||||
if(theta > 0.25 * CGAL_PI) // @todo is there a point to this
|
||||
theta = 0.5 * CGAL_PI - theta;
|
||||
|
||||
return std::make_pair(pol.area(), FT{theta});
|
||||
}
|
||||
|
||||
template <typename PointRange, typename Traits>
|
||||
void optimize_along_OBB_axes(typename Traits::Matrix& rot,
|
||||
const PointRange& points,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Point_3 Point;
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
typedef typename Traits::Vector Vector;
|
||||
|
||||
CGAL_static_assertion((std::is_same<typename boost::range_value<PointRange>::type, Point>::value));
|
||||
|
||||
std::vector<Point> rotated_points;
|
||||
rotated_points.reserve(points.size());
|
||||
|
||||
FT xmin, ymin, zmin, xmax, ymax, zmax;
|
||||
xmin = ymin = zmin = FT{std::numeric_limits<double>::max()};
|
||||
xmax = ymax = zmax = FT{std::numeric_limits<double>::lowest()};
|
||||
|
||||
for(const Point& pt : points)
|
||||
{
|
||||
Vector pv(3);
|
||||
pv.set(0, pt.x());
|
||||
pv.set(1, pt.y());
|
||||
pv.set(2, pt.z());
|
||||
pv = rot * pv;
|
||||
|
||||
rotated_points.emplace_back(pv(0), pv(1), pv(2));
|
||||
|
||||
xmin = (std::min)(xmin, pv(0));
|
||||
ymin = (std::min)(ymin, pv(1));
|
||||
zmin = (std::min)(zmin, pv(2));
|
||||
xmax = (std::max)(xmax, pv(0));
|
||||
ymax = (std::max)(ymax, pv(1));
|
||||
zmax = (std::max)(zmax, pv(2));
|
||||
}
|
||||
|
||||
const FT lx = xmax - xmin;
|
||||
const FT ly = ymax - ymin;
|
||||
const FT lz = zmax - zmin;
|
||||
|
||||
std::array<FT, 3> angles;
|
||||
std::array<FT, 3> volumes;
|
||||
|
||||
FT area_xy;
|
||||
std::tie(area_xy, angles[0]) = compute_2D_deviation(rotated_points, ALONG_Z, traits);
|
||||
volumes[0] = lz * area_xy;
|
||||
|
||||
FT area_xz;
|
||||
std::tie(area_xz, angles[1]) = compute_2D_deviation(rotated_points, ALONG_Y, traits);
|
||||
volumes[1] = ly * area_xz;
|
||||
|
||||
FT area_yz;
|
||||
std::tie(area_yz, angles[2]) = compute_2D_deviation(rotated_points, ALONG_X, traits);
|
||||
volumes[2] = lx * area_yz;
|
||||
|
||||
auto it = std::min_element(volumes.begin(), volumes.end());
|
||||
typename std::iterator_traits<decltype(it)>::difference_type d = std::distance(volumes.begin(), it);
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_PP
|
||||
std::cout << "volumes: " << volumes[0] << " " << volumes[1] << " " << volumes[2] << std::endl;
|
||||
std::cout << "angles: " << angles[0] << " " << angles[1] << " " << angles[2] << std::endl;
|
||||
std::cout << "min at " << d << std::endl;
|
||||
#endif
|
||||
|
||||
if(d == 0) // Along_Z
|
||||
{
|
||||
const double c = std::cos(angles[0]);
|
||||
const double s = std::sin(angles[0]);
|
||||
|
||||
Matrix opt;
|
||||
opt.set(0, 0, c); opt.set(0, 1, s); opt.set(0, 2, 0);
|
||||
opt.set(1, 0, -s); opt.set(1, 1, c); opt.set(1, 2, 0);
|
||||
opt.set(2, 0, 0); opt.set(2, 1, 0); opt.set(2, 2, 1);
|
||||
|
||||
rot = opt * rot;
|
||||
}
|
||||
else if(d == 1) // Along_Y
|
||||
{
|
||||
const double c = std::cos(angles[1]);
|
||||
const double s = std::sin(angles[1]);
|
||||
|
||||
Matrix opt;
|
||||
opt.set(0, 0, c); opt.set(0, 1, 0); opt.set(0, 2, -s);
|
||||
opt.set(1, 0, 0); opt.set(1, 1, 1); opt.set(1, 2, 0);
|
||||
opt.set(2, 0, s); opt.set(2, 1, 0); opt.set(2, 2, c);
|
||||
|
||||
rot = opt * rot;
|
||||
}
|
||||
else if(d == 2) // Along_X
|
||||
{
|
||||
const double c = std::cos(angles[2]);
|
||||
const double s = std::sin(angles[2]);
|
||||
|
||||
Matrix opt;
|
||||
opt.set(0, 0, 1); opt.set(0, 1, 0); opt.set(0, 2, 0);
|
||||
opt.set(1, 0, 0); opt.set(1, 1, c); opt.set(1, 2, s);
|
||||
opt.set(2, 0, 0); opt.set(2, 1, -s); opt.set(2, 2, c);
|
||||
|
||||
rot = opt * rot;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGAL_assertion(false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_INTERNAL_OPTIMIZE_2_H
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
// Konstantinos Katrioplas
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/internal/fitness_function.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Random.h>
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template<typename Traits>
|
||||
struct Vertex_with_fitness
|
||||
{
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
|
||||
Vertex_with_fitness() { CGAL_assertion_code(m_is_val_initialized = false;) }
|
||||
Vertex_with_fitness(const Matrix m, const FT v) : m_mat(std::move(m)), m_val(v)
|
||||
{
|
||||
CGAL_assertion_code(m_is_val_initialized = true;)
|
||||
}
|
||||
|
||||
template <typename PointRange>
|
||||
Vertex_with_fitness(const Matrix m,
|
||||
const PointRange& points,
|
||||
const Traits& traits)
|
||||
:
|
||||
m_mat(std::move(m))
|
||||
{
|
||||
m_val = compute_fitness(m, points, traits);
|
||||
CGAL_assertion_code(m_is_val_initialized = true;)
|
||||
}
|
||||
|
||||
Matrix& matrix() { return m_mat; }
|
||||
const Matrix& matrix() const { return m_mat; }
|
||||
FT& fitness() { return m_val; }
|
||||
FT fitness() const { CGAL_assertion(m_is_val_initialized); return m_val; }
|
||||
|
||||
private:
|
||||
Matrix m_mat;
|
||||
FT m_val;
|
||||
CGAL_assertion_code(bool m_is_val_initialized;)
|
||||
};
|
||||
|
||||
template<typename Traits>
|
||||
class Population
|
||||
{
|
||||
public:
|
||||
typedef typename Traits::FT FT;
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
|
||||
typedef Vertex_with_fitness<Traits> Vertex;
|
||||
typedef std::array<Vertex, 4> Simplex;
|
||||
typedef std::vector<Simplex> Simplex_container;
|
||||
|
||||
public:
|
||||
Population(const Traits& traits) : m_traits(traits) { }
|
||||
|
||||
// Access
|
||||
std::size_t size() const { return m_simplices.size(); }
|
||||
Simplex& operator[](const std::size_t i) { CGAL_assertion(i < m_simplices.size()); return m_simplices[i]; }
|
||||
const Simplex& operator[](const std::size_t i) const { CGAL_assertion(i < m_simplices.size()); return m_simplices[i]; }
|
||||
Simplex_container& simplices() { return m_simplices; }
|
||||
|
||||
private:
|
||||
Matrix create_random_matrix(CGAL::Random& rng) const
|
||||
{
|
||||
Matrix m;
|
||||
|
||||
for(std::size_t i=0; i<3; ++i)
|
||||
for(std::size_t j=0; j<3; ++j)
|
||||
m.set(i, j, FT(rng.get_double()));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename PointRange>
|
||||
Simplex create_simplex(const PointRange& points,
|
||||
CGAL::Random& rng) const
|
||||
{
|
||||
Simplex s;
|
||||
for(std::size_t i=0; i<4; ++i)
|
||||
s[i] = Vertex{m_traits.get_Q(create_random_matrix(rng)), points, m_traits};
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// create random population
|
||||
template <typename PointRange>
|
||||
void initialize(const std::size_t population_size,
|
||||
const PointRange& points,
|
||||
CGAL::Random& rng)
|
||||
{
|
||||
m_simplices.clear();
|
||||
m_simplices.reserve(population_size);
|
||||
for(std::size_t i=0; i<population_size; ++i)
|
||||
m_simplices.emplace_back(create_simplex(points, rng));
|
||||
}
|
||||
|
||||
Vertex& get_best_vertex()
|
||||
{
|
||||
std::size_t simplex_id = static_cast<std::size_t>(-1), vertex_id = static_cast<std::size_t>(-1);
|
||||
FT best_fitness = FT{std::numeric_limits<double>::max()};
|
||||
for(std::size_t i=0, ps=m_simplices.size(); i<ps; ++i)
|
||||
{
|
||||
for(std::size_t j=0; j<4; ++j)
|
||||
{
|
||||
const Vertex& vertex = m_simplices[i][j];
|
||||
const FT fitness = vertex.fitness();
|
||||
if(fitness < best_fitness)
|
||||
{
|
||||
simplex_id = i;
|
||||
vertex_id = j;
|
||||
best_fitness = fitness;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_simplices[simplex_id][vertex_id];
|
||||
}
|
||||
|
||||
// Debug
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
|
||||
void show_population() const
|
||||
{
|
||||
std::size_t id = 0;
|
||||
for(const Simplex& s : m_simplices)
|
||||
{
|
||||
std::cout << "Simplex: " << id++ << std::endl;
|
||||
for(const Matrix& m : s)
|
||||
std::cout << m << "\n\n";
|
||||
std:: cout << std:: endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::vector<Simplex> m_simplices;
|
||||
|
||||
const Traits& m_traits;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H
|
||||
|
|
@ -0,0 +1,432 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Mael Rouxel-Labbé
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_ORIENTED_BOUNDING_BOX_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_ORIENTED_BOUNDING_BOX_H
|
||||
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/internal/evolution.h>
|
||||
#include <CGAL/Optimal_bounding_box/internal/population.h>
|
||||
#include <CGAL/Optimal_bounding_box/Oriented_bounding_box_traits_3.h>
|
||||
|
||||
#include <CGAL/boost/graph/Named_function_parameters.h>
|
||||
#include <CGAL/boost/graph/named_params_helper.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#include <CGAL/Convex_hull_traits_3.h>
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
#include <CGAL/Iso_cuboid_3.h>
|
||||
#include <CGAL/Iterator_range.h>
|
||||
#include <CGAL/Kernel_traits.h>
|
||||
#include <CGAL/Random.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
#include <CGAL/Real_timer.h>
|
||||
#endif
|
||||
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/range/value_type.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#ifdef DOXYGEN_RUNNING
|
||||
#define CGAL_BGL_NP_TEMPLATE_PARAMETERS NamedParameters
|
||||
#define CGAL_BGL_NP_CLASS NamedParameters
|
||||
#endif
|
||||
|
||||
namespace CGAL {
|
||||
namespace Optimal_bounding_box {
|
||||
namespace internal {
|
||||
|
||||
template <typename PointRange, typename Traits>
|
||||
void construct_oriented_bounding_box(const PointRange& points,
|
||||
const typename Traits::Aff_transformation_3& transformation,
|
||||
const typename Traits::Aff_transformation_3& inverse_transformation,
|
||||
std::array<typename Traits::Point_3, 8>& obb_points,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Point_3 Point;
|
||||
|
||||
// Construct the bbox of the transformed point set
|
||||
CGAL::Bbox_3 bbox;
|
||||
for(const Point& pt : points)
|
||||
{
|
||||
const Point rotated_pt = transformation.transform(pt);
|
||||
bbox += traits.construct_bbox_3_object()(rotated_pt);
|
||||
}
|
||||
|
||||
obb_points[0] = Point(bbox.xmin(), bbox.ymin(), bbox.zmin());
|
||||
obb_points[1] = Point(bbox.xmax(), bbox.ymin(), bbox.zmin());
|
||||
obb_points[2] = Point(bbox.xmax(), bbox.ymax(), bbox.zmin());
|
||||
obb_points[3] = Point(bbox.xmin(), bbox.ymax(), bbox.zmin());
|
||||
|
||||
obb_points[4] = Point(bbox.xmin(), bbox.ymax(), bbox.zmax()); // see order in make_hexahedron()...
|
||||
obb_points[5] = Point(bbox.xmin(), bbox.ymin(), bbox.zmax());
|
||||
obb_points[6] = Point(bbox.xmax(), bbox.ymin(), bbox.zmax());
|
||||
obb_points[7] = Point(bbox.xmax(), bbox.ymax(), bbox.zmax());
|
||||
|
||||
// Apply the inverse rotation to the rotated axis aligned bounding box
|
||||
for(std::size_t i=0; i<8; ++i)
|
||||
{
|
||||
obb_points[i] = inverse_transformation.transform(obb_points[i]);
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
|
||||
std::cout << " OBB[" << i << "] = " << obb_points[i] << std::endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename PointRange, typename Traits>
|
||||
void compute_best_transformation(const PointRange& points,
|
||||
typename Traits::Aff_transformation_3& transformation,
|
||||
typename Traits::Aff_transformation_3& inverse_transformation,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Matrix Matrix;
|
||||
typedef typename Traits::Aff_transformation_3 Aff_transformation_3;
|
||||
|
||||
CGAL_assertion(points.size() >= 3);
|
||||
|
||||
const std::size_t max_generations = 100;
|
||||
const std::size_t population_size = 30;
|
||||
const std::size_t nelder_mead_iterations = 20;
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
Evolution<PointRange, Traits> search_solution(points, rng, traits);
|
||||
search_solution.evolve(max_generations, population_size, nelder_mead_iterations);
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
std::cout << "evolve: " << timer.time() << std::endl;
|
||||
timer.reset();
|
||||
#endif
|
||||
|
||||
const Matrix& rot = search_solution.get_best_vertex().matrix();
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
std::cout << "get best: " << timer.time() << std::endl;
|
||||
#endif
|
||||
|
||||
transformation = Aff_transformation_3(rot(0, 0), rot(0, 1), rot(0, 2),
|
||||
rot(1, 0), rot(1, 1), rot(1, 2),
|
||||
rot(2, 0), rot(2, 1), rot(2, 2));
|
||||
|
||||
// inverse transformation is simply the transposed since the matrix is unitary
|
||||
inverse_transformation = Aff_transformation_3(rot(0, 0), rot(1, 0), rot(2, 0),
|
||||
rot(0, 1), rot(1, 1), rot(2, 1),
|
||||
rot(0, 2), rot(1, 2), rot(2, 2));
|
||||
}
|
||||
|
||||
// Following two functions are overloads to dispatch depending on return type
|
||||
template <typename PointRange, typename K, typename Traits>
|
||||
void construct_oriented_bounding_box(const PointRange& points,
|
||||
CGAL::Aff_transformation_3<K>& transformation,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits)
|
||||
{
|
||||
typename Traits::Aff_transformation_3 inverse_transformation;
|
||||
compute_best_transformation(points, transformation, inverse_transformation, rng, traits);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename Array, typename Traits>
|
||||
void construct_oriented_bounding_box(const PointRange& points,
|
||||
Array& obb_points,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits,
|
||||
typename boost::enable_if<
|
||||
typename boost::has_range_iterator<Array>
|
||||
>::type* = 0)
|
||||
{
|
||||
typename Traits::Aff_transformation_3 transformation, inverse_transformation;
|
||||
compute_best_transformation(points, transformation, inverse_transformation, rng, traits);
|
||||
|
||||
construct_oriented_bounding_box(points, transformation, inverse_transformation, obb_points, traits);
|
||||
}
|
||||
|
||||
template <typename PointRange, typename PolygonMesh, typename Traits>
|
||||
void construct_oriented_bounding_box(const PointRange& points,
|
||||
PolygonMesh& pm,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits,
|
||||
typename boost::disable_if<
|
||||
typename boost::has_range_iterator<PolygonMesh>
|
||||
>::type* = 0)
|
||||
{
|
||||
typename Traits::Aff_transformation_3 transformation, inverse_transformation;
|
||||
compute_best_transformation(points, transformation, inverse_transformation, rng, traits);
|
||||
|
||||
std::array<typename Traits::Point_3, 8> obb_points;
|
||||
construct_oriented_bounding_box(points, transformation, inverse_transformation, obb_points, traits);
|
||||
|
||||
CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3],
|
||||
obb_points[4], obb_points[5], obb_points[6], obb_points[7], pm);
|
||||
}
|
||||
|
||||
// Entry point, decide whether to compute the CH_3 or not
|
||||
template <typename PointRange, typename Output, typename Traits>
|
||||
void construct_oriented_bounding_box(const PointRange& points,
|
||||
const bool use_ch,
|
||||
Output& output,
|
||||
CGAL::Random& rng,
|
||||
const Traits& traits)
|
||||
{
|
||||
typedef typename Traits::Point_3 Point;
|
||||
|
||||
CGAL_static_assertion((std::is_same<typename boost::range_value<PointRange>::type, Point>::value));
|
||||
|
||||
if(use_ch) // construct the convex hull to reduce the number of points
|
||||
{
|
||||
std::vector<Point> ch_points;
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
CGAL::Real_timer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
CGAL::Convex_hull_traits_3<Traits> CH_traits;
|
||||
extreme_points_3(points, std::back_inserter(ch_points), CH_traits);
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
|
||||
std::cout << "CH time: " << timer.time() << std::endl;
|
||||
#endif
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
|
||||
std::cout << ch_points.size() << " points on the convex hull" << std::endl;
|
||||
#endif
|
||||
|
||||
return construct_oriented_bounding_box(ch_points, output, rng, traits);
|
||||
}
|
||||
else
|
||||
{
|
||||
return construct_oriented_bounding_box(points, output, rng, traits);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Optimal_bounding_box
|
||||
|
||||
/// \addtogroup PkgOptimalBoundingBox_Oriented_bounding_box
|
||||
///
|
||||
/// The function `oriented_bounding_box` computes an approximation of the <i>optimal bounding box</i>,
|
||||
/// which is defined as the rectangular box with smallest volume of all the rectangular boxes containing
|
||||
/// the input points.
|
||||
///
|
||||
/// Internally, the algorithm uses an optimization process to compute a transformation (rotation)
|
||||
/// \f$ {\mathcal R}_b\f$ such that the axis-aligned box of the rotated input point set
|
||||
/// has a volume that is as small as possible given a fixed maximal number of optimization iterations.
|
||||
///
|
||||
/// \cgalHeading{Input}
|
||||
///
|
||||
/// The input can be either a range of 3D points, or a polygon mesh.
|
||||
///
|
||||
/// \cgalHeading{Output}
|
||||
///
|
||||
/// The result of the algorithm can be retrieved as either:
|
||||
/// - the best affine transformation \f${\mathcal R}_b\f$ that the algorithm has found;
|
||||
/// - an array of eight points, representing the best oriented bounding box (\f${\mathcal B}_b\f$)
|
||||
/// that the algorithm has constructed, which is related to \f$ {\mathcal R}_b\f$ as it is
|
||||
/// the inverse transformation of the axis-aligned bounding box of the transformed point set.
|
||||
/// The order of the points in the array is the same as in the function
|
||||
/// \link PkgBGLHelperFct `CGAL::make_hexahedron()` \endlink,
|
||||
/// which can be used to construct a mesh from these points.
|
||||
/// - a model of `MutableFaceGraph`
|
||||
///
|
||||
/// Note that when returning an array of points, these points are constructed from the axis-aligned
|
||||
/// bounding box and some precision loss should therefore be expected if a kernel not providing
|
||||
/// exact constructions is used.
|
||||
///
|
||||
/// The algorithm is based on a paper by Chang, Gorissen, and Melchior \cgalCite{cgal:cgm-fobbo-11}.
|
||||
|
||||
/// \ingroup PkgOptimalBoundingBox_Oriented_bounding_box
|
||||
///
|
||||
/// The function `oriented_bounding_box` computes an approximation of the <i>optimal bounding box</i>,
|
||||
/// which is defined as the rectangular box with smallest volume of all the rectangular boxes containing
|
||||
/// the input points.
|
||||
///
|
||||
/// See \ref PkgOptimalBoundingBox_Oriented_bounding_box for more information.
|
||||
///
|
||||
/// \tparam PointRange a model of `Range`. The value type may not be equal to the type `%Point_3` of the traits class
|
||||
/// if a point map is provided via named parameters (see below) to access points.
|
||||
/// \tparam Output either the type `Aff_transformation_3` of the traits class,
|
||||
/// or `std::array<Point, 8>` with `Point` being equivalent to the type `%Point_3` of the traits class,
|
||||
/// or a model of `MutableFaceGraph`
|
||||
/// \tparam NamedParameters a sequence of \ref obb_namedparameters "Named Parameters"
|
||||
///
|
||||
/// \param points the input range
|
||||
/// \param out the resulting array of points or affine transformation
|
||||
/// \param np an optional sequence of \ref obb_namedparameters "Named Parameters" among the ones listed below:
|
||||
///
|
||||
/// \cgalNamedParamsBegin
|
||||
/// \cgalParamBegin{point_map}
|
||||
/// a model of `ReadablePropertyMap` with value type the type `%Point_3` of the traits class.
|
||||
/// If this parameter is omitted, `CGAL::Identity_property_map<%Point_3>` is used.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits}
|
||||
/// a geometric traits class instance, model of the concept `OrientedBoundingBoxTraits_3`.
|
||||
/// %Default is a default construction object of type `CGAL::Oriented_bounding_box_traits_3<K>`
|
||||
/// where `K` is a kernel type deduced from the point type.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{use_convex_hull}
|
||||
/// a Boolean value to indicate whether the algorithm should first extract the so-called extreme
|
||||
/// points of the data range (i.e. construct the convex hull) to reduce the input data range
|
||||
/// and accelerate the algorithm. %Default is `true`.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
template <typename PointRange,
|
||||
typename Output,
|
||||
typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
void oriented_bounding_box(const PointRange& points,
|
||||
Output& out,
|
||||
const CGAL_BGL_NP_CLASS& np
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, typename boost::enable_if<
|
||||
typename boost::has_range_iterator<PointRange>
|
||||
>::type* = 0
|
||||
#endif
|
||||
)
|
||||
{
|
||||
using CGAL::parameters::choose_parameter;
|
||||
using CGAL::parameters::get_parameter;
|
||||
|
||||
typedef typename CGAL::GetPointMap<PointRange, CGAL_BGL_NP_CLASS>::type PointMap;
|
||||
|
||||
#if defined(CGAL_EIGEN3_ENABLED)
|
||||
typedef typename boost::property_traits<PointMap>::value_type Point;
|
||||
typedef typename CGAL::Kernel_traits<Point>::type K;
|
||||
typedef Oriented_bounding_box_traits_3<K> Default_traits;
|
||||
#else
|
||||
typedef void Default_traits;
|
||||
#endif
|
||||
|
||||
typedef typename internal_np::Lookup_named_param_def<internal_np::geom_traits_t,
|
||||
CGAL_BGL_NP_CLASS,
|
||||
Default_traits>::type Geom_traits;
|
||||
|
||||
CGAL_static_assertion_msg(!(std::is_same<Geom_traits, void>::value),
|
||||
"You must provide a traits class or have Eigen enabled!");
|
||||
|
||||
Geom_traits traits = choose_parameter<Geom_traits>(get_parameter(np, internal_np::geom_traits));
|
||||
PointMap point_map = choose_parameter<PointMap>(get_parameter(np, internal_np::point_map));
|
||||
|
||||
const bool use_ch = choose_parameter(get_parameter(np, internal_np::use_convex_hull), true);
|
||||
const unsigned int seed = choose_parameter(get_parameter(np, internal_np::random_seed), -1); // undocumented
|
||||
|
||||
CGAL::Random fixed_seed_rng(seed);
|
||||
CGAL::Random& rng = (seed == unsigned(-1)) ? CGAL::get_default_random() : fixed_seed_rng;
|
||||
|
||||
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
|
||||
std::cout << "Random seed: " << rng.get_seed() << std::endl;
|
||||
#endif
|
||||
|
||||
// @todo handle those cases (or call min_rectangle_2 with a projection)
|
||||
if(points.size() <= 3)
|
||||
{
|
||||
std::cerr << "The oriented bounding box cannot (yet) be computed for a mesh with fewer than 4 vertices!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
return Optimal_bounding_box::internal::construct_oriented_bounding_box(
|
||||
CGAL::make_range(
|
||||
boost::make_transform_iterator(points.begin(), CGAL::Property_map_to_unary_function<PointMap>(point_map)),
|
||||
boost::make_transform_iterator(points.end(), CGAL::Property_map_to_unary_function<PointMap>(point_map))),
|
||||
use_ch, out, rng, traits);
|
||||
}
|
||||
|
||||
/// \ingroup PkgOptimalBoundingBox_Oriented_bounding_box
|
||||
///
|
||||
/// Extracts the vertices of the mesh as a point range and calls the overload using points as input.
|
||||
///
|
||||
/// \tparam PolygonMesh a model of `VertexListGraph`
|
||||
/// \tparam Output either the type `Aff_transformation_3` of the traits class,
|
||||
/// or `std::array<Point, 8>` with `Point` being equivalent to the type `%Point_3` of the traits class,
|
||||
/// or a model of `MutableFaceGraph`
|
||||
/// \tparam NamedParameters a sequence of \ref obb_namedparameters "Named Parameters"
|
||||
///
|
||||
/// \param pmesh the input mesh
|
||||
/// \param out the resulting array of points or affine transformation
|
||||
/// \param np an optional sequence of \ref obb_namedparameters "Named Parameters" 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 `PolygonMesh`.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{geom_traits}
|
||||
/// a geometric traits class instance, model of the concept `OrientedBoundingBoxTraits_3`.
|
||||
/// %Default is a default construction object of type `CGAL::Oriented_bounding_box_traits_3<K>`
|
||||
/// where `K` is a kernel type deduced from the point type.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalParamBegin{use_convex_hull}
|
||||
/// a Boolean value to indicate whether the algorithm should first extract the so-called extreme
|
||||
/// points of the data range (i.e. construct the convex hull) to reduce the input data range
|
||||
/// and accelerate the algorithm. %Default is `true`.
|
||||
/// \cgalParamEnd
|
||||
/// \cgalNamedParamsEnd
|
||||
///
|
||||
template <typename PolygonMesh,
|
||||
typename Output,
|
||||
typename CGAL_BGL_NP_TEMPLATE_PARAMETERS>
|
||||
void oriented_bounding_box(const PolygonMesh& pmesh,
|
||||
Output& out,
|
||||
const CGAL_BGL_NP_CLASS& np
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
, typename boost::disable_if<
|
||||
typename boost::has_range_iterator<PolygonMesh>
|
||||
>::type* = 0
|
||||
#endif
|
||||
)
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
using CGAL::parameters::choose_parameter;
|
||||
using CGAL::parameters::get_parameter;
|
||||
|
||||
typedef typename CGAL::GetVertexPointMap<PolygonMesh, CGAL_BGL_NP_CLASS>::const_type VPM;
|
||||
|
||||
VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point),
|
||||
get_const_property_map(vertex_point, pmesh));
|
||||
|
||||
oriented_bounding_box(vertices(pmesh), out, np.point_map(vpm));
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Convenience overloads
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Input /*range or mesh*/, typename Output /*transformation, array, or mesh*/>
|
||||
void oriented_bounding_box(const Input& in, Output& out)
|
||||
{
|
||||
return oriented_bounding_box(in, out, CGAL::parameters::all_default());
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
} // end namespace CGAL
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_ORIENTED_BOUNDING_BOX_H
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2018-2019 GeometryFactory (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
//
|
||||
// Author(s) : Konstantinos Katrioplas
|
||||
// Mael Rouxel-Labbé
|
||||
//
|
||||
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_OBB_H
|
||||
#define CGAL_OPTIMAL_BOUNDING_BOX_OBB_H
|
||||
|
||||
#ifndef DOXYGEN_RUNNING
|
||||
#include <CGAL/license/Optimal_bounding_box.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \ingroup PkgOptimalBoundingBoxRef
|
||||
* \file CGAL/optimal_bounding_box.h
|
||||
* Convenience header file including the headers for all the classes and functions of this package.
|
||||
*/
|
||||
|
||||
#include <CGAL/Optimal_bounding_box/Oriented_bounding_box_traits_3.h>
|
||||
#include <CGAL/Optimal_bounding_box/oriented_bounding_box.h>
|
||||
|
||||
#endif // CGAL_OPTIMAL_BOUNDING_BOX_OBB_H
|
||||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory (France)
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
Algebraic_foundations
|
||||
Arithmetic_kernel
|
||||
BGL
|
||||
Bounding_volumes
|
||||
Cartesian_kernel
|
||||
Circulator
|
||||
Convex_hull_2
|
||||
Convex_hull_3
|
||||
Distance_2
|
||||
Distance_3
|
||||
Filtered_kernel
|
||||
Hash_map
|
||||
Homogeneous_kernel
|
||||
Installation
|
||||
Intersections_2
|
||||
Intersections_3
|
||||
Interval_support
|
||||
Kernel_23
|
||||
Kernel_d
|
||||
Modular_arithmetic
|
||||
Number_types
|
||||
Optimal_bounding_box
|
||||
Optimisation_basic
|
||||
Polygon
|
||||
Profiling_tools
|
||||
Property_map
|
||||
Random_numbers
|
||||
STL_Extension
|
||||
Solver_interface
|
||||
Stream_support
|
||||
TDS_2
|
||||
Triangulation_2
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -0,0 +1 @@
|
|||
GeometryFactory
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Created by the script cgal_create_CMakeLists
|
||||
# This is the CMake script for compiling a set of CGAL applications.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1...3.15)
|
||||
project( Optimal_bounding_box_Tests )
|
||||
|
||||
find_package(CGAL QUIET)
|
||||
|
||||
if (NOT CGAL_FOUND)
|
||||
message(STATUS "This project requires the CGAL library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
include( ${CGAL_USE_FILE} )
|
||||
|
||||
find_package(Eigen3 3.1.0 REQUIRED) #(3.1.0 or greater)
|
||||
if (NOT EIGEN3_FOUND)
|
||||
message(STATUS "This project requires the Eigen library, and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
create_single_source_cgal_program("test_OBB_traits.cpp")
|
||||
create_single_source_cgal_program("test_nelder_mead.cpp")
|
||||
create_single_source_cgal_program("test_optimization_algorithms.cpp")
|
||||
|
||||
foreach(target
|
||||
test_OBB_traits
|
||||
test_nelder_mead
|
||||
test_optimization_algorithms)
|
||||
CGAL_target_use_Eigen(${target})
|
||||
endforeach()
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,323 @@
|
|||
OFF
|
||||
121 200 0
|
||||
0 0 0
|
||||
0.10000000000000001 0 0
|
||||
0.20000000000000001 0 0
|
||||
0.29999999999999999 0 0
|
||||
0.40000000000000002 0 0
|
||||
0.5 0 0
|
||||
0.59999999999999998 0 0
|
||||
0.69999999999999996 0 0
|
||||
0.80000000000000004 0 0
|
||||
0.90000000000000002 0 0
|
||||
1 0 0
|
||||
0 0.10000000000000001 0.10000000000000001
|
||||
0.10000000000000001 0.10000000000000001 0.10000000000000001
|
||||
0.20000000000000001 0.10000000000000001 0.10000000000000001
|
||||
0.29999999999999999 0.10000000000000001 0.10000000000000001
|
||||
0.40000000000000002 0.10000000000000001 0.10000000000000001
|
||||
0.5 0.10000000000000001 0.10000000000000001
|
||||
0.59999999999999998 0.10000000000000001 0.10000000000000001
|
||||
0.69999999999999996 0.10000000000000001 0.10000000000000001
|
||||
0.80000000000000004 0.10000000000000001 0.10000000000000001
|
||||
0.90000000000000002 0.10000000000000001 0.10000000000000001
|
||||
1 0.10000000000000001 0.10000000000000001
|
||||
0 0.20000000000000001 0.20000000000000001
|
||||
0.10000000000000001 0.20000000000000001 0.20000000000000001
|
||||
0.20000000000000001 0.20000000000000001 0.20000000000000001
|
||||
0.29999999999999999 0.20000000000000001 0.20000000000000001
|
||||
0.40000000000000002 0.20000000000000001 0.20000000000000001
|
||||
0.5 0.20000000000000001 0.20000000000000001
|
||||
0.59999999999999998 0.20000000000000001 0.20000000000000001
|
||||
0.69999999999999996 0.20000000000000001 0.20000000000000001
|
||||
0.80000000000000004 0.20000000000000001 0.20000000000000001
|
||||
0.90000000000000002 0.20000000000000001 0.20000000000000001
|
||||
1 0.20000000000000001 0.20000000000000001
|
||||
0 0.29999999999999999 0.29999999999999999
|
||||
0.10000000000000001 0.29999999999999999 0.29999999999999999
|
||||
0.20000000000000001 0.29999999999999999 0.29999999999999999
|
||||
0.29999999999999999 0.29999999999999999 0.29999999999999999
|
||||
0.40000000000000002 0.29999999999999999 0.29999999999999999
|
||||
0.5 0.29999999999999999 0.29999999999999999
|
||||
0.59999999999999998 0.29999999999999999 0.29999999999999999
|
||||
0.69999999999999996 0.29999999999999999 0.29999999999999999
|
||||
0.80000000000000004 0.29999999999999999 0.29999999999999999
|
||||
0.90000000000000002 0.29999999999999999 0.29999999999999999
|
||||
1 0.29999999999999999 0.29999999999999999
|
||||
0 0.40000000000000002 0.40000000000000002
|
||||
0.10000000000000001 0.40000000000000002 0.40000000000000002
|
||||
0.20000000000000001 0.40000000000000002 0.40000000000000002
|
||||
0.29999999999999999 0.40000000000000002 0.40000000000000002
|
||||
0.40000000000000002 0.40000000000000002 0.40000000000000002
|
||||
0.5 0.40000000000000002 0.40000000000000002
|
||||
0.59999999999999998 0.40000000000000002 0.40000000000000002
|
||||
0.69999999999999996 0.40000000000000002 0.40000000000000002
|
||||
0.80000000000000004 0.40000000000000002 0.40000000000000002
|
||||
0.90000000000000002 0.40000000000000002 0.40000000000000002
|
||||
1 0.40000000000000002 0.40000000000000002
|
||||
0 0.5 0.5
|
||||
0.10000000000000001 0.5 0.5
|
||||
0.20000000000000001 0.5 0.5
|
||||
0.29999999999999999 0.5 0.5
|
||||
0.40000000000000002 0.5 0.5
|
||||
0.5 0.5 0.5
|
||||
0.59999999999999998 0.5 0.5
|
||||
0.69999999999999996 0.5 0.5
|
||||
0.80000000000000004 0.5 0.5
|
||||
0.90000000000000002 0.5 0.5
|
||||
1 0.5 0.5
|
||||
0 0.59999999999999998 0.59999999999999998
|
||||
0.10000000000000001 0.59999999999999998 0.59999999999999998
|
||||
0.20000000000000001 0.59999999999999998 0.59999999999999998
|
||||
0.29999999999999999 0.59999999999999998 0.59999999999999998
|
||||
0.40000000000000002 0.59999999999999998 0.59999999999999998
|
||||
0.5 0.59999999999999998 0.59999999999999998
|
||||
0.59999999999999998 0.59999999999999998 0.59999999999999998
|
||||
0.69999999999999996 0.59999999999999998 0.59999999999999998
|
||||
0.80000000000000004 0.59999999999999998 0.59999999999999998
|
||||
0.90000000000000002 0.59999999999999998 0.59999999999999998
|
||||
1 0.59999999999999998 0.59999999999999998
|
||||
0 0.69999999999999996 0.69999999999999996
|
||||
0.10000000000000001 0.69999999999999996 0.69999999999999996
|
||||
0.20000000000000001 0.69999999999999996 0.69999999999999996
|
||||
0.29999999999999999 0.69999999999999996 0.69999999999999996
|
||||
0.40000000000000002 0.69999999999999996 0.69999999999999996
|
||||
0.5 0.69999999999999996 0.69999999999999996
|
||||
0.59999999999999998 0.69999999999999996 0.69999999999999996
|
||||
0.69999999999999996 0.69999999999999996 0.69999999999999996
|
||||
0.80000000000000004 0.69999999999999996 0.69999999999999996
|
||||
0.90000000000000002 0.69999999999999996 0.69999999999999996
|
||||
1 0.69999999999999996 0.69999999999999996
|
||||
0 0.80000000000000004 0.80000000000000004
|
||||
0.10000000000000001 0.80000000000000004 0.80000000000000004
|
||||
0.20000000000000001 0.80000000000000004 0.80000000000000004
|
||||
0.29999999999999999 0.80000000000000004 0.80000000000000004
|
||||
0.40000000000000002 0.80000000000000004 0.80000000000000004
|
||||
0.5 0.80000000000000004 0.80000000000000004
|
||||
0.59999999999999998 0.80000000000000004 0.80000000000000004
|
||||
0.69999999999999996 0.80000000000000004 0.80000000000000004
|
||||
0.80000000000000004 0.80000000000000004 0.80000000000000004
|
||||
0.90000000000000002 0.80000000000000004 0.80000000000000004
|
||||
1 0.80000000000000004 0.80000000000000004
|
||||
0 0.90000000000000002 0.90000000000000002
|
||||
0.10000000000000001 0.90000000000000002 0.90000000000000002
|
||||
0.20000000000000001 0.90000000000000002 0.90000000000000002
|
||||
0.29999999999999999 0.90000000000000002 0.90000000000000002
|
||||
0.40000000000000002 0.90000000000000002 0.90000000000000002
|
||||
0.5 0.90000000000000002 0.90000000000000002
|
||||
0.59999999999999998 0.90000000000000002 0.90000000000000002
|
||||
0.69999999999999996 0.90000000000000002 0.90000000000000002
|
||||
0.80000000000000004 0.90000000000000002 0.90000000000000002
|
||||
0.90000000000000002 0.90000000000000002 0.90000000000000002
|
||||
1 0.90000000000000002 0.90000000000000002
|
||||
0 1 1
|
||||
0.10000000000000001 1 1
|
||||
0.20000000000000001 1 1
|
||||
0.29999999999999999 1 1
|
||||
0.40000000000000002 1 1
|
||||
0.5 1 1
|
||||
0.59999999999999998 1 1
|
||||
0.69999999999999996 1 1
|
||||
0.80000000000000004 1 1
|
||||
0.90000000000000002 1 1
|
||||
1 1 1
|
||||
3 0 1 11
|
||||
3 1 12 11
|
||||
3 11 12 22
|
||||
3 12 23 22
|
||||
3 22 23 33
|
||||
3 23 34 33
|
||||
3 33 34 44
|
||||
3 34 45 44
|
||||
3 44 45 55
|
||||
3 45 56 55
|
||||
3 55 56 66
|
||||
3 56 67 66
|
||||
3 66 67 77
|
||||
3 67 78 77
|
||||
3 77 78 88
|
||||
3 78 89 88
|
||||
3 88 89 99
|
||||
3 89 100 99
|
||||
3 99 100 110
|
||||
3 100 111 110
|
||||
3 1 2 12
|
||||
3 2 13 12
|
||||
3 12 13 23
|
||||
3 13 24 23
|
||||
3 23 24 34
|
||||
3 24 35 34
|
||||
3 34 35 45
|
||||
3 35 46 45
|
||||
3 45 46 56
|
||||
3 46 57 56
|
||||
3 56 57 67
|
||||
3 57 68 67
|
||||
3 67 68 78
|
||||
3 68 79 78
|
||||
3 78 79 89
|
||||
3 79 90 89
|
||||
3 89 90 100
|
||||
3 90 101 100
|
||||
3 100 101 111
|
||||
3 101 112 111
|
||||
3 2 3 13
|
||||
3 3 14 13
|
||||
3 13 14 24
|
||||
3 14 25 24
|
||||
3 24 25 35
|
||||
3 25 36 35
|
||||
3 35 36 46
|
||||
3 36 47 46
|
||||
3 46 47 57
|
||||
3 47 58 57
|
||||
3 57 58 68
|
||||
3 58 69 68
|
||||
3 68 69 79
|
||||
3 69 80 79
|
||||
3 79 80 90
|
||||
3 80 91 90
|
||||
3 90 91 101
|
||||
3 91 102 101
|
||||
3 101 102 112
|
||||
3 102 113 112
|
||||
3 3 4 14
|
||||
3 4 15 14
|
||||
3 14 15 25
|
||||
3 15 26 25
|
||||
3 25 26 36
|
||||
3 26 37 36
|
||||
3 36 37 47
|
||||
3 37 48 47
|
||||
3 47 48 58
|
||||
3 48 59 58
|
||||
3 58 59 69
|
||||
3 59 70 69
|
||||
3 69 70 80
|
||||
3 70 81 80
|
||||
3 80 81 91
|
||||
3 81 92 91
|
||||
3 91 92 102
|
||||
3 92 103 102
|
||||
3 102 103 113
|
||||
3 103 114 113
|
||||
3 4 5 15
|
||||
3 5 16 15
|
||||
3 15 16 26
|
||||
3 16 27 26
|
||||
3 26 27 37
|
||||
3 27 38 37
|
||||
3 37 38 48
|
||||
3 38 49 48
|
||||
3 48 49 59
|
||||
3 49 60 59
|
||||
3 59 60 70
|
||||
3 60 71 70
|
||||
3 70 71 81
|
||||
3 71 82 81
|
||||
3 81 82 92
|
||||
3 82 93 92
|
||||
3 92 93 103
|
||||
3 93 104 103
|
||||
3 103 104 114
|
||||
3 104 115 114
|
||||
3 5 6 16
|
||||
3 6 17 16
|
||||
3 16 17 27
|
||||
3 17 28 27
|
||||
3 27 28 38
|
||||
3 28 39 38
|
||||
3 38 39 49
|
||||
3 39 50 49
|
||||
3 49 50 60
|
||||
3 50 61 60
|
||||
3 60 61 71
|
||||
3 61 72 71
|
||||
3 71 72 82
|
||||
3 72 83 82
|
||||
3 82 83 93
|
||||
3 83 94 93
|
||||
3 93 94 104
|
||||
3 94 105 104
|
||||
3 104 105 115
|
||||
3 105 116 115
|
||||
3 6 7 17
|
||||
3 7 18 17
|
||||
3 17 18 28
|
||||
3 18 29 28
|
||||
3 28 29 39
|
||||
3 29 40 39
|
||||
3 39 40 50
|
||||
3 40 51 50
|
||||
3 50 51 61
|
||||
3 51 62 61
|
||||
3 61 62 72
|
||||
3 62 73 72
|
||||
3 72 73 83
|
||||
3 73 84 83
|
||||
3 83 84 94
|
||||
3 84 95 94
|
||||
3 94 95 105
|
||||
3 95 106 105
|
||||
3 105 106 116
|
||||
3 106 117 116
|
||||
3 7 8 18
|
||||
3 8 19 18
|
||||
3 18 19 29
|
||||
3 19 30 29
|
||||
3 29 30 40
|
||||
3 30 41 40
|
||||
3 40 41 51
|
||||
3 41 52 51
|
||||
3 51 52 62
|
||||
3 52 63 62
|
||||
3 62 63 73
|
||||
3 63 74 73
|
||||
3 73 74 84
|
||||
3 74 85 84
|
||||
3 84 85 95
|
||||
3 85 96 95
|
||||
3 95 96 106
|
||||
3 96 107 106
|
||||
3 106 107 117
|
||||
3 107 118 117
|
||||
3 8 9 19
|
||||
3 9 20 19
|
||||
3 19 20 30
|
||||
3 20 31 30
|
||||
3 30 31 41
|
||||
3 31 42 41
|
||||
3 41 42 52
|
||||
3 42 53 52
|
||||
3 52 53 63
|
||||
3 53 64 63
|
||||
3 63 64 74
|
||||
3 64 75 74
|
||||
3 74 75 85
|
||||
3 75 86 85
|
||||
3 85 86 96
|
||||
3 86 97 96
|
||||
3 96 97 107
|
||||
3 97 108 107
|
||||
3 107 108 118
|
||||
3 108 119 118
|
||||
3 9 10 20
|
||||
3 10 21 20
|
||||
3 20 21 31
|
||||
3 21 32 31
|
||||
3 31 32 42
|
||||
3 32 43 42
|
||||
3 42 43 53
|
||||
3 43 54 53
|
||||
3 53 54 64
|
||||
3 54 65 64
|
||||
3 64 65 75
|
||||
3 65 76 75
|
||||
3 75 76 86
|
||||
3 76 87 86
|
||||
3 86 87 97
|
||||
3 87 98 97
|
||||
3 97 98 108
|
||||
3 98 109 108
|
||||
3 108 109 119
|
||||
3 109 120 119
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
OFF
|
||||
4 4 0
|
||||
|
||||
-1 -0.1 0
|
||||
-1 0.1 0
|
||||
1 0 -0.1
|
||||
1 0 0.1
|
||||
3 0 1 2
|
||||
3 2 3 0
|
||||
3 1 3 2
|
||||
3 0 3 1
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
413065776.152494 326396843.840397 326457757.911644
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
0 0 0
|
||||
0 1 2
|
||||
0 2 4
|
||||
0 3 6
|
||||
0 10 20
|
||||
0 0.5 1
|
||||
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
413065776.152494 326396843.840397 0
|
||||
413057847.377906 326403660.329056 0
|
||||
413052569.655378 326399341.810968 0
|
||||
412964155.996695 326429557.407149 0
|
||||
412960887.449993 326443760.793625 0
|
||||
412939753.084117 326436727.039421 0
|
||||
412939894.318992 326428463.667967 0
|
||||
412947664.119328 326419882.748586 0
|
||||
412970476.46515 326451966.912356 0
|
||||
412968925.050862 326458160.301721 0
|
||||
412963543.512664 326454495.012767 0
|
||||
412985746.970294 326424302.733302 0
|
||||
412983665.865636 326410836.59751 0
|
||||
412996088.235308 326419469.954289 0
|
||||
412998096.793163 326423084.180324 0
|
||||
413003418.285576 326419809.050109 0
|
||||
413002038.294065 326427600.699796 0
|
||||
412945313.935335 326454359.672656 0
|
||||
412943663.154485 326452834.040025 0
|
||||
412952251.09554 326452986.901051 0
|
||||
412950732.333508 326457757.911644 0
|
||||
412943971.574173 326459149.099198 0
|
||||
412934361.648126 326445041.605944 0
|
||||
412936751.268924 326454822.208572 0
|
||||
412964758.701994 326486192.337374 0
|
||||
412966490.855253 326478259.235383 0
|
||||
412973194.081713 326482046.898235 0
|
||||
412950650.516328 326468707.808723 0
|
||||
412957725.270744 326476103.847023 0
|
||||
412950026.231257 326477412.439015 0
|
||||
412988174.944206 326470661.339091 0
|
||||
412986909.075808 326462858.270384 0
|
||||
413000669.61306 326456348.730054 0
|
||||
412966234.090172 326488146.292068 0
|
||||
413023232.123734 326461197.560115 0
|
||||
413023550.270655 326471002.013297 0
|
||||
413016185.260894 326465438.977186 0
|
||||
412987141.775588 326489693.339605 0
|
||||
412982918.043107 326488237.152808 0
|
||||
412985980.280763 326483135.425286 0
|
||||
413001196.353514 326479715.175257 0
|
||||
413008202.547705 326474962.703983 0
|
||||
413003755.131316 326481400.115507 0
|
||||
412929683.198695 326465491.420262 0
|
||||
412920189.499339 326451860.04878 0
|
||||
412931611.507502 326452533.708517 0
|
||||
412992581.061321 326477132.127848 0
|
||||
412989279.419663 326480089.894799 0
|
||||
412935705.096519 326482202.861555 0
|
||||
412925307.138482 326466637.344135 0
|
||||
413076469.52736 326433412.768228 0
|
||||
413075298.398716 326444763.979995 0
|
||||
413065834.246237 326440647.027719 0
|
||||
413009745.175265 326502212.1638 0
|
||||
413001718.895276 326508920.841833 0
|
||||
413002418.144751 326497753.488837 0
|
||||
413060741.401393 326423820.134531 0
|
||||
413060876.676061 326428728.639701 0
|
||||
413058999.571918 326423687.390799 0
|
||||
413025105.511534 326478606.208507 0
|
||||
413037158.816855 326472407.974956 0
|
||||
413026100.112628 326483530.179333 0
|
||||
413079758.83472 326425207.53598 0
|
||||
413076210.923893 326422944.976439 0
|
||||
413078151.988242 326416248.664714 0
|
||||
413053952.794291 326463144.972745 0
|
||||
413055684.722689 326475529.630202 0
|
||||
413045099.788495 326474825.69738 0
|
||||
413062042.967186 326437063.922844 0
|
||||
413066790.302583 326430817.2269 0
|
||||
413004709.107113 326490135.418709 0
|
||||
413005093.685865 326489983.127837 0
|
||||
413098251.972367 326408565.921651 0
|
||||
413098367.233587 326415127.45218 0
|
||||
413097944.35044 326413442.449707 0
|
||||
413070518.763323 326460355.49692 0
|
||||
413066193.752266 326467461.946737 0
|
||||
413087099.80728 326418237.162439 0
|
||||
412932643.127595 326424163.465682 0
|
||||
412947239.568275 326415586.45517 0
|
||||
412929877.917135 326420120.542778 0
|
||||
413010920.918128 326399072.312299 0
|
||||
412915060.825449 326423803.643013 0
|
||||
412963212.559984 326417484.293606 0
|
||||
412974527.414159 326428576.196833 0
|
||||
412992373.377627 326455620.014196 0
|
||||
413010074.272151 326418465.382469 0
|
||||
413011850.753162 326417002.217271 0
|
||||
413014406.991439 326420203.661922 0
|
||||
412977637.839421 326432544.829395 0
|
||||
412986148.487405 326429359.611152 0
|
||||
412995280.156846 326431026.989975 0
|
||||
412990626.28213 326425374.845568 0
|
||||
413032797.62091 326426191.034153 0
|
||||
413029970.570148 326419936.329868 0
|
||||
413044681.544615 326417464.080029 0
|
||||
412999129.25698 326438072.80725 0
|
||||
413007734.056563 326423851.649794 0
|
||||
413016471.93654 326426364.913717 0
|
||||
412968431.452864 326491828.041548 0
|
||||
412958675.073533 326494006.076801 0
|
||||
413012148.256747 326487804.579704 0
|
||||
413016405.832048 326480671.32311 0
|
||||
412975768.001435 326448708.020146 0
|
||||
412979720.162501 326436886.822391 0
|
||||
412982917.886679 326443564.393356 0
|
||||
412988678.510158 326449487.248631 0
|
||||
412985417.106869 326452678.469145 0
|
||||
412971510.871442 326435116.950769 0
|
||||
412983109.808175 326457244.32078 0
|
||||
412957466.876904 326451325.256978 0
|
||||
412959384.40943 326448781.181773 0
|
||||
412966768.138142 326473363.04219 0
|
||||
412971910.952526 326476870.046921 0
|
||||
412963392.569735 326463111.127056 0
|
||||
412924771.98365 326432849.602577 0
|
||||
412917475.177804 326429370.043518 0
|
||||
412911569.816167 326425718.742949 0
|
||||
412924489.589924 326449937.575511 0
|
||||
412956933.247292 326455774.007997 0
|
||||
412955340.545694 326460219.517522 0
|
||||
412977018.754996 326466258.738995 0
|
||||
412970686.301222 326466481.954067 0
|
||||
412978255.629151 326461355.571957 0
|
||||
412939153.439846 326465339.238827 0
|
||||
412923821.154719 326426918.928828 0
|
||||
412975936.409656 326502806.20831 0
|
||||
412963303.14509 326498679.785427 0
|
||||
412969138.482087 326493922.342246 0
|
||||
412956467.21651 326489106.767098 0
|
||||
412959578.052441 326480365.162202 0
|
||||
412977352.621415 326497109.261795 0
|
||||
412941422.08486 326477143.510512 0
|
||||
412936831.795868 326467205.375027 0
|
||||
412961266.195768 326503954.723704 0
|
||||
412958703.392685 326524881.814902 0
|
||||
412953249.527674 326518460.235631 0
|
||||
412935010.36184 326494112.455851 0
|
||||
412931570.65415 326484602.04937 0
|
||||
412985374.324569 326513222.867276 0
|
||||
412978227.727596 326510871.926542 0
|
||||
412984173.754694 326502503.840454 0
|
||||
412985688.206537 326494576.776311 0
|
||||
412978009.820415 326492658.751496 0
|
||||
412993618.008235 326491281.852681 0
|
||||
412997947.150272 326492521.079555 0
|
||||
412976873.960635 326486185.606476 0
|
||||
412981478.037092 326484421.347501 0
|
||||
412980418.065914 326478321.690068 0
|
||||
412979438.184438 326473334.846215 0
|
||||
413010215.690383 326443409.550491 0
|
||||
413008228.44707 326458894.052728 0
|
||||
413035617.465636 326446767.558378 0
|
||||
413027230.055638 326446990.503477 0
|
||||
413030854.849802 326440245.461135 0
|
||||
412979140.451061 326454242.503581 0
|
||||
412985468.6174 326450604.80651 0
|
||||
413015771.02389 326453064.045201 0
|
||||
413021991.755036 326445142.840934 0
|
||||
413008006.052746 326469763.695134 0
|
||||
413048901.884808 326422501.5037 0
|
||||
413045028.78386 326426372.15428 0
|
||||
413005007.536883 326484301.633515 0
|
||||
413002785.535959 326490180.214403 0
|
||||
413014109.69202 326461894.536067 0
|
||||
413017207.888265 326470063.830947 0
|
||||
413045293.513014 326449673.312107 0
|
||||
413044019.75301 326447988.572283 0
|
||||
413047003.614678 326443105.313308 0
|
||||
412999003.436139 326487344.001445 0
|
||||
412996651.65689 326491134.958733 0
|
||||
413012316.245006 326479912.254408 0
|
||||
413012587.728747 326484153.816803 0
|
||||
413016871.37429 326476971.655283 0
|
||||
413019842.625853 326474794.530385 0
|
||||
413039469.406178 326437529.843339 0
|
||||
413041502.67459 326485107.978727 0
|
||||
413036035.620497 326461314.614016 0
|
||||
413031490.325583 326456799.67237 0
|
||||
413020789.72965 326452093.515847 0
|
||||
413020692.119972 326434154.560939 0
|
||||
413029690.023638 326438011.408021 0
|
||||
413043486.972873 326454746.798277 0
|
||||
413033511.062177 326430679.751046 0
|
||||
413067488.089213 326425961.293338 0
|
||||
413083753.259443 326426175.344791 0
|
||||
413067460.916052 326410232.697374 0
|
||||
413068622.531383 326416317.705612 0
|
||||
413061037.102135 326415163.721378 0
|
||||
413071143.181797 326424762.764848 0
|
||||
413060387.108431 326414188.28851 0
|
||||
413060445.58895 326451275.748613 0
|
||||
413036317.30909 326431883.117032 0
|
||||
413045873.300553 326435644.793299 0
|
||||
413048794.267495 326389319.436376 0
|
||||
413030291.769546 326411368.835099 0
|
||||
413024488.398109 326415338.686016 0
|
||||
413021905.956926 326410737.878939 0
|
||||
413027639.836779 326415641.265719 0
|
||||
413017857.083999 326417952.301599 0
|
||||
413029827.400431 326406821.764259 0
|
||||
413001443.929946 326407150.378482 0
|
||||
413036041.452869 326405791.758584 0
|
||||
413033454.48341 326399656.242176 0
|
||||
413018633.129927 326413338.952301 0
|
||||
413045368.965357 326402337.610635 0
|
||||
413048447.394379 326395169.908511 0
|
||||
412986849.902761 326405367.534053 0
|
||||
413065081.744554 326401671.778183 0
|
||||
413092397.837156 326422086.08121 0
|
||||
413095318.341189 326412788.599152 0
|
||||
413093695.254875 326400330.203004 0
|
||||
413099020.077932 326406314.05352 0
|
||||
413093140.218869 326403110.903958 0
|
||||
413056121.776141 326406403.684953 0
|
||||
413089620.108842 326414007.091517 0
|
||||
413089387.417624 326419721.87399 0
|
||||
413093404.232693 326395001.998282 0
|
||||
413085896.789345 326396361.60811 0
|
||||
413085454.676931 326391470.731474 0
|
||||
413074508.839395 326394470.397757 0
|
||||
413068350.570434 326395560.501438 0
|
||||
413070143.96055 326386445.935889 0
|
||||
412918858.560132 326434979.970278 0
|
||||
412955394.145789 326449536.682215 0
|
||||
412971144.038673 326433652.368538 0
|
||||
412965073.360409 326439051.77804 0
|
||||
412970981.692447 326409503.990341 0
|
||||
413014840.087809 326404397.988193 0
|
||||
412994018.136075 326445298.914892 0
|
||||
412990097.829467 326437133.362141 0
|
||||
412965842.792609 326448792.291328 0
|
||||
412961763.785867 326445852.010028 0
|
||||
412947255.093497 326463668.462422 0
|
||||
412939952.26946 326466492.382176 0
|
||||
412943709.427436 326472618.681827 0
|
||||
412952246.783422 326483371.121473 0
|
||||
412944807.921928 326491083.247909 0
|
||||
412940579.938471 326495813.432763 0
|
||||
412945630.90436 326501939.425427 0
|
||||
412938409.182245 326503335.780256 0
|
||||
412951371.196888 326498868.583434 0
|
||||
412949313.764109 326504296.763374 0
|
||||
412945558.683443 326510754.714855 0
|
||||
413008766.713556 326484732.391891 0
|
||||
412990390.280433 326484843.195428 0
|
||||
412995165.502732 326483367.864039 0
|
||||
413016256.164946 326494798.780171 0
|
||||
413017224.89391 326461129.632116 0
|
||||
413029625.683716 326471350.776378 0
|
||||
413025019.999494 326476200.095554 0
|
||||
413048766.414482 326435871.77665 0
|
||||
413051725.256746 326438529.947023 0
|
||||
413052007.160945 326422036.946841 0
|
||||
413058067.843268 326435775.445353 0
|
||||
413083660.953967 326393424.812132 0
|
||||
413083336.161107 326400813.355748 0
|
||||
413066349.33981 326419281.508749 0
|
||||
413068090.500382 326410610.12681 0
|
||||
413074241.401196 326404770.242276 0
|
||||
413081317.053152 326414171.97812 0
|
||||
413073381.651167 326406897.136775 0
|
||||
413095766.46998 326387248.540458 0
|
||||
413097047.640536 326395426.23288 0
|
||||
413098209.521961 326406637.959602 0
|
||||
413089554.505615 326388294.334232 0
|
||||
413074403.539056 326415367.945363 0
|
||||
413040020.425247 326411046.731682 0
|
||||
413045679.434506 326406659.04965 0
|
||||
413039095.903129 326409071.668118 0
|
||||
413031306.230818 326393733.283998 0
|
||||
413052303.600823 326400659.626307 0
|
||||
413081695.584061 326380509.699198 0
|
||||
413077541.674433 326389883.685777 0
|
||||
413082416.500748 326382824.511316 0
|
||||
413073027.473224 326382906.090405 0
|
||||
413088349.695199 326383000.125606 0
|
||||
413094911.539918 326387536.877598 0
|
||||
413092119.400999 326388985.514422 0
|
||||
413093374.909798 326384034.886791 0
|
||||
413096500.785907 326395520.129613 0
|
||||
413094014.467295 326377700.363085 0
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
OFF
|
||||
4 4 0
|
||||
|
||||
0 1 0
|
||||
1 0 0
|
||||
0 0 0
|
||||
0 0 1
|
||||
3 0 1 2
|
||||
3 2 3 0
|
||||
3 1 3 2
|
||||
3 0 3 1
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
OFF
|
||||
4 2 0
|
||||
0 0 0
|
||||
1 0 0
|
||||
0 1 0
|
||||
1 1 0
|
||||
3 0 1 2
|
||||
3 2 1 3
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
|
||||
#include <CGAL/assertions.h>
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::FT FT;
|
||||
typedef K::Point_3 Point_3;
|
||||
|
||||
typedef CGAL::Oriented_bounding_box_traits_3<K> Traits;
|
||||
typedef Traits::Matrix Matrix;
|
||||
|
||||
void check_equality(const FT d1, const FT d2)
|
||||
{
|
||||
const FT epsilon = 1e-3;
|
||||
|
||||
bool ok;
|
||||
if(std::is_floating_point<FT>::value)
|
||||
ok = CGAL::abs(d1 - d2) < epsilon * CGAL::abs(d2);
|
||||
else
|
||||
ok = (d1 == d2);
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
std::cout << "Error: got " << d1 << " but expected: " << d2 << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void test_fitness_function(const Traits& traits)
|
||||
{
|
||||
std::array<Point_3, 4> points;
|
||||
points[0] = Point_3(0.866802, 0.740808, 0.895304);
|
||||
points[1] = Point_3(0.912651, 0.761565, 0.160330);
|
||||
points[2] = Point_3(0.093661, 0.892578, 0.737412);
|
||||
points[3] = Point_3(0.166461, 0.149912, 0.364944);
|
||||
|
||||
Matrix rotation;
|
||||
rotation.set(0, 0, -0.809204);
|
||||
rotation.set(0, 1, 0.124296);
|
||||
rotation.set(0, 2, 0.574230);
|
||||
rotation.set(1, 0, -0.574694);
|
||||
rotation.set(1, 1, 0.035719);
|
||||
rotation.set(1, 2, -0.817589);
|
||||
rotation.set(2, 0, -0.122134);
|
||||
rotation.set(2, 1, -0.991602);
|
||||
rotation.set(2, 2, 0.042528);
|
||||
|
||||
const double fitness = CGAL::Optimal_bounding_box::internal::compute_fitness(rotation, points, traits);
|
||||
check_equality(fitness, 0.58606);
|
||||
}
|
||||
|
||||
void test_eigen_matrix_interface()
|
||||
{
|
||||
Matrix A;
|
||||
A.set(0, 0, 0.1);
|
||||
A.set(0, 1, 0.2);
|
||||
A.set(0, 2, 0.3);
|
||||
A.set(1, 0, 0.4);
|
||||
A.set(1, 1, 0.5);
|
||||
A.set(1, 2, 0.6);
|
||||
A.set(2, 0, 0.7);
|
||||
A.set(2, 1, 0.8);
|
||||
A.set(2, 2, 0.9);
|
||||
|
||||
Matrix B;
|
||||
B = CGAL::Optimal_bounding_box::internal::transpose(A);
|
||||
|
||||
Matrix S;
|
||||
S = 0.5 * A;
|
||||
|
||||
Matrix C;
|
||||
C.set(0, 0, 0.3011944);
|
||||
C.set(0, 1, 0.9932761);
|
||||
C.set(0, 2, 0.5483701);
|
||||
C.set(1, 0, 0.5149142);
|
||||
C.set(1, 1, 0.5973263);
|
||||
C.set(1, 2, 0.5162336);
|
||||
C.set(2, 0, 0.0039213);
|
||||
C.set(2, 1, 0.0202949);
|
||||
C.set(2, 2, 0.9240308);
|
||||
|
||||
Matrix Q = Traits::get_Q(C);
|
||||
|
||||
check_equality(Q(0,0), -0.504895);
|
||||
check_equality(Q(0,1), 0.862834);
|
||||
check_equality(Q(0,2), -0.024447);
|
||||
check_equality(Q(1,0), -0.863156);
|
||||
check_equality(Q(1,1), -0.504894);
|
||||
check_equality(Q(1,2), 0.006687);
|
||||
check_equality(Q(2,0), -0.006573);
|
||||
check_equality(Q(2,1), 0.024478);
|
||||
check_equality(Q(2,2), 0.999679);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
Traits traits;
|
||||
|
||||
test_fitness_function(traits);
|
||||
test_eigen_matrix_interface();
|
||||
|
||||
std::cout << "Done!" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::FT FT;
|
||||
typedef K::Point_3 Point_3;
|
||||
|
||||
typedef CGAL::Oriented_bounding_box_traits_3<K> Traits;
|
||||
typedef Traits::Matrix Matrix;
|
||||
typedef CGAL::Optimal_bounding_box::internal::Population<Traits>::Vertex Vertex;
|
||||
|
||||
void check_equality(const FT d1, const FT d2)
|
||||
{
|
||||
const FT epsilon = 1e-3;
|
||||
|
||||
bool ok;
|
||||
if(std::is_floating_point<FT>::value)
|
||||
ok = CGAL::abs(d1 - d2) < epsilon * CGAL::abs(d2);
|
||||
else
|
||||
ok = (d1 == d2);
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
std::cout << "Error: got " << d1 << " but expected: " << d2 << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void test_simplex_operations(const Traits& traits)
|
||||
{
|
||||
Matrix Sc;
|
||||
Sc.set(0, 0, -0.809204); Sc.set(0, 1, 0.124296); Sc.set(0, 2, 0.574230);
|
||||
Sc.set(1, 0, -0.574694); Sc.set(1, 1, 0.035719); Sc.set(1, 2, -0.817589);
|
||||
Sc.set(2, 0, -0.122134); Sc.set(2, 1, -0.991602); Sc.set(2, 2, 0.042528);
|
||||
|
||||
Matrix S_worst;
|
||||
S_worst.set(0, 0, -0.45070); S_worst.set(0, 1, -0.32769); S_worst.set(0, 2, -0.83035);
|
||||
S_worst.set(1, 0, -0.13619); S_worst.set(1, 1, -0.89406); S_worst.set(1, 2, 0.42675);
|
||||
S_worst.set(2, 0, -0.88222); S_worst.set(2, 1, 0.30543); S_worst.set(2, 2, 0.35833);
|
||||
|
||||
Matrix Sr = CGAL::Optimal_bounding_box::internal::reflection(Sc, S_worst);
|
||||
check_equality(Sr(0,0), -0.13359);
|
||||
check_equality(Sr(0,1), -0.95986);
|
||||
check_equality(Sr(0,2), -0.24664);
|
||||
check_equality(Sr(1,0), -0.60307);
|
||||
check_equality(Sr(1,1), -0.11875);
|
||||
check_equality(Sr(1,2), 0.78880);
|
||||
check_equality(Sr(2,0), -0.78642);
|
||||
check_equality(Sr(2,1), 0.25411);
|
||||
check_equality(Sr(2,2), -0.56300);
|
||||
|
||||
Matrix Se = CGAL::Optimal_bounding_box::internal::expansion(Sc, S_worst, Sr);
|
||||
check_equality(Se(0,0), -0.87991);
|
||||
check_equality(Se(0,1), 0.36105);
|
||||
check_equality(Se(0,2), -0.30888);
|
||||
check_equality(Se(1,0), -0.11816);
|
||||
check_equality(Se(1,1), -0.79593);
|
||||
check_equality(Se(1,2), -0.59375);
|
||||
check_equality(Se(2,0), -0.460215);
|
||||
check_equality(Se(2,1), -0.48595);
|
||||
check_equality(Se(2,2), 0.74300);
|
||||
|
||||
Matrix S_a;
|
||||
S_a.set(0, 0, -0.277970); S_a.set(0, 1, 0.953559); S_a.set(0, 2, 0.116010);
|
||||
S_a.set(1, 0, -0.567497); S_a.set(1, 1, -0.065576); S_a.set(1, 2, -0.820760);
|
||||
S_a.set(2, 0, -0.775035); S_a.set(2, 1, -0.293982); S_a.set(2, 2, 0.559370);
|
||||
|
||||
Matrix S_b;
|
||||
S_b.set(0, 0, -0.419979); S_b.set(0, 1, 0.301765); S_b.set(0, 2, -0.8558940);
|
||||
S_b.set(1, 0, -0.653011); S_b.set(1, 1, -0.755415); S_b.set(1, 2, 0.054087);
|
||||
S_b.set(2, 0, -0.630234); S_b.set(2, 1, 0.581624); S_b.set(2, 2, 0.514314);
|
||||
|
||||
Matrix S_c = CGAL::Optimal_bounding_box::internal::mean(S_a, S_b, traits);
|
||||
check_equality(S_c(0,0), -0.35111);
|
||||
check_equality(S_c(0,1), 0.79308);
|
||||
check_equality(S_c(0,2), -0.49774);
|
||||
check_equality(S_c(1,0), -0.61398);
|
||||
check_equality(S_c(1,1), -0.59635);
|
||||
check_equality(S_c(1,2), -0.51710);
|
||||
check_equality(S_c(2,0), -0.70693);
|
||||
check_equality(S_c(2,1), 0.12405);
|
||||
check_equality(S_c(2,2), 0.69632);
|
||||
}
|
||||
|
||||
void test_centroid(const Traits& traits)
|
||||
{
|
||||
Matrix S_a;
|
||||
S_a.set(0, 0, -0.588443); S_a.set(0, 1, 0.807140); S_a.set(0, 2, -0.047542);
|
||||
S_a.set(1, 0, -0.786228); S_a.set(1, 1, -0.584933); S_a.set(1, 2, -0.199246);
|
||||
S_a.set(2, 0, -0.188629); S_a.set(2, 1, -0.079867); S_a.set(2, 2, 0.978795);
|
||||
|
||||
Matrix S_b;
|
||||
S_b.set(0, 0, -0.2192721); S_b.set(0, 1, 0.2792986); S_b.set(0, 2, -0.9348326);
|
||||
S_b.set(1, 0, -0.7772152); S_b.set(1, 1, -0.6292092); S_b.set(1, 2, -0.005686);
|
||||
S_b.set(2, 0, -0.5897934); S_b.set(2, 1, 0.7253193); S_b.set(2, 2, 0.3550431);
|
||||
|
||||
Matrix S_c;
|
||||
S_c.set(0, 0, -0.32657); S_c.set(0, 1, -0.60013); S_c.set(0, 2, -0.730206);
|
||||
S_c.set(1, 0, -0.20022); S_c.set(1, 1, -0.71110); S_c.set(1, 2, 0.67398);
|
||||
S_c.set(2, 0, -0.92372); S_c.set(2, 1, 0.36630); S_c.set(2, 2, 0.11207);
|
||||
|
||||
Matrix S_centroid = CGAL::Optimal_bounding_box::internal::nm_centroid(S_a, S_b, S_c, traits);
|
||||
check_equality(S_centroid(0,0), -0.419979);
|
||||
check_equality(S_centroid(0,1), 0.301765);
|
||||
check_equality(S_centroid(0,2), -0.855894);
|
||||
check_equality(S_centroid(1,0), -0.653011);
|
||||
check_equality(S_centroid(1,1), -0.755415);
|
||||
check_equality(S_centroid(1,2), 0.054087);
|
||||
check_equality(S_centroid(2,0), -0.630234);
|
||||
check_equality(S_centroid(2,1), 0.581624);
|
||||
check_equality(S_centroid(2,2), 0.514314);
|
||||
}
|
||||
|
||||
void test_nelder_mead(const Traits& traits)
|
||||
{
|
||||
std::array<Point_3, 4> points;
|
||||
points[0] = Point_3(0.866802, 0.740808, 0.895304);
|
||||
points[1] = Point_3(0.912651, 0.761565, 0.160330);
|
||||
points[2] = Point_3(0.093661, 0.892578, 0.737412);
|
||||
points[3] = Point_3(0.166461, 0.149912, 0.364944);
|
||||
|
||||
// one simplex
|
||||
std::array<Vertex, 4> simplex;
|
||||
|
||||
Matrix v0, v1, v2, v3;
|
||||
v0.set(0, 0, -0.2192721); v0.set(0, 1, 0.2792986); v0.set(0, 2, -0.9348326);
|
||||
v0.set(1, 0, -0.7772152); v0.set(1, 1, -0.6292092); v0.set(1, 2, -0.0056861);
|
||||
v0.set(2, 0, -0.5897934); v0.set(2, 1, 0.7253193); v0.set(2, 2, 0.3550431);
|
||||
|
||||
v1.set(0, 0, -0.588443); v1.set(0, 1, 0.807140); v1.set(0, 2, -0.047542);
|
||||
v1.set(1, 0, -0.786228); v1.set(1, 1, -0.584933); v1.set(1, 2, -0.199246);
|
||||
v1.set(2, 0, -0.188629); v1.set(2, 1, -0.079867); v1.set(2, 2, 0.978795);
|
||||
|
||||
v2.set(0, 0, -0.277970); v2.set(0, 1, 0.953559); v2.set(0, 2, 0.116010);
|
||||
v2.set(1, 0, -0.567497); v2.set(1, 1, -0.065576); v2.set(1, 2, -0.820760);
|
||||
v2.set(2, 0, -0.775035); v2.set(2, 1, -0.293982); v2.set(2, 2, 0.559370);
|
||||
|
||||
v3.set(0, 0, -0.32657); v3.set(0, 1, -0.60013); v3.set(0, 2, -0.73020);
|
||||
v3.set(1, 0, -0.20022); v3.set(1, 1, -0.71110); v3.set(1, 2, 0.67398);
|
||||
v3.set(2, 0, -0.92372); v3.set(2, 1, 0.36630); v3.set(2, 2, 0.11207);
|
||||
|
||||
simplex[0] = Vertex{v0, points, traits};
|
||||
simplex[1] = Vertex{v1, points, traits};
|
||||
simplex[2] = Vertex{v2, points, traits};
|
||||
simplex[3] = Vertex{v3, points, traits};
|
||||
|
||||
std::size_t nm_iterations = 19;
|
||||
CGAL::Optimal_bounding_box::internal::nelder_mead(simplex, nm_iterations, points, traits);
|
||||
|
||||
const Matrix& v0_new = simplex[0].matrix();
|
||||
check_equality(v0_new(0,0), -0.288975);
|
||||
check_equality(v0_new(0,1), 0.7897657);
|
||||
check_equality(v0_new(0,2), -0.541076);
|
||||
check_equality(v0_new(1,0), -0.9407046);
|
||||
check_equality(v0_new(1,1), -0.3391466);
|
||||
check_equality(v0_new(1,2), 0.0073817);
|
||||
check_equality(v0_new(2,0), -0.1776743);
|
||||
check_equality(v0_new(2,1), 0.5111260);
|
||||
check_equality(v0_new(2,2), 0.84094);
|
||||
|
||||
const Matrix& v1_new = simplex[1].matrix();
|
||||
check_equality(v1_new(0,0), -0.458749);
|
||||
check_equality(v1_new(0,1), 0.823283);
|
||||
check_equality(v1_new(0,2), -0.334296);
|
||||
check_equality(v1_new(1,0), -0.885235);
|
||||
check_equality(v1_new(1,1), -0.455997);
|
||||
check_equality(v1_new(1,2), 0.091794);
|
||||
check_equality(v1_new(2,0), -0.076866);
|
||||
check_equality(v1_new(2,1), 0.338040);
|
||||
check_equality(v1_new(2,2), 0.937987);
|
||||
|
||||
const Matrix& v2_new = simplex[2].matrix();
|
||||
check_equality(v2_new(0,0), -0.346582);
|
||||
check_equality(v2_new(0,1), 0.878534);
|
||||
check_equality(v2_new(0,2), -0.328724);
|
||||
check_equality(v2_new(1,0), -0.936885);
|
||||
check_equality(v2_new(1,1), -0.341445);
|
||||
check_equality(v2_new(1,2), 0.075251);
|
||||
check_equality(v2_new(2,0), -0.046131);
|
||||
check_equality(v2_new(2,1), 0.334057);
|
||||
check_equality(v2_new(2,2), 0.941423);
|
||||
|
||||
const Matrix& v3_new = simplex[3].matrix();
|
||||
check_equality(v3_new(0,0), -0.394713);
|
||||
check_equality(v3_new(0,1), 0.791782);
|
||||
check_equality(v3_new(0,2), -0.466136);
|
||||
check_equality(v3_new(1,0), -0.912112);
|
||||
check_equality(v3_new(1,1), -0.398788);
|
||||
check_equality(v3_new(1,2), 0.094972);
|
||||
check_equality(v3_new(2,0), -0.110692);
|
||||
check_equality(v3_new(2,1), 0.462655);
|
||||
check_equality(v3_new(2,2), 0.879601);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
Traits traits;
|
||||
|
||||
test_simplex_operations(traits);
|
||||
test_centroid(traits);
|
||||
test_nelder_mead(traits);
|
||||
|
||||
std::cout << "Done!" << std::endl;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
#define CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
|
||||
|
||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
#include <CGAL/Polyhedron_3.h>
|
||||
|
||||
#include <CGAL/boost/graph/generators.h>
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
#include <CGAL/Polygon_mesh_processing/triangulate_faces.h>
|
||||
#include <CGAL/Polygon_mesh_processing/measure.h>
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
|
||||
typedef K::FT FT;
|
||||
typedef K::Point_3 Point;
|
||||
|
||||
typedef CGAL::Polyhedron_3<K> Mesh;
|
||||
|
||||
typedef CGAL::Oriented_bounding_box_traits_3<K> Traits;
|
||||
typedef Traits::Matrix Matrix;
|
||||
|
||||
bool is_equal(const FT d1, const FT d2)
|
||||
{
|
||||
const FT epsilon = 1e-3;
|
||||
|
||||
bool ok;
|
||||
if(std::is_floating_point<FT>::value)
|
||||
ok = CGAL::abs(d1 - d2) < std::max(epsilon * d1, epsilon);
|
||||
else
|
||||
ok = (d1 == d2);
|
||||
|
||||
if(!ok)
|
||||
{
|
||||
std::cout << "Got " << d1 << " but expected: " << d2 << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename PointRange>
|
||||
void test_OBB_data(const PointRange& points,
|
||||
const double expected_vol,
|
||||
const bool with_convex_hull = true)
|
||||
{
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
// the algorithm is allowed to fail, but not too often
|
||||
int failure_count = 0;
|
||||
for(int i=0; i<10; ++i)
|
||||
{
|
||||
std::cout << "iter #" << i << std::endl;
|
||||
|
||||
CGAL::Surface_mesh<Point> obb_mesh;
|
||||
CGAL::oriented_bounding_box(points, obb_mesh, CGAL::parameters::use_convex_hull(with_convex_hull));
|
||||
PMP::triangulate_faces(obb_mesh);
|
||||
|
||||
// the triangulate algorithm might fail if the algorithm manages
|
||||
// to fit perfectly the box to have a true 0 volume
|
||||
if(CGAL::is_triangle_mesh(obb_mesh))
|
||||
{
|
||||
double vol = PMP::volume(obb_mesh);
|
||||
std::cout << " volume is: " << vol << ", expected: " << expected_vol << std::endl;
|
||||
if(!is_equal(vol, expected_vol))
|
||||
{
|
||||
std::cout << "Failure!" << std::endl;
|
||||
++failure_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "failures: " << failure_count << std::endl;
|
||||
assert(failure_count < 2); // 10% failure
|
||||
}
|
||||
|
||||
void test_OBB_of_mesh(const std::string fname,
|
||||
const double expected_vol)
|
||||
{
|
||||
std::cout << "Test: " << fname << std::endl;
|
||||
|
||||
std::ifstream input(fname);
|
||||
Mesh mesh;
|
||||
if(!input || !(input >> mesh) || mesh.is_empty())
|
||||
{
|
||||
std::cerr << fname << " is not a valid input file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::vector<Point> points;
|
||||
for(const auto v : vertices(mesh))
|
||||
points.push_back(v->point());
|
||||
|
||||
test_OBB_data(points, expected_vol);
|
||||
}
|
||||
|
||||
void test_OBB_of_point_set(const std::string fname,
|
||||
const double expected_vol)
|
||||
{
|
||||
std::cout << "Test: " << fname << std::endl;
|
||||
|
||||
std::ifstream input(fname);
|
||||
if(!input)
|
||||
{
|
||||
std::cerr << fname << " is not a valid input file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
std::deque<Point> points;
|
||||
double x, y, z;
|
||||
while(input >> x >> y >> z)
|
||||
points.emplace_back(x, y, z);
|
||||
|
||||
test_OBB_data(points, expected_vol, false /*no convex hull due to degenerate data*/);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout.precision(17);
|
||||
|
||||
test_OBB_of_mesh("data/elephant.off", 0.294296);
|
||||
test_OBB_of_mesh("data/long_tetrahedron.off", 0.04);
|
||||
test_OBB_of_mesh("data/reference_tetrahedron.off", 1);
|
||||
|
||||
// degenerate cases, disabled because
|
||||
// - some testsuite platforms are too slow in debug, and they timeout
|
||||
// - the algorithm does not fully support degenerate data: it returns a box which is optimal
|
||||
// in terms of volume (0), but is not necessarily optimal in the lower dimensions (i.e., the base
|
||||
// of the OBB is not optimal).
|
||||
// test_OBB_of_mesh("data/triangles.off", 0); // 2D data set
|
||||
// test_OBB_of_mesh("data/flat_mesh.off", 0); // 2D data set
|
||||
// test_OBB_of_point_set("data/points_2D.xyz", 0); // 2D data set
|
||||
// test_OBB_of_point_set("data/points_1D.xyz", 0); // 1D data set
|
||||
// test_OBB_of_point_set("data/points_0D.xyz", 0); // 0D data set
|
||||
|
||||
std::cout << "Done!" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -27,13 +27,13 @@
|
|||
#include <CGAL/Regular_triangulation_cell_base_3.h>
|
||||
|
||||
#include <CGAL/enum.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
#include <CGAL/internal/Has_nested_type_Bare_point.h>
|
||||
#include <CGAL/spatial_sort.h>
|
||||
#include <CGAL/utility.h>
|
||||
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
|
|
@ -498,12 +498,12 @@ public:
|
|||
// Spatial sorting can only be applied to bare points, so we need an adaptor
|
||||
typedef typename Geom_traits::Construct_point_3 Construct_point_3;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
spatial_sort(pbegin, points.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
boost::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
geom_traits().construct_point_3_object()), geom_traits()));
|
||||
|
||||
Cell_handle hint;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ int main(int argc, char* argv[])
|
|||
Mesh mesh;
|
||||
if(!input || !(input >> mesh) || num_vertices(mesh) == 0)
|
||||
{
|
||||
std::cerr << filename << " is not a valid off file.\n";
|
||||
std::cerr << filename << " is not a valid off file." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
Mesh mesh1;
|
||||
if ( !input || !(input >> mesh1) ) {
|
||||
std::cerr << filename1 << " is not a valid off file.\n";
|
||||
std::cerr << filename1 << " is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
input.close();
|
||||
|
|
@ -34,7 +34,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
Mesh mesh2;
|
||||
if ( !input || !(input >> mesh2) ) {
|
||||
std::cerr << filename2 << " is not a valid off file.\n";
|
||||
std::cerr << filename2 << " is not a valid off file." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
#include <CGAL/boost/graph/helpers.h>
|
||||
#include <CGAL/Polygon_mesh_processing/connected_components.h>
|
||||
#include <CGAL/property_map.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
|
@ -167,7 +168,7 @@ void test_CC_with_area_size_map(Mesh sm,
|
|||
|
||||
std::cout << "We keep the " << 2 << " largest components" << std::endl;
|
||||
std::size_t res = PMP::keep_largest_connected_components(sm, 2,
|
||||
PMP::parameters::face_size_map(CGAL::internal::boost_::make_function_property_map<face_descriptor>(f))
|
||||
PMP::parameters::face_size_map(boost::make_function_property_map<face_descriptor>(f))
|
||||
.dry_run(true)
|
||||
.output_iterator(std::back_inserter(faces_to_remove)));
|
||||
|
||||
|
|
@ -183,7 +184,7 @@ void test_CC_with_area_size_map(Mesh sm,
|
|||
|
||||
PMP::keep_largest_connected_components(sm, 2,
|
||||
PMP::parameters::face_size_map(
|
||||
CGAL::internal::boost_::make_function_property_map<face_descriptor>(f)));
|
||||
boost::make_function_property_map<face_descriptor>(f)));
|
||||
assert(vertices(sm).size() == 1459);
|
||||
|
||||
{
|
||||
|
|
@ -199,7 +200,7 @@ void test_CC_with_area_size_map(Mesh sm,
|
|||
Face_descriptor_area_functor<Mesh, Kernel> f(m, k);
|
||||
PMP::keep_large_connected_components(m, 10,
|
||||
CGAL::parameters::face_size_map(
|
||||
CGAL::internal::boost_::make_function_property_map<face_descriptor>(f)));
|
||||
boost::make_function_property_map<face_descriptor>(f)));
|
||||
assert(vertices(m).size() == 3);
|
||||
|
||||
PMP::keep_largest_connected_components(m, 1);
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ void run(const char* filename1, const char* filename2, const char* msg)
|
|||
{
|
||||
TriangleMesh mesh1;
|
||||
if ( !CGAL::read_off(filename1, mesh1) ) {
|
||||
std::cerr << filename1 << " is not a valid off file.\n";
|
||||
std::cerr << filename1 << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
TriangleMesh mesh2;
|
||||
if ( !CGAL::read_off(filename2, mesh2) ) {
|
||||
std::cerr << filename2 << " is not a valid off file.\n";
|
||||
std::cerr << filename2 << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ void test_merge_duplicated_vertices_in_boundary_cycles(const char* fname,
|
|||
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ void read_mesh(const char* fname,
|
|||
std::ifstream input(fname);
|
||||
if (!input || !(input >> mesh) || mesh.is_empty())
|
||||
{
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ void remove_degeneracies(const char* filename,
|
|||
Mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty())
|
||||
{
|
||||
std::cerr << filename << " is not a valid off file.\n";
|
||||
std::cerr << filename << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ void remove_negligible_connected_components(const char* filename)
|
|||
Mesh mesh, mesh_cpy;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty())
|
||||
{
|
||||
std::cerr << filename << " is not a valid off file.\n";
|
||||
std::cerr << filename << " is not a valid off file." << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ void check_edge_degeneracy(const char* fname)
|
|||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
std::vector<edge_descriptor> all_edges(edges(mesh).begin(), edges(mesh).end());
|
||||
|
|
@ -44,7 +44,7 @@ void check_triangle_face_degeneracy(const char* fname)
|
|||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ void test_needles_and_caps(const char* fname)
|
|||
std::ifstream input(fname);
|
||||
Surface_mesh mesh;
|
||||
if (!input || !(input >> mesh) || mesh.is_empty()) {
|
||||
std::cerr << fname << " is not a valid off file.\n";
|
||||
std::cerr << fname << " is not a valid off file." << std::endl;
|
||||
std::exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,14 +11,14 @@
|
|||
#include <CGAL/IO/STL_writer.h>
|
||||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <QColor>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMainWindow>
|
||||
#include <QInputDialog>
|
||||
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
|
@ -90,7 +90,7 @@ load(QFileInfo fileinfo, bool& ok, bool add_to_scene){
|
|||
SMesh* SM = new SMesh();
|
||||
if (CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(triangles))
|
||||
{
|
||||
auto pmap = CGAL::internal::boost_::make_function_property_map<std::array<double, 3>, Point_3>(
|
||||
auto pmap = boost::make_function_property_map<std::array<double, 3>, Point_3>(
|
||||
[](const std::array<double, 3>& a) { return Point_3(a[0], a[1], a[2]); });
|
||||
CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, triangles, *SM,
|
||||
CGAL::parameters::point_map(pmap),
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ target_link_libraries(clipping_box_plugin PUBLIC scene_edit_box_item scene_basi
|
|||
polyhedron_demo_plugin(create_bbox_mesh_plugin Create_bbox_mesh_plugin)
|
||||
target_link_libraries(create_bbox_mesh_plugin PUBLIC scene_surface_mesh_item)
|
||||
|
||||
polyhedron_demo_plugin(create_obb_mesh_plugin Create_obb_mesh_plugin)
|
||||
target_link_libraries(create_obb_mesh_plugin PUBLIC scene_surface_mesh_item scene_selection_item scene_points_with_normal_item)
|
||||
|
||||
qt5_wrap_ui( volumesUI_FILES Basic_generator_widget.ui)
|
||||
polyhedron_demo_plugin(basic_generator_plugin Basic_generator_plugin ${volumesUI_FILES} KEYWORDS PolygonMesh PointSetProcessing)
|
||||
target_link_libraries(basic_generator_plugin PUBLIC scene_surface_mesh_item scene_points_with_normal_item scene_polylines_item)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,154 @@
|
|||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <CGAL/Three/Scene_item.h>
|
||||
#include <CGAL/Three/Scene_interface.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
|
||||
#include "Scene_surface_mesh_item.h"
|
||||
#include "Scene_polyhedron_selection_item.h"
|
||||
#include "Scene_points_with_normal_item.h"
|
||||
|
||||
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
|
||||
|
||||
#include <CGAL/optimal_bounding_box.h>
|
||||
|
||||
using namespace CGAL::Three;
|
||||
|
||||
typedef Scene_surface_mesh_item Scene_facegraph_item;
|
||||
|
||||
class Create_obb_mesh_plugin :
|
||||
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:
|
||||
void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*);
|
||||
QList<QAction*> actions() const;
|
||||
|
||||
bool applicable(QAction*) const
|
||||
{
|
||||
if(scene->mainSelectionIndex() != -1
|
||||
&& scene->item(scene->mainSelectionIndex())->isFinite())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void gather_mesh_points(std::vector<Point_3>& points);
|
||||
void obb();
|
||||
|
||||
public Q_SLOTS:
|
||||
void createObb()
|
||||
{
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
obb();
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
private:
|
||||
Scene_interface* scene;
|
||||
QMainWindow* mw;
|
||||
QAction* actionObb;
|
||||
}; // end Create_obb_mesh_plugin class
|
||||
|
||||
void Create_obb_mesh_plugin::init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*)
|
||||
{
|
||||
scene = scene_interface;
|
||||
mw = mainWindow;
|
||||
actionObb = new QAction(tr("Create &Optimal Bbox Mesh"), mainWindow);
|
||||
actionObb->setObjectName("createObbMeshAction");
|
||||
connect(actionObb, SIGNAL(triggered()), this, SLOT(createObb()));
|
||||
}
|
||||
|
||||
QList<QAction*> Create_obb_mesh_plugin::actions() const
|
||||
{
|
||||
return QList<QAction*>() << actionObb;
|
||||
}
|
||||
|
||||
void Create_obb_mesh_plugin::gather_mesh_points(std::vector<Point_3>& points)
|
||||
{
|
||||
const Scene_interface::Item_id index = scene->mainSelectionIndex();
|
||||
|
||||
Scene_facegraph_item* item = qobject_cast<Scene_facegraph_item*>(scene->item(index));
|
||||
|
||||
Scene_polyhedron_selection_item* selection_item =
|
||||
qobject_cast<Scene_polyhedron_selection_item*>(scene->item(index));
|
||||
|
||||
Scene_points_with_normal_item* point_set_item =
|
||||
qobject_cast<Scene_points_with_normal_item*>(scene->item(index));
|
||||
|
||||
if(item || selection_item)
|
||||
{
|
||||
typedef typename boost::property_map<FaceGraph, boost::vertex_point_t>::type PointPMap;
|
||||
typedef typename boost::graph_traits<FaceGraph>::vertex_descriptor vertex_descriptor;
|
||||
typedef typename boost::graph_traits<FaceGraph>::face_descriptor face_descriptor;
|
||||
|
||||
std::vector<vertex_descriptor> selected_vertices;
|
||||
|
||||
if(item != NULL)
|
||||
{
|
||||
FaceGraph& pmesh = *item->polyhedron();
|
||||
selected_vertices.assign(vertices(pmesh).begin(), vertices(pmesh).end());
|
||||
PointPMap pmap = get(CGAL::vertex_point, pmesh);
|
||||
for(vertex_descriptor v : selected_vertices)
|
||||
points.push_back(get(pmap, v));
|
||||
|
||||
}
|
||||
else if(selection_item != NULL) // using selection of faces
|
||||
{
|
||||
FaceGraph& pmesh = *selection_item->polyhedron();
|
||||
for(face_descriptor f : selection_item->selected_facets)
|
||||
{
|
||||
for(vertex_descriptor v : vertices_around_face(halfedge(f, pmesh), pmesh))
|
||||
selected_vertices.push_back(v);
|
||||
}
|
||||
|
||||
PointPMap pmap = get(CGAL::vertex_point, pmesh);
|
||||
for(vertex_descriptor v : selected_vertices)
|
||||
points.push_back(get(pmap, v));
|
||||
}
|
||||
|
||||
CGAL_assertion(points.size() >= 3);
|
||||
}
|
||||
|
||||
if(point_set_item)
|
||||
{
|
||||
Point_set* points_set = point_set_item->point_set();
|
||||
if(points_set == NULL)
|
||||
return;
|
||||
|
||||
std::cout << "points_set->size()= " << points_set->size() << std::endl;
|
||||
for(const Point_3& p : points_set->points())
|
||||
points.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Create_obb_mesh_plugin::obb()
|
||||
{
|
||||
// gather point coordinates
|
||||
std::vector<Point_3> points;
|
||||
gather_mesh_points(points);
|
||||
|
||||
// find obb
|
||||
std::array<Point_3, 8> obb_points;
|
||||
CGAL::oriented_bounding_box(points, obb_points);
|
||||
|
||||
Scene_facegraph_item* item;
|
||||
SMesh* p = new SMesh;
|
||||
CGAL::make_hexahedron(obb_points[0], obb_points[1], obb_points[2], obb_points[3],
|
||||
obb_points[4], obb_points[5], obb_points[6], obb_points[7], *p);
|
||||
item = new Scene_facegraph_item(p);
|
||||
|
||||
item->setName("Optimal bbox mesh");
|
||||
item->setRenderingMode(Wireframe);
|
||||
scene->addItem(item);
|
||||
}
|
||||
|
||||
#include "Create_obb_mesh_plugin.moc"
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
//
|
||||
//=======================================================================
|
||||
// Author: Philipp Moeller
|
||||
//
|
||||
// Copyright 2012, Philipp Moeller
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
//=======================================================================
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
// Note: This file was copied from Boost v1.64 because it was introduced
|
||||
// in a release (~v1.51) that is newer than the oldest release of Boost
|
||||
// that CGAL supports.
|
||||
// the property map 'function_property_map' is (currently) used
|
||||
// in the packages Triangulation_2 and Triangulation_3.
|
||||
|
||||
#ifndef CGAL_INTERNAL_BOOST_PROPERTY_MAP_FUNCTION_PROPERTY_MAP_HPP
|
||||
#define CGAL_INTERNAL_BOOST_PROPERTY_MAP_FUNCTION_PROPERTY_MAP_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/property_map/property_map.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace CGAL {
|
||||
namespace internal {
|
||||
namespace boost_ {
|
||||
|
||||
template<typename Func,
|
||||
typename Key,
|
||||
typename Ret = typename boost::result_of<const Func(const Key&)>::type>
|
||||
class function_property_map
|
||||
: public boost::put_get_helper<Ret, function_property_map<Func, Key, Ret> >
|
||||
{
|
||||
public:
|
||||
typedef Key key_type;
|
||||
typedef Ret reference;
|
||||
typedef typename boost::remove_cv<typename boost::remove_reference<Ret>::type>::type value_type;
|
||||
|
||||
typedef typename boost::mpl::if_<
|
||||
boost::mpl::and_<
|
||||
boost::is_reference<Ret>,
|
||||
boost::mpl::not_< boost::is_const<Ret> >
|
||||
>,
|
||||
boost::lvalue_property_map_tag,
|
||||
boost::readable_property_map_tag>::type
|
||||
category;
|
||||
|
||||
function_property_map(Func f = Func()) : f(f) {}
|
||||
|
||||
reference operator[](const Key& k) const {
|
||||
return f(k);
|
||||
}
|
||||
|
||||
private:
|
||||
Func f;
|
||||
};
|
||||
|
||||
template<typename Key, typename Func>
|
||||
function_property_map<Func, Key>
|
||||
make_function_property_map(const Func& f) {
|
||||
return function_property_map<Func, Key>(f);
|
||||
}
|
||||
|
||||
template<typename Key, typename Ret, typename Func>
|
||||
function_property_map<Func, Key, Ret>
|
||||
make_function_property_map(const Func& f) {
|
||||
return function_property_map<Func, Key, Ret>(f);
|
||||
}
|
||||
|
||||
} // boost_
|
||||
} // internal
|
||||
} // CGAL
|
||||
|
||||
#endif /* CGAL_INTERNAL_BOOST_PROPERTY_MAP_FUNCTION_PROPERTY_MAP_HPP */
|
||||
|
|
@ -86,6 +86,9 @@ public:
|
|||
\cgalConcept
|
||||
Concept of matrix type used by the concept `SvdTraits`.
|
||||
|
||||
\cgalRefines `DefaultConstructible`
|
||||
\cgalRefines `Assignable`
|
||||
|
||||
\cgalHasModel `CGAL::Eigen_matrix<T>`
|
||||
*/
|
||||
class SvdTraits::Matrix
|
||||
|
|
|
|||
|
|
@ -8,377 +8,84 @@
|
|||
//
|
||||
// Author(s) : Gael Guennebaud
|
||||
|
||||
#ifndef CGAL_EIGEN_MATRIX_H
|
||||
#define CGAL_EIGEN_MATRIX_H
|
||||
#ifndef CGAL_SOLVER_INTERFACE_EIGEN_MATRIX_H
|
||||
#define CGAL_SOLVER_INTERFACE_EIGEN_MATRIX_H
|
||||
|
||||
#include <CGAL/basic.h> // include basic.h before testing #defines
|
||||
|
||||
#include <Eigen/Sparse>
|
||||
#include <CGAL/Eigen_sparse_matrix.h> // for backward compatibility
|
||||
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgSolverInterfaceRef
|
||||
|
||||
The class `Eigen_sparse_matrix` is a wrapper around `Eigen` matrix type
|
||||
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html">`Eigen::SparseMatrix`</a>
|
||||
that represents general matrices, be they symmetric or not.
|
||||
|
||||
\cgalModels `SparseLinearAlgebraTraits_d::Matrix`
|
||||
|
||||
\tparam T Number type.
|
||||
|
||||
\sa `CGAL::Eigen_vector<T>`
|
||||
\sa `CGAL::Eigen_matrix<T>`
|
||||
\sa `CGAL::Eigen_sparse_symmetric_matrix<T>`
|
||||
*/
|
||||
template<class T>
|
||||
struct Eigen_sparse_matrix
|
||||
{
|
||||
// Public types
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// The internal matrix type from \ref thirdpartyEigen "Eigen".
|
||||
typedef Eigen::SparseMatrix<T> EigenType;
|
||||
|
||||
typedef T NT;
|
||||
/// @}
|
||||
|
||||
Eigen_sparse_matrix(const EigenType& et)
|
||||
: m_is_already_built(true), m_matrix(et), m_is_symmetric(false)
|
||||
{}
|
||||
|
||||
// Public operations
|
||||
public:
|
||||
Eigen_sparse_matrix() :
|
||||
m_is_already_built(false)
|
||||
{}
|
||||
|
||||
/// Create a square matrix initialized with zeros.
|
||||
Eigen_sparse_matrix(std::size_t dim, ///< Matrix dimension.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
:
|
||||
m_is_already_built(false),
|
||||
m_matrix(static_cast<int>(dim), static_cast<int>(dim))
|
||||
{
|
||||
CGAL_precondition(dim > 0);
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
m_triplets.reserve(dim); // reserve memory for a regular 3D grid
|
||||
}
|
||||
|
||||
/// Create a square matrix initialized with zeros.
|
||||
Eigen_sparse_matrix(int dim, ///< Matrix dimension.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(dim, dim)
|
||||
{
|
||||
CGAL_precondition(dim > 0);
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(dim);
|
||||
}
|
||||
|
||||
/// Create a rectangular matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns if `is_symmetric` is true.
|
||||
Eigen_sparse_matrix(std::size_t rows, ///< Number of rows.
|
||||
std::size_t columns, ///< Number of columns.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(static_cast<int>(rows), static_cast<int>(columns))
|
||||
{
|
||||
CGAL_precondition(rows > 0);
|
||||
CGAL_precondition(columns > 0);
|
||||
if(m_is_symmetric)
|
||||
{
|
||||
CGAL_precondition(rows == columns);
|
||||
}
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(rows);
|
||||
}
|
||||
|
||||
void swap(Eigen_sparse_matrix& other)
|
||||
{
|
||||
std::swap(m_is_already_built, other.m_is_already_built);
|
||||
std::swap(m_is_symmetric, other.m_is_symmetric);
|
||||
m_matrix.swap(other.m_matrix);
|
||||
m_triplets.swap(other.m_triplets);
|
||||
}
|
||||
|
||||
|
||||
/// Delete this object and the wrapped matrix.
|
||||
~Eigen_sparse_matrix() { }
|
||||
|
||||
/// Create a rectangular matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns if `is_symmetric` is true.
|
||||
Eigen_sparse_matrix(int rows, ///< Number of rows.
|
||||
int columns, ///< Number of columns.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(rows,columns)
|
||||
{
|
||||
CGAL_precondition(rows > 0);
|
||||
CGAL_precondition(columns > 0);
|
||||
if(is_symmetric)
|
||||
{
|
||||
CGAL_precondition(rows == columns);
|
||||
}
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(rows);
|
||||
}
|
||||
|
||||
/// Return the matrix number of rows
|
||||
int row_dimension() const { return static_cast<int>(m_matrix.rows()); }
|
||||
/// Return the matrix number of columns
|
||||
int column_dimension() const { return static_cast<int>(m_matrix.cols()); }
|
||||
|
||||
/// Write access to a matrix coefficient: a_ij <- val.
|
||||
///
|
||||
/// Users can optimize calls to this function by setting 'new_coef' to `true`
|
||||
/// if the coefficient does not already exist in the matrix.
|
||||
///
|
||||
/// \warning For symmetric matrices, `Eigen_sparse_matrix` only stores the lower triangle
|
||||
/// and `set_coef()` does nothing if (i, j) belongs to the upper triangle.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
void set_coef(std::size_t i_, std::size_t j_, T val, bool new_coef = false)
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
|
||||
if (m_is_symmetric && (j > i))
|
||||
return;
|
||||
|
||||
if(m_is_already_built)
|
||||
{
|
||||
m_matrix.coeffRef(i,j) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_coef == false)
|
||||
{
|
||||
assemble_matrix();
|
||||
m_matrix.coeffRef(i,j) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_triplets.push_back(Triplet(i,j,val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write access to a matrix coefficient: a_ij <- a_ij + val.
|
||||
///
|
||||
/// \warning For symmetric matrices, Eigen_sparse_matrix only stores the lower triangle
|
||||
/// `add_coef()` does nothing if (i, j) belongs to the upper triangle.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
void add_coef(std::size_t i_, std::size_t j_, T val)
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
if(m_is_symmetric && (j > i))
|
||||
return;
|
||||
|
||||
if(m_is_already_built){
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
m_matrix.coeffRef(i,j) += val;
|
||||
}else{
|
||||
m_triplets.push_back(Triplet(i,j,val));
|
||||
}
|
||||
}
|
||||
|
||||
/// Read access to a matrix coefficient.
|
||||
///
|
||||
/// \warning Complexity:
|
||||
/// - O(log(n)) if the matrix is already built.
|
||||
/// - O(n) if the matrix is not built.
|
||||
/// `n` being the number of entries in the matrix.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
NT get_coef (std::size_t i_, std::size_t j_) const
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
|
||||
if(m_is_symmetric && j > i)
|
||||
std::swap(i, j);
|
||||
|
||||
if (m_is_already_built)
|
||||
return m_matrix.coeffRef(i,j);
|
||||
else
|
||||
{
|
||||
NT val = 0;
|
||||
for(std::size_t t=0; t<m_triplets.size(); ++t)
|
||||
{
|
||||
if(m_triplets[t].col() == j &&
|
||||
m_triplets[t].row() == i)
|
||||
val += m_triplets[t].value();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
void assemble_matrix() const
|
||||
{
|
||||
m_matrix.setFromTriplets(m_triplets.begin(), m_triplets.end());
|
||||
m_is_already_built = true;
|
||||
m_triplets.clear(); // the matrix is built and will not be rebuilt
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/// Return the internal matrix, with type `EigenType`.
|
||||
const EigenType& eigen_object() const
|
||||
{
|
||||
if(!m_is_already_built)
|
||||
assemble_matrix();
|
||||
|
||||
// turns the matrix into compressed mode:
|
||||
// -> release some memory
|
||||
// -> required for some external solvers
|
||||
m_matrix.makeCompressed();
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
/// Return the internal matrix, with type `EigenType`.
|
||||
EigenType& eigen_object()
|
||||
{
|
||||
if(!m_is_already_built)
|
||||
assemble_matrix();
|
||||
|
||||
// turns the matrix into compressed mode:
|
||||
// -> release some memory
|
||||
// -> required for some external solvers
|
||||
m_matrix.makeCompressed();
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
friend Eigen_sparse_matrix
|
||||
operator*(const T& c, const Eigen_sparse_matrix& M)
|
||||
{
|
||||
return Eigen_sparse_matrix(c* M.eigen_object());
|
||||
}
|
||||
|
||||
|
||||
friend Eigen_sparse_matrix
|
||||
operator+(const Eigen_sparse_matrix& M0, const Eigen_sparse_matrix& M1)
|
||||
{
|
||||
return Eigen_sparse_matrix(M0.eigen_object()+ M1.eigen_object());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
|
||||
// Fields
|
||||
private:
|
||||
mutable bool m_is_already_built;
|
||||
|
||||
typedef Eigen::Triplet<T,int> Triplet;
|
||||
mutable std::vector<Triplet> m_triplets;
|
||||
|
||||
mutable EigenType m_matrix;
|
||||
|
||||
// Symmetric/hermitian?
|
||||
bool m_is_symmetric;
|
||||
}; // Eigen_sparse_matrix
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgSolverInterfaceRef
|
||||
|
||||
The class `Eigen_sparse_symmetric_matrix` is a wrapper around `Eigen` matrix type
|
||||
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html">`Eigen::SparseMatrix` </a>
|
||||
|
||||
Since the matrix is symmetric, only the lower triangle part is stored.
|
||||
|
||||
\cgalModels `SparseLinearAlgebraTraits_d::Matrix`
|
||||
|
||||
\tparam T Number type.
|
||||
|
||||
\sa `CGAL::Eigen_vector<T>`
|
||||
\sa `CGAL::Eigen_sparse_matrix<T>`
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
struct Eigen_sparse_symmetric_matrix
|
||||
: public Eigen_sparse_matrix<T>
|
||||
{
|
||||
/// Create a square *symmetric* matrix initialized with zeros.
|
||||
Eigen_sparse_symmetric_matrix(int dim) ///< Matrix dimension.
|
||||
: Eigen_sparse_matrix<T>(dim, true /* symmetric */)
|
||||
{
|
||||
}
|
||||
|
||||
/// Create a square *symmetric* matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns.
|
||||
Eigen_sparse_symmetric_matrix(int rows, ///< Number of rows.
|
||||
int columns) ///< Number of columns.
|
||||
: Eigen_sparse_matrix<T>(rows, columns, true /* symmetric */)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
\ingroup PkgSolverInterfaceRef
|
||||
|
||||
The class `Eigen_matrix` is a wrapper around `Eigen` matrix type
|
||||
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html">`Eigen::Matrix`</a>.
|
||||
|
||||
\cgalModels `SvdTraits::Matrix`
|
||||
|
||||
\tparam T Number type.
|
||||
\tparam D1 Number of rows, or Dynamic
|
||||
\tparam D2 Number of columns, or Dynamic
|
||||
|
||||
\sa `CGAL::Eigen_vector<T>`
|
||||
\sa `CGAL::Eigen_sparse_matrix<T>`
|
||||
\sa `CGAL::Eigen_sparse_symmetric_matrix<T>`
|
||||
*/
|
||||
template <class FT>
|
||||
template <class FT, int D1 = ::Eigen::Dynamic, int D2 = ::Eigen::Dynamic>
|
||||
struct Eigen_matrix
|
||||
: public ::Eigen::Matrix<FT, ::Eigen::Dynamic, ::Eigen::Dynamic>
|
||||
: public ::Eigen::Matrix<FT, D1, D2>
|
||||
{
|
||||
/// The internal matrix type from \ref thirdpartyEigen "Eigen".
|
||||
typedef ::Eigen::Matrix<FT, ::Eigen::Dynamic, ::Eigen::Dynamic> EigenType;
|
||||
typedef ::Eigen::Matrix<FT, D1, D2> EigenType;
|
||||
|
||||
/// Construct a matrix with `nr` rows and `nc` columns.
|
||||
/// Constructs a null matrix.
|
||||
Eigen_matrix() { }
|
||||
|
||||
/// Constructs an uninitialized matrix with `nr` rows and `nc` columns.
|
||||
/// This is useful for dynamic-size matrices.
|
||||
/// For fixed-size matrices, it is redundant to pass these parameters.
|
||||
Eigen_matrix(std::size_t nr, std::size_t nc) : EigenType(nr, nc) { }
|
||||
|
||||
/// Return the matrix number of rows.
|
||||
/// Constructs a matrix from an Eigen matrix.
|
||||
Eigen_matrix(const EigenType& b) : EigenType(b) { }
|
||||
|
||||
/// Returns the matrix number of rows.
|
||||
std::size_t number_of_rows() const { return this->rows(); }
|
||||
/// Return the matrix number of columns.
|
||||
/// Returns the matrix number of columns.
|
||||
std::size_t number_of_columns() const { return this->cols(); }
|
||||
|
||||
/// Return the value of the matrix at position (i,j).
|
||||
/// Returns the value of the matrix at position (i,j).
|
||||
FT operator()( std::size_t i , std::size_t j ) const { return EigenType::operator()(i,j); }
|
||||
|
||||
/// Write access to a matrix coefficient: `a_ij` <- `val`.
|
||||
/// Writes access to a matrix coefficient: `a_ij` <- `val`.
|
||||
void set(std::size_t i, std::size_t j, FT value) { this->coeffRef(i,j) = value; }
|
||||
|
||||
/// Return the internal matrix, with type `EigenType`.
|
||||
/// Returns the internal matrix, with type `EigenType`.
|
||||
const EigenType& eigen_object() const { return static_cast<const EigenType&>(*this); }
|
||||
|
||||
public:
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
friend Eigen_matrix operator*(const FT c, const Eigen_matrix& M)
|
||||
{
|
||||
return Eigen_matrix(c * M.eigen_object());
|
||||
}
|
||||
|
||||
friend Eigen_matrix operator*(const Eigen_matrix& M0, const Eigen_matrix& M1)
|
||||
{
|
||||
return Eigen_matrix(M0.eigen_object() * M1.eigen_object());
|
||||
}
|
||||
|
||||
friend Eigen_matrix operator+(const Eigen_matrix& M0, const Eigen_matrix& M1)
|
||||
{
|
||||
return Eigen_matrix(M0.eigen_object() + M1.eigen_object());
|
||||
}
|
||||
/// \endcond
|
||||
};
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif // CGAL_EIGEN_MATRIX_H
|
||||
#endif // CGAL_SOLVER_INTERFACE_EIGEN_MATRIX_H
|
||||
|
|
|
|||
|
|
@ -0,0 +1,335 @@
|
|||
// Copyright (c) 2012 INRIA Bordeaux Sud-Ouest (France), All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org)
|
||||
//
|
||||
// $URL$
|
||||
// $Id$
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
|
||||
//
|
||||
// Author(s) : Gael Guennebaud
|
||||
|
||||
#ifndef CGAL_SOLVER_INTERFACE_EIGEN_SPARSE_MATRIX_H
|
||||
#define CGAL_SOLVER_INTERFACE_EIGEN_SPARSE_MATRIX_H
|
||||
|
||||
#include <CGAL/basic.h> // include basic.h before testing #defines
|
||||
|
||||
#include <Eigen/Sparse>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/*!
|
||||
\ingroup PkgSolverInterfaceRef
|
||||
|
||||
The class `Eigen_sparse_matrix` is a wrapper around `Eigen` matrix type
|
||||
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html">`Eigen::SparseMatrix`</a>
|
||||
that represents general matrices, be they symmetric or not.
|
||||
|
||||
\cgalModels `SparseLinearAlgebraTraits_d::Matrix`
|
||||
|
||||
\tparam T Number type.
|
||||
|
||||
\sa `CGAL::Eigen_vector<T>`
|
||||
\sa `CGAL::Eigen_matrix<T>`
|
||||
\sa `CGAL::Eigen_sparse_symmetric_matrix<T>`
|
||||
*/
|
||||
template<class T>
|
||||
struct Eigen_sparse_matrix
|
||||
{
|
||||
// Public types
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/// The internal matrix type from \ref thirdpartyEigen "Eigen".
|
||||
typedef Eigen::SparseMatrix<T> EigenType;
|
||||
|
||||
typedef T NT;
|
||||
/// @}
|
||||
|
||||
Eigen_sparse_matrix(const EigenType& et)
|
||||
: m_is_already_built(true), m_matrix(et), m_is_symmetric(false)
|
||||
{}
|
||||
|
||||
// Public operations
|
||||
public:
|
||||
Eigen_sparse_matrix() : m_is_already_built(false) { }
|
||||
|
||||
/// Create a square matrix initialized with zeros.
|
||||
Eigen_sparse_matrix(std::size_t dim, ///< Matrix dimension.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
:
|
||||
m_is_already_built(false),
|
||||
m_matrix(static_cast<int>(dim), static_cast<int>(dim))
|
||||
{
|
||||
CGAL_precondition(dim > 0);
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
m_triplets.reserve(dim); // reserve memory for a regular 3D grid
|
||||
}
|
||||
|
||||
/// Create a square matrix initialized with zeros.
|
||||
Eigen_sparse_matrix(int dim, ///< Matrix dimension.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(dim, dim)
|
||||
{
|
||||
CGAL_precondition(dim > 0);
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(dim);
|
||||
}
|
||||
|
||||
/// Create a rectangular matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns if `is_symmetric` is true.
|
||||
Eigen_sparse_matrix(std::size_t rows, ///< Number of rows.
|
||||
std::size_t columns, ///< Number of columns.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(static_cast<int>(rows), static_cast<int>(columns))
|
||||
{
|
||||
CGAL_precondition(rows > 0);
|
||||
CGAL_precondition(columns > 0);
|
||||
if(m_is_symmetric)
|
||||
{
|
||||
CGAL_precondition(rows == columns);
|
||||
}
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(rows);
|
||||
}
|
||||
|
||||
void swap(Eigen_sparse_matrix& other)
|
||||
{
|
||||
std::swap(m_is_already_built, other.m_is_already_built);
|
||||
std::swap(m_is_symmetric, other.m_is_symmetric);
|
||||
m_matrix.swap(other.m_matrix);
|
||||
m_triplets.swap(other.m_triplets);
|
||||
}
|
||||
|
||||
/// Delete this object and the wrapped matrix.
|
||||
~Eigen_sparse_matrix() { }
|
||||
|
||||
/// Create a rectangular matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns if `is_symmetric` is true.
|
||||
Eigen_sparse_matrix(int rows, ///< Number of rows.
|
||||
int columns, ///< Number of columns.
|
||||
bool is_symmetric = false) ///< Symmetric/hermitian?
|
||||
: m_is_already_built(false),
|
||||
m_matrix(rows,columns)
|
||||
{
|
||||
CGAL_precondition(rows > 0);
|
||||
CGAL_precondition(columns > 0);
|
||||
if(is_symmetric)
|
||||
{
|
||||
CGAL_precondition(rows == columns);
|
||||
}
|
||||
|
||||
m_is_symmetric = is_symmetric;
|
||||
// reserve memory for a regular 3D grid
|
||||
m_triplets.reserve(rows);
|
||||
}
|
||||
|
||||
/// Return the matrix number of rows
|
||||
int row_dimension() const { return static_cast<int>(m_matrix.rows()); }
|
||||
/// Return the matrix number of columns
|
||||
int column_dimension() const { return static_cast<int>(m_matrix.cols()); }
|
||||
|
||||
/// Write access to a matrix coefficient: a_ij <- val.
|
||||
///
|
||||
/// Users can optimize calls to this function by setting 'new_coef' to `true`
|
||||
/// if the coefficient does not already exist in the matrix.
|
||||
///
|
||||
/// \warning For symmetric matrices, `Eigen_sparse_matrix` only stores the lower triangle
|
||||
/// and `set_coef()` does nothing if (i, j) belongs to the upper triangle.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
void set_coef(std::size_t i_, std::size_t j_, T val, bool new_coef = false)
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
|
||||
if (m_is_symmetric && (j > i))
|
||||
return;
|
||||
|
||||
if(m_is_already_built)
|
||||
{
|
||||
m_matrix.coeffRef(i,j) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_coef == false)
|
||||
{
|
||||
assemble_matrix();
|
||||
m_matrix.coeffRef(i,j) = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_triplets.push_back(Triplet(i,j,val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Write access to a matrix coefficient: a_ij <- a_ij + val.
|
||||
///
|
||||
/// \warning For symmetric matrices, Eigen_sparse_matrix only stores the lower triangle
|
||||
/// `add_coef()` does nothing if (i, j) belongs to the upper triangle.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
void add_coef(std::size_t i_, std::size_t j_, T val)
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
if(m_is_symmetric && (j > i))
|
||||
return;
|
||||
|
||||
if(m_is_already_built){
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
m_matrix.coeffRef(i,j) += val;
|
||||
}else{
|
||||
m_triplets.push_back(Triplet(i,j,val));
|
||||
}
|
||||
}
|
||||
|
||||
/// Read access to a matrix coefficient.
|
||||
///
|
||||
/// \warning Complexity:
|
||||
/// - O(log(n)) if the matrix is already built.
|
||||
/// - O(n) if the matrix is not built.
|
||||
/// `n` being the number of entries in the matrix.
|
||||
///
|
||||
/// \pre 0 <= i < row_dimension().
|
||||
/// \pre 0 <= j < column_dimension().
|
||||
NT get_coef (std::size_t i_, std::size_t j_) const
|
||||
{
|
||||
int i = static_cast<int>(i_);
|
||||
int j = static_cast<int>(j_);
|
||||
CGAL_precondition(i < row_dimension());
|
||||
CGAL_precondition(j < column_dimension());
|
||||
|
||||
if(m_is_symmetric && j > i)
|
||||
std::swap(i, j);
|
||||
|
||||
if (m_is_already_built)
|
||||
return m_matrix.coeffRef(i,j);
|
||||
else
|
||||
{
|
||||
NT val = 0;
|
||||
for(std::size_t t=0; t<m_triplets.size(); ++t)
|
||||
{
|
||||
if(m_triplets[t].col() == j &&
|
||||
m_triplets[t].row() == i)
|
||||
val += m_triplets[t].value();
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
void assemble_matrix() const
|
||||
{
|
||||
m_matrix.setFromTriplets(m_triplets.begin(), m_triplets.end());
|
||||
m_is_already_built = true;
|
||||
m_triplets.clear(); // the matrix is built and will not be rebuilt
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
/// Return the internal matrix, with type `EigenType`.
|
||||
const EigenType& eigen_object() const
|
||||
{
|
||||
if(!m_is_already_built)
|
||||
assemble_matrix();
|
||||
|
||||
// turns the matrix into compressed mode:
|
||||
// -> release some memory
|
||||
// -> required for some external solvers
|
||||
m_matrix.makeCompressed();
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
/// Return the internal matrix, with type `EigenType`.
|
||||
EigenType& eigen_object()
|
||||
{
|
||||
if(!m_is_already_built)
|
||||
assemble_matrix();
|
||||
|
||||
// turns the matrix into compressed mode:
|
||||
// -> release some memory
|
||||
// -> required for some external solvers
|
||||
m_matrix.makeCompressed();
|
||||
return m_matrix;
|
||||
}
|
||||
|
||||
public:
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
friend Eigen_sparse_matrix
|
||||
operator*(const T& c, const Eigen_sparse_matrix& M)
|
||||
{
|
||||
return Eigen_sparse_matrix(c* M.eigen_object());
|
||||
}
|
||||
|
||||
friend Eigen_sparse_matrix
|
||||
operator+(const Eigen_sparse_matrix& M0, const Eigen_sparse_matrix& M1)
|
||||
{
|
||||
return Eigen_sparse_matrix(M0.eigen_object()+ M1.eigen_object());
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
// Fields
|
||||
private:
|
||||
mutable bool m_is_already_built;
|
||||
|
||||
typedef Eigen::Triplet<T,int> Triplet;
|
||||
mutable std::vector<Triplet> m_triplets;
|
||||
|
||||
mutable EigenType m_matrix;
|
||||
|
||||
// Symmetric/hermitian?
|
||||
bool m_is_symmetric;
|
||||
}; // Eigen_sparse_matrix
|
||||
|
||||
|
||||
/*!
|
||||
\ingroup PkgSolverInterfaceRef
|
||||
|
||||
The class `Eigen_sparse_symmetric_matrix` is a wrapper around `Eigen` matrix type
|
||||
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html">`Eigen::SparseMatrix` </a>
|
||||
|
||||
Since the matrix is symmetric, only the lower triangle part is stored.
|
||||
|
||||
\cgalModels `SparseLinearAlgebraTraits_d::Matrix`
|
||||
|
||||
\tparam T Number type.
|
||||
|
||||
\sa `CGAL::Eigen_vector<T>`
|
||||
\sa `CGAL::Eigen_sparse_matrix<T>`
|
||||
*/
|
||||
template<class T>
|
||||
struct Eigen_sparse_symmetric_matrix
|
||||
: public Eigen_sparse_matrix<T>
|
||||
{
|
||||
/// Create a square *symmetric* matrix initialized with zeros.
|
||||
Eigen_sparse_symmetric_matrix(int dim) ///< Matrix dimension.
|
||||
: Eigen_sparse_matrix<T>(dim, true /* symmetric */)
|
||||
{ }
|
||||
|
||||
/// Create a square *symmetric* matrix initialized with zeros.
|
||||
///
|
||||
/// \pre rows == columns.
|
||||
Eigen_sparse_symmetric_matrix(int rows, ///< Number of rows.
|
||||
int columns) ///< Number of columns.
|
||||
: Eigen_sparse_matrix<T>(rows, columns, true /* symmetric */)
|
||||
{ }
|
||||
};
|
||||
|
||||
} //namespace CGAL
|
||||
|
||||
#endif // CGAL_SOLVER_INTERFACE_EIGEN_SPARSE_MATRIX_H
|
||||
|
|
@ -33,9 +33,9 @@ which is a simple array of numbers.
|
|||
\sa `CGAL::Eigen_sparse_symmetric_matrix<T>`
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
template<class T, int D = ::Eigen::Dynamic>
|
||||
class Eigen_vector
|
||||
: public Eigen::Matrix<T, Eigen::Dynamic, 1>
|
||||
: public ::Eigen::Matrix<T, D, 1>
|
||||
{
|
||||
// Public types
|
||||
public:
|
||||
|
|
@ -44,23 +44,23 @@ public:
|
|||
typedef T NT;
|
||||
|
||||
/// The internal vector type from \ref thirdpartyEigen "Eigen".
|
||||
typedef Eigen::Matrix<T, Eigen::Dynamic, 1> EigenType;
|
||||
typedef ::Eigen::Matrix<T, D, 1> EigenType;
|
||||
/// @}
|
||||
|
||||
// Public operations
|
||||
public:
|
||||
Eigen_vector<T>& operator=(const Eigen_vector<T>& other)
|
||||
Eigen_vector& operator=(const Eigen_vector& other)
|
||||
{
|
||||
return static_cast<EigenType&>(*this) = other.eigen_object();
|
||||
}
|
||||
|
||||
Eigen_vector<T>& operator=(const EigenType& other)
|
||||
Eigen_vector& operator=(const EigenType& other)
|
||||
{
|
||||
return static_cast<Eigen_vector<T>&>(static_cast<EigenType&>(*this) = other);
|
||||
return static_cast<Eigen_vector&>(static_cast<EigenType&>(*this) = other);
|
||||
}
|
||||
Eigen_vector()
|
||||
: EigenType()
|
||||
{}
|
||||
|
||||
/// Constructs a null vector.
|
||||
Eigen_vector() : EigenType() {}
|
||||
|
||||
/// Create a vector initialized with zeros.
|
||||
Eigen_vector(std::size_t dimension)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include <CGAL/utility.h>
|
||||
#include <CGAL/Object.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
#include <CGAL/internal/Has_nested_type_Bare_point.h>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
|
@ -34,6 +33,7 @@
|
|||
|
||||
#include <boost/iterator/zip_iterator.hpp>
|
||||
#include <boost/mpl/and.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
|
||||
#endif //CGAL_TRIANGULATION_2_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO
|
||||
|
||||
|
|
@ -414,12 +414,12 @@ public:
|
|||
// spatial sorting must use bare points, so we need an adapter
|
||||
typedef typename Geom_traits::Construct_point_2 Construct_point_2;
|
||||
typedef typename boost::result_of<const Construct_point_2(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_2, Weighted_point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_2, Weighted_point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_2<Geom_traits, fpmap> Search_traits_2;
|
||||
|
||||
spatial_sort(points.begin(), points.end(),
|
||||
Search_traits_2(
|
||||
CGAL::internal::boost_::make_function_property_map<Weighted_point, Ret, Construct_point_2>(
|
||||
boost::make_function_property_map<Weighted_point, Ret, Construct_point_2>(
|
||||
geom_traits().construct_point_2_object()), geom_traits()));
|
||||
|
||||
Face_handle hint;
|
||||
|
|
@ -482,13 +482,13 @@ private:
|
|||
typedef Index_to_Bare_point<Construct_point_2,
|
||||
std::vector<Weighted_point> > Access_bare_point;
|
||||
typedef typename boost::result_of<const Construct_point_2(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef boost::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_2<Gt, fpmap> Search_traits_2;
|
||||
|
||||
Access_bare_point accessor(points, geom_traits().construct_point_2_object());
|
||||
spatial_sort(indices.begin(), indices.end(),
|
||||
Search_traits_2(
|
||||
CGAL::internal::boost_::make_function_property_map<
|
||||
boost::make_function_property_map<
|
||||
std::size_t, Ret, Access_bare_point>(accessor),
|
||||
geom_traits()));
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@
|
|||
#include <CGAL/Spatial_sort_traits_adapter_2.h>
|
||||
|
||||
#include <CGAL/double.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
|
|
|
|||
|
|
@ -25,10 +25,9 @@
|
|||
#include <CGAL/spatial_sort.h>
|
||||
#include <CGAL/Spatial_sort_traits_adapter_2.h>
|
||||
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/random/geometric_distribution.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
|
|
@ -130,12 +129,12 @@ public:
|
|||
// Spatial sort can only be used with Gt::Point_2: we need an adapter
|
||||
typedef typename Geom_traits::Construct_point_2 Construct_point_2;
|
||||
typedef typename boost::result_of<const Construct_point_2(const Point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_2, Point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_2, Point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_2<Geom_traits, fpmap> Search_traits_2;
|
||||
|
||||
spatial_sort(points.begin(), points.end(),
|
||||
Search_traits_2(
|
||||
CGAL::internal::boost_::make_function_property_map<Point, Ret, Construct_point_2>(
|
||||
boost::make_function_property_map<Point, Ret, Construct_point_2>(
|
||||
geom_traits().construct_point_2_object()), geom_traits()));
|
||||
|
||||
// hints[i] is the face of the previously inserted point in level i.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ fills the face graph `tm` with the <A HREF="https://en.wikipedia.org/wiki/Simpli
|
|||
if `vh` is on the convex hull of the triangulation, and if `no_infinite_faces == false`.
|
||||
Otherwise, an arbitrary vertex descriptor of the triangle mesh `tm`.
|
||||
|
||||
\sa `convex_hull_3_to_polyhedron_3()`
|
||||
\sa `convex_hull_3_to_face_graph()`
|
||||
|
||||
*/
|
||||
template <class Triangulation, class TriangleMesh>
|
||||
|
|
|
|||
|
|
@ -22,13 +22,6 @@
|
|||
|
||||
#include <CGAL/basic.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
# include <CGAL/point_generators_3.h>
|
||||
# include <tbb/parallel_for.h>
|
||||
|
|
@ -41,7 +34,6 @@
|
|||
#include <CGAL/Regular_triangulation_vertex_base_3.h>
|
||||
#include <CGAL/Regular_triangulation_cell_base_3.h>
|
||||
#include <CGAL/internal/Has_nested_type_Bare_point.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <CGAL/Cartesian_converter.h>
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
|
|
@ -63,6 +55,20 @@
|
|||
#include <CGAL/point_generators_3.h>
|
||||
#endif
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace CGAL {
|
||||
|
||||
/************************************************
|
||||
|
|
@ -269,12 +275,12 @@ private:
|
|||
// Spatial sorting can only be applied to bare points, so we need an adaptor
|
||||
typedef typename Geom_traits::Construct_point_3 Construct_point_3;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
spatial_sort(points_on_far_sphere.begin(), points_on_far_sphere.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
boost::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
geom_traits().construct_point_3_object()), geom_traits()));
|
||||
|
||||
typename std::vector<Weighted_point>::const_iterator it_p =
|
||||
|
|
@ -341,12 +347,12 @@ public:
|
|||
// kernel creates temporaries and prevent it.
|
||||
typedef typename Geom_traits::Construct_point_3 Construct_point_3;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_3, Weighted_point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
spatial_sort(points.begin(), points.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
boost::make_function_property_map<Weighted_point, Ret, Construct_point_3>(
|
||||
geom_traits().construct_point_3_object()), geom_traits()));
|
||||
|
||||
// Parallel
|
||||
|
|
@ -466,14 +472,14 @@ private:
|
|||
typedef Index_to_Bare_point<Construct_point_3,
|
||||
std::vector<Weighted_point> > Access_bare_point;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Weighted_point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef boost::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Gt, fpmap> Search_traits_3;
|
||||
|
||||
Access_bare_point accessor(points, geom_traits().construct_point_3_object());
|
||||
spatial_sort(indices.begin(), indices.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<
|
||||
std::size_t, Ret, Access_bare_point>(accessor),
|
||||
boost::make_function_property_map<
|
||||
std::size_t, Ret, Access_bare_point>(accessor),
|
||||
geom_traits()));
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@
|
|||
#include <CGAL/function_objects.h>
|
||||
#include <CGAL/Iterator_project.h>
|
||||
#include <CGAL/Default.h>
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Spatial_lock_grid_3.h>
|
||||
|
|
@ -57,6 +56,7 @@
|
|||
#include <boost/random/uniform_smallint.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
|
@ -6664,12 +6664,12 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover& rem
|
|||
// Spatial sorting can only be applied to bare points, so we need an adaptor
|
||||
typedef typename Geom_traits::Construct_point_3 Construct_point_3;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_3, Point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_3, Point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
spatial_sort(vps.begin(), vps.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<Point, Ret, Construct_point_3>(
|
||||
boost::make_function_property_map<Point, Ret, Construct_point_3>(
|
||||
geom_traits().construct_point_3_object()), geom_traits()));
|
||||
|
||||
std::size_t svps = vps.size();
|
||||
|
|
|
|||
|
|
@ -33,8 +33,7 @@
|
|||
#include <CGAL/Triangulation_hierarchy_vertex_base_3.h>
|
||||
#include <CGAL/Location_policy.h>
|
||||
|
||||
#include <CGAL/internal/boost/function_property_map.hpp>
|
||||
|
||||
#include <boost/property_map/function_property_map.hpp>
|
||||
#include <boost/random/linear_congruential.hpp>
|
||||
#include <boost/random/geometric_distribution.hpp>
|
||||
#include <boost/random/variate_generator.hpp>
|
||||
|
|
@ -169,12 +168,12 @@ public:
|
|||
// Spatial sort can only be used with Geom_traits::Point_3: we need an adapter
|
||||
typedef typename Geom_traits::Construct_point_3 Construct_point_3;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Construct_point_3, Point, Ret> fpmap;
|
||||
typedef boost::function_property_map<Construct_point_3, Point, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
spatial_sort(points.begin(), points.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<Point, Ret, Construct_point_3>(
|
||||
boost::make_function_property_map<Point, Ret, Construct_point_3>(
|
||||
geom_traits().construct_point_3_object()), geom_traits()));
|
||||
|
||||
// hints[i] is the vertex of the previously inserted point in level i.
|
||||
|
|
@ -246,13 +245,13 @@ private:
|
|||
typedef Index_to_Bare_point<Construct_point_3,
|
||||
std::vector<Point> > Access_bare_point;
|
||||
typedef typename boost::result_of<const Construct_point_3(const Point&)>::type Ret;
|
||||
typedef CGAL::internal::boost_::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef boost::function_property_map<Access_bare_point, std::size_t, Ret> fpmap;
|
||||
typedef CGAL::Spatial_sort_traits_adapter_3<Geom_traits, fpmap> Search_traits_3;
|
||||
|
||||
Access_bare_point accessor(points, geom_traits().construct_point_3_object());
|
||||
spatial_sort(indices.begin(), indices.end(),
|
||||
Search_traits_3(
|
||||
CGAL::internal::boost_::make_function_property_map<
|
||||
boost::make_function_property_map<
|
||||
std::size_t, Ret, Access_bare_point>(accessor),
|
||||
geom_traits()));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue