Merge branch 'CGAL-Optimal_bounding_box-GF-old' into CGAL-Optimal_bounding_box-GF

This commit is contained in:
Mael Rouxel-Labbé 2019-12-03 16:28:19 +01:00
commit edefc616f3
38 changed files with 20890 additions and 0 deletions

View File

@ -0,0 +1,29 @@
# 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()
else()
include(${EIGEN3_USE_FILE})
endif()
create_single_source_cgal_program("bench_obb.cpp")
create_single_source_cgal_program("bench_perfomance.cpp")
create_single_source_cgal_program("bench_custom.cpp")
create_single_source_cgal_program("bench_fitness_function.cpp")

View File

@ -0,0 +1,64 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/optimal_bounding_box.h>
#include <CGAL/subdivision_method_3.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <fstream>
#include <vector>
//#define CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
void bench(const char* fname)
{
std::vector<K::Point_3> sm_points, obb_points;
std::ifstream in(fname);
K::Point_3 p;
int i = 0;
while(in >> p)
{
if(i % 2 == 0) // avoid normals
sm_points.push_back(p);
++i;
}
std::cout << "input data (points + normals)= " << i << std::endl;
std::cout << "number of points= " << sm_points.size() << std::endl;
CGAL::Eigen_linear_algebra_traits la_traits;
// use convex hull - > true
// no convex hull - > false
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(sm_points, obb_points, la_traits, false);
std::cout << "done" << '\n';
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
std::cout.precision(17);
for(int i =0; i < obb_points.size(); i++)
std::cout << obb_points[i] << std::endl;
CGAL::Surface_mesh<K::Point_3> mesh;
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], mesh);
std::ofstream out("/tmp/result_obb.off");
out << mesh;
out.close();
#endif
}
int main(int argc, char* argv[])
{
bench(argv[1]);
return 0;
}

View File

@ -0,0 +1,64 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/fitness_function.h>
#include <CGAL/Optimal_bounding_box/helper.h>
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/subdivision_method_3.h>
#include <CGAL/Timer.h>
#include <fstream>
#include <iostream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
int main()
{
const char* fname = "data/elephant.off";
// 1) import a lot a mesh and subdivide it to create a big mesh
std::ifstream input(fname);
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty())
{
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
CGAL::Subdivision_method_3::CatmullClark_subdivision(mesh,
CGAL::parameters::number_of_iterations(6));
int nb_points = static_cast<int>(vertices(mesh).size());
std::cout << "number of points= " << nb_points << std::endl;
// 2) fill a Matrix with them
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
typedef Linear_algebra_traits::MatrixX3d MatrixX3d;
typedef Linear_algebra_traits::Matrix3d Matrix3d;
MatrixX3d points_mat(nb_points, 3);
CGAL::Optimal_bounding_box::sm_to_matrix(mesh, points_mat);
// 3) create a population of simplices
CGAL::Optimal_bounding_box::Population<Linear_algebra_traits> pop(50);
CGAL::Timer timer;
timer.start();
// 4) compute fitness of population via the Fitness map
CGAL::Optimal_bounding_box::Fitness_map<Linear_algebra_traits,
Matrix3d, MatrixX3d> fit_map(pop, points_mat);
double result = fit_map.get_best_fitness_value();
timer.stop();
std::cout << "took " << timer.time() << " to compute the fitness of all vertices.\n";
std::cout << "value of fittest vertex= " << result << std::endl;
return 0;
}

View File

@ -0,0 +1,115 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polyhedron_3.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/Optimal_bounding_box/optimal_bounding_box.h>
#include <CGAL/convex_hull_3.h>
#include <CGAL/Timer.h>
#include <iostream>
#include <fstream>
//#define CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
bool assert_doubles(double d1, double d2, double epsilon)
{
return (d1 < d2 + epsilon && d1 > d2 - epsilon) ? true : false;
}
template <typename SurfaceMesh, typename Point>
void gather_mesh_points(SurfaceMesh& mesh, std::vector<Point>& points)
{
typedef typename boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<SurfaceMesh, CGAL::vertex_point_t>::type PointPMap;
PointPMap pmap = get(boost::vertex_point, mesh);
BOOST_FOREACH(vertex_descriptor v, vertices(mesh))
points.push_back(get(pmap, v));
}
template <typename Point>
double calculate_volume(std::vector<Point> points)
{
CGAL::Bbox_3 bbox;
bbox = bbox_3(points.begin(), points.end());
K::Iso_cuboid_3 ic(bbox);
return ic.volume();
}
void bench_finding_obb(std::string fname)
{
std::ifstream input(fname);
CGAL::Eigen_linear_algebra_traits la_traits;
std::vector<K::Point_3> sm_points;
// import a mesh
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty())
{
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
// get mesh points
gather_mesh_points(mesh, sm_points);
CGAL::Timer timer;
// 1) measure convex hull calculation
timer.start();
CGAL::Polyhedron_3<K> poly;
convex_hull_3(sm_points.begin(), sm_points.end(), poly);
std::vector<K::Point_3> ch_points(poly.points_begin(), poly.points_end());
timer.stop();
std::cout << "takes : " << timer.time() << " seconds to find the convex hull\n";
// 2) using convex hull
timer.reset();
timer.start();
std::vector<K::Point_3> obb_points1;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(sm_points, obb_points1, la_traits, true);
timer.stop();
std::cout << "found obb using convex hull: " << timer.time() << " seconds\n";
// 3) without convex hull
timer.reset();
timer.start();
std::vector<K::Point_3> obb_points2;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(sm_points, obb_points2, la_traits, false);
timer.stop();
std::cout << "found obb without convex hull: " << timer.time() << " seconds\n";
timer.reset();
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
CGAL::Surface_mesh<K::Point_3> 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);
CGAL::Surface_mesh<K::Point_3> 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::ofstream out1("data/obb_result1.off");
out1 << result_mesh1;
out1.close();
std::ofstream out2("data/obb_result2.off");
out2 << result_mesh2;
out2.close();
#endif
}
int main()
{
bench_finding_obb("data/elephant.off");
return 0;
}

View File

@ -0,0 +1,85 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/optimal_bounding_box.h>
#include <CGAL/subdivision_method_3.h>
#include <CGAL/Timer.h>
#include <fstream>
#include <iostream>
//#define CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
void bench_finding_obb(std::string fname)
{
std::ifstream input(fname);
// import a mesh
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty())
{
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
// export some times
std::ofstream outt("data/times.txt");
outt << "nb_vertices "<< "with_ch " << "without_ch" << std::endl;
CGAL::Timer timer;
std::size_t measurements = 4;
CGAL::Eigen_linear_algebra_traits la_traits;
for (std::size_t t = 0; t < measurements; ++t)
{
std::cout << "#vertices= " << vertices(mesh).size() << " |";
// 1) using convex hull
timer.start();
CGAL::Surface_mesh<K::Point_3> obb_mesh1;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(mesh, obb_mesh1, la_traits, true);
timer.stop();
double t_ch = timer.time();
std::cout << " with ch: " << timer.time() << " s |";
// 2) without convex hull
timer.reset();
timer.start();
CGAL::Surface_mesh<K::Point_3> obb_mesh2;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(mesh, obb_mesh2, la_traits, false);
timer.stop();
double t_no_ch = timer.time();
std::cout << " without ch: " << timer.time() << " s\n";
timer.reset();
outt << vertices(mesh).size() << " " << t_ch << " " << t_no_ch << std::endl;
// 3) subdivision
CGAL::Subdivision_method_3::CatmullClark_subdivision(mesh,
CGAL::parameters::number_of_iterations(1));
}
outt.close();
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_BENCHMARK
std::ofstream out1("data/obb_result1.off");
out1 << obb_points1;
out1.close();
std::ofstream out2("data/obb_result2.off");
out2 << obb_points2;
out2.close();
#endif
}
int main()
{
bench_finding_obb("data/elephant.off");
return 0;
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
nb_vertices with_ch without_ch
2775 0.037331 0.327787
16670 0.118251 1.96901
66692 0.362664 7.75459
266780 1.20984 32.166

View File

@ -0,0 +1,19 @@
import matplotlib.pyplot as plt
import numpy as np
#path-to-benchmarks
benchmarkfile='data/times.txt'
data = np.loadtxt(benchmarkfile, skiprows = 1)
x = data[:, 0]
y1 = data[:, 1]
y2 = data[:, 2]
plt.plot(x, y1, 'go--', label='with convex hull')
plt.plot(x, y2, 'ro--', label='without convex hull')
legend = plt.legend(loc='best')
plt.xlabel('#vertices')
plt.ylabel('seconds')
plt.show()

View File

@ -0,0 +1 @@
To draw a graph with the benchmark times set the path-to-the-measurments in draw_benchmark_times.py if necessary, and run the script with python 3.

View File

@ -0,0 +1,6 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Optimal Bounding Box"
EXTRACT_ALL = false
HIDE_UNDOC_CLASSES = true
WARN_IF_UNDOCUMENTED = false

View File

@ -0,0 +1,315 @@
/*!
\defgroup pmp_namedparameters Named Parameters for Polygon Mesh Processing
\ingroup PkgPolygonMeshProcessing
In this package, all functions optional parameters are implemented as BGL optional
named parameters (see \ref BGLNamedParameters for more information on how to use them).
Since the parameters of the various polygon mesh processing 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 polygon mesh processing 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 PkgBGLSummary
(see \ref bgl_namedparameters), are used in this package:
\cgalNPTableBegin
\cgalNPBegin{vertex_point_map} \anchor PMP_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{vertex_index_map} \anchor PMP_vertex_index_map
is the property map containing the index of each vertex of the input polygon mesh.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and the value type
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::vertex_index_t>::type>::value_type \endcode
<b>Default:</b> \code boost::get(CGAL::vertex_index, pmesh)\endcode
\cgalNPEnd
\cgalNPBegin{face_index_map} \anchor PMP_face_index_map
is the property map containing the index of each face of the input polygon mesh.\n
<b>Type:</b> a class model of `ReadablePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and the value type:
\code typename boost::property_traits<typename boost::property_map<PolygonMesh, CGAL::face_index_t>::type>::value_type \endcode
<b>Default:</b> \code boost::get(CGAL::face_index, pmesh)\endcode
If this internal property map exists, its values should be initialized.
\cgalNPEnd
\cgalNPBegin{edge_is_constrained_map} \anchor PMP_edge_is_constrained_map
is the property map containing information about edges of the input polygon mesh
being marked or not. In `isotropic_remeshing()` and `connected_components()`,
the marked edges are constrained.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%edge_descriptor` as key type and
`bool` as value type. It should be default constructible.\n
<b>Default:</b> a default property map where no edge is constrained
\cgalNPEnd
\cgalNPTableEnd
In addition to these named parameters, this package offers the following named parameters:
\cgalNPTableBegin
\cgalNPBegin{geom_traits} \anchor PMP_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{vertex_incident_patches_map} \anchor PMP_vertex_incident_patches_map
is the property map containing the surface patches incident to each vertex of the input polygon mesh.\n
<b>Type:</b> a class model of `LvaluePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type. Its value type
must be a container of `boost::property_traits<PatchIdMap>::%value_type` and have a function `insert()`.
A `std::set` or a `boost::unordered_set` are recommended, as a patch index may be
inserted several times.\n
<b>Default:</b> \code boost::get(CGAL::vertex_incident_patches_t, pmesh)\endcode
\cgalNPEnd
\cgalNPBegin{vertex_feature_degree_map} \anchor PMP_vertex_feature_degree_map
is the property map containing the number of feature edges being incident to the vertices of the polygon mesh `pmesh`.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
`int` as value type. It should be default constructible.\n
<b>Default:</b> \code boost::get(CGAL::vertex_feature_degree_t(), pmesh) \endcode
\cgalNPEnd
\cgalNPBegin{vertex_is_constrained_map} \anchor PMP_vertex_is_constrained_map
is the property map containing information about vertices of the input polygon mesh being constrained or not.
Constrained vertices may be replaced by new vertices, but the number and location
of vertices remain unchanged.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%vertex_descriptor` as key type and
`bool` as value type. It should be default constructible.\n
<b>Default:</b> a default property map where no vertex is constrained is provided.
\cgalNPEnd
\cgalNPBegin{face_patch_map} \anchor PMP_face_patch_map
is a property map containing information about faces.
It is particularly well-suited for preserving surface patch IDs,
or face colors.
The edges at the interface between surface patches are treated similarly
to the ones of `edge_is_constrained_map`.\n
<b>Type:</b> a class model of `ReadWritePropertyMap` with
`boost::graph_traits<PolygonMesh>::%face_descriptor` as key type and
the desired property, model of `CopyConstructible` as value type.\n
<b>Default:</b> a default property map where each face is associated with the ID of
the connected component it belongs to. Connected components are
computed with respect to the constrained edges listed in the property map
`edge_is_constrained_map`
\cgalNPEnd
\cgalNPBegin{first_index} \anchor PMP_first_index
is the index of the first surface patch.\n
<b>Type:</b> `std::size_t`\n
<b>Default:</b> 1
\cgalNPEnd
\cgalNPBegin{density_control_factor} \anchor PMP_density_control_factor
controls the density of the mesh generated by refinement, with larger values causing denser refinements.
The density of vertices in the refined region is this factor times higher than before refinement.\n
<b>Type:</b> floating scalar value\n
<b>Default:</b> `CGAL::sqrt(2)`
\cgalNPEnd
\cgalNPBegin{fairing_continuity} \anchor PMP_fairing_continuity
controls the tangential continuity of the output surface in `fair()`.
The possible values are 0, 1 and 2, refering to the C<sup>0</sup>, C<sup>1</sup>
and C<sup>2</sup> continuity.\n
<b>Type:</b> \c unsigned \c int between 0 and 2\n
<b>Default:</b> `1`
\cgalNPEnd
\cgalNPBegin{sparse_linear_solver} \anchor PMP_sparse_linear_solver
is the solver used in `fair()`.\n
<b>Type:</b> a class model of `SparseLinearAlgebraWithFactorTraits_d`.\n
<b>Default:</b> if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and
`CGAL_EIGEN3_ENABLED` is defined, then the following overload of `Eigen_solver_traits`
is provided as default value:\n
\code CGAL::Eigen_solver_traits<Eigen::SparseLU<CGAL::Eigen_sparse_matrix<double>::EigenType, Eigen::COLAMDOrdering<int> > > \endcode
\cgalNPEnd
\cgalNPBegin{number_of_iterations} \anchor PMP_number_of_iterations
is the number of iterations of the sequence of iterations performed in `isotropic_remeshing()`.\n
<b>Type:</b> \c unsigned \c int \n
<b>Default:</b> `1`
\cgalNPEnd
\cgalNPBegin{protect_constraints} \anchor PMP_protect_constraints
enables the protection of constraints listed by \ref PMP_edge_is_constrained_map
"edge_is_constrained_map" and boundary edges
in `isotropic_remeshing()`. If `true`, constraint edges cannot be modified at all
during the remeshing process.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `false`
\cgalNPEnd
\cgalNPBegin{relax_constraints} \anchor PMP_relax_constraints
enables the tangential relaxation step in `isotropic_remeshing()`
to be performed on vertices that are endpoints of constraints listed
by \ref PMP_edge_is_constrained_map "edge_is_constrained_map", and boundary edges.
The vertices move along the constrained polylines they belong to.
Corners (i.e. vertices incident to more than 2 constraints, and vertices listed in
\ref PMP_vertex_is_constrained_map "vertex_is_constrained_map") are not allowed
to move at all.
If \ref PMP_protect_constraints "protect_constraints" is
set to `true`, this parameter is ignored.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{number_of_relaxation_steps} \anchor PMP_number_of_relaxation_steps
is the number of iterations of tangential relaxation that are performed at each iteration
of `isotropic_remeshing()`. A larger number of relaxation steps lead to
a more isotropic mesh.\n
<b>Type:</b> \c unsigned \c int \n
<b>Default:</b> `1`
\cgalNPEnd
\cgalNPBegin{use_delaunay_triangulation} \anchor PMP_use_delaunay_triangulation
enables the use of the Delaunay triangulation facet search space for hole filling functions.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{use_random_uniform_sampling} \anchor PMP_use_random_uniform_sampling
is a parameter used in `sample_triangle_mesh()` to indicate if points should be picked
in a random uniform way.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{use_grid_sampling} \anchor PMP_use_grid_sampling
is a parameter used in `sample_triangle_mesh()` to indicate if points should be picked
in on a grid in each face.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `false`
\cgalNPEnd
\cgalNPBegin{use_monte_carlo_sampling} \anchor PMP_use_monte_carlo_sampling
is a parameter used in `sample_triangle_mesh()` to indicate if points should be picked
using a Monte-Carlo approach.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `false`
\cgalNPEnd
\cgalNPBegin{sample_edges} \anchor PMP_sample_edges
is a parameter used in `sample_triangle_mesh()` to indicate if a dedicated sampling
of edges should be done.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{sample_vertices} \anchor PMP_sample_vertices
is a parameter used in `sample_triangle_mesh()` to indicate if triangle vertices should
be copied in the output iterator.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{sample_faces} \anchor PMP_sample_faces
is a parameter used in `sample_triangle_mesh()` to indicate if the interior of faces
should be considered for the sampling.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{number_of_points_on_faces} \anchor PMP_number_of_points_on_faces
is a parameter used in `sample_triangle_mesh()` to set the number of points picked
using the random uniform method on faces.\n
<b>Type:</b> `std::size_t` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{number_of_points_on_edges} \anchor PMP_number_of_points_on_edges
is a parameter used in `sample_triangle_mesh()` to set the number of points picked
using the random uniform method on edges.\n
<b>Type:</b> `std::size_t` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{number_of_points_per_face} \anchor PMP_number_of_points_per_face
is a parameter used in `sample_triangle_mesh()` to set the number of points picked
per face using the Monte-Carlo method.\n
<b>Type:</b> `std::size_t` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{number_of_points_per_edge} \anchor PMP_number_of_points_per_edge
is a parameter used in `sample_triangle_mesh()` to set the number of points picked
per edge using the Monte-Carlo method.\n
<b>Type:</b> `std::size_t` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{grid_spacing} \anchor PMP_grid_spacing
is a parameter used in `sample_triangle_mesh()` to set the grid spacing when using
the grid sampling method.\n
<b>Type:</b> `double` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{number_of_points_per_area_unit} \anchor PMP_number_of_points_per_area_unit
is a parameter used in `sample_triangle_mesh()` to set the number of points per
area unit to be picked up in faces for the random uniform sampling and
Monte-Carlo methods.\n
<b>Type:</b> `double` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{number_of_points_per_distance_unit} \anchor PMP_number_of_points_per_distance_unit
is a parameter used in `sample_triangle_mesh()` to set the number of points per
distance unit to be picked up on edges for the random uniform sampling and
Monte-Carlo methods.\n
<b>Type:</b> `double` \n
<b>Default:</b> `0`
\cgalNPEnd
\cgalNPBegin{do_project} \anchor PMP_do_project
is a parameter used in `random_perturbation()` to set whether vertices should be re-projected
to the input surface after their geometric perturbation.\n
<b>Type:</b> `bool` \n
<b>Default:</b> `true`
\cgalNPEnd
\cgalNPBegin{random_seed} \anchor PMP_random_seed
is a parameter used in `random_perturbation()` to choose a seed to initialize
the random number generator `CGAL::Random()`.
If this parameter is not provided, the perturbation is not deterministic
(i.e. not reproducible from one run to the other).\n
<b>Type:</b> `unsigned int` \n
<b>Default:</b> the random number generator is initialized with `CGAL::Random()`
\cgalNPEnd
\cgalNPBegin{outward_orientation} \anchor PMP_outward_orientation
Parameter used in orientation functions to choose between an outward or inward orientation.
\n
\b Type : `bool` \n
\b Default value is `true`
\cgalNPBegin{do_overlap_test_of_bounded_sides} \anchor PMP_do_overlap_test_of_bounded_sides
Parameter used in intersection test functions to indicate whether overlapping tests of bounded sides
of close meshes should be done in addition to surface intersection tests.
\n
\b Type : `bool` \n
\b Default value is `false`
\cgalNPEnd
\cgalNPTableEnd
*/

View File

@ -0,0 +1,9 @@
namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_OptimalBoundingBox
\cgalAutoToc
\authors
} /* namespace CGAL */

View File

@ -0,0 +1,30 @@
/// \defgroup PkgOptimalBoundingBox Optimal Bounding Box Reference
/// \defgroup PkgOptimalBoundingBoxConcepts Concepts
/// \ingroup PkgOptimalBoundingBox
\cgalPkgDescriptionBegin{Optimal Bounding Box, PkgOptimalBoundingBoxSummary}
\cgalPkgPicture{}
\cgalPkgSummaryBegin
\cgalPkgAuthor{}
\cgalPkgDesc{This package provides stuff.}
\cgalPkgManuals{Chapter_OptimalBoundingBox,PkgOptimalBoundingBox}
\cgalPkgSummaryEnd
\cgalPkgShortInfoBegin
\cgalPkgSince{5.2}
\cgalPkgDependsOn{documented for each function;}
\cgalPkgBib{cgal:lty-pmp}
\cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgDemo{Polyhedron demo,polyhedron_3.zip}
\cgalPkgShortInfoEnd
\cgalPkgDescriptionEnd
\cgalClassifedRefPages
## Parameters ##
## Functions ##
*/

View File

@ -0,0 +1,14 @@
Manual
Kernel_23
STL_Extension
Algebraic_foundations
Circulator
Stream_support
Polyhedron
BGL
Solver_interface
Surface_mesh
Surface_mesh_deformation
AABB_tree
Triangulation_2
Spatial_sorting

View File

@ -0,0 +1,4 @@
/*!
\example Optimal_bounding_box/example_todo.cpp
*/

View File

@ -0,0 +1,24 @@
# 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()
else()
include(${EIGEN3_USE_FILE})
endif()
create_single_source_cgal_program("example.cpp")

View File

@ -0,0 +1,252 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H
#define CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/Optimal_bounding_box/nelder_mead_functions.h>
#include <CGAL/Optimal_bounding_box/fitness_function.h>
#include <CGAL/Random.h>
#include <CGAL/number_utils.h>
#include <algorithm>
#include <iostream>
#include <vector>
namespace CGAL {
namespace Optimal_bounding_box {
template <typename Linear_algebra_traits>
class Evolution
{
typedef typename Linear_algebra_traits::MatrixXd MatrixXd;
typedef typename Linear_algebra_traits::Matrix3d Matrix3d;
typedef typename Linear_algebra_traits::Vector3d Vector3d;
public:
Evolution(Population<Linear_algebra_traits>& pop, MatrixXd& points)
: population(pop), point_data(points)
{}
void genetic_algorithm()
{
// random permutations
std::size_t m = population.size();
//groups 1,2 : size m/2 groups 3,4 : size (m - m/2). m/2 is floored
std::size_t size_first_group = m/2;
std::size_t size_second_group = m - m/2;
std::vector<std::size_t> ids1(m/2), ids2(m/2);
std::vector<std::size_t> ids3(m - m/2), ids4(m - m/2);
CGAL::Random rng;
int im = static_cast<int>(m);
std::generate(ids1.begin(), ids1.end(),
[&rng, &im] () { return rng.get_int(0, im); });
std::generate(ids2.begin(), ids2.end(),
[&rng, &im] () { return rng.get_int(0, im); });
std::generate(ids3.begin(), ids3.end(),
[&rng, &im] () { return rng.get_int(0, im); });
std::generate(ids4.begin(), ids4.end(),
[&rng, &im] () { return rng.get_int(0, im); });
Population<Linear_algebra_traits> group1(m/2), group2(m/2);
Population<Linear_algebra_traits> group3(m - m/2), group4(m - m/2);
for(std::size_t i = 0; i < ids1.size(); ++i)
group1[i] = population[ids1[i]];
for(std::size_t i = 0; i < ids2.size(); ++i)
group2[i] = population[ids2[i]];
for(std::size_t i = 0; i < ids3.size(); ++i)
group3[i] = population[ids3[i]];
for(std::size_t i = 0; i < ids4.size(); ++i)
group4[i] = population[ids4[i]];
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
check_det(group1);
check_det(group2);
check_det(group3);
check_det(group4);
#endif
// crossover I
Population<Linear_algebra_traits> offspringsA(size_first_group);
double bias = 0.1;
for(std::size_t i = 0; i < size_first_group; ++i)
{
std::vector<Matrix3d> offspring(4);
for(int j = 0; j < 4; ++j)
{
double r = rng.get_double();
double fitnessA = compute_fitness<Linear_algebra_traits>(group1[i][j], point_data);
double fitnessB = compute_fitness<Linear_algebra_traits>(group2[i][j], point_data);
double threshold;
if(fitnessA < fitnessB)
threshold = 0.5 + bias;
else
threshold = 0.5 - bias;
if(r < threshold) // choose A
offspring[j] = group1[i][j];
else // choose B
offspring[j] = group2[i][j];
}
offspringsA[i] = offspring;
}
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
std::cout << "offspringsA: \n" ;
check_det(offspringsA);
#endif
// crossover II
Population<Linear_algebra_traits> offspringsB(size_second_group);
bias = 0.1;
for(std::size_t i = 0; i < size_second_group; ++i)
{
std::vector<Matrix3d> offspring(4);
for(int j = 0; j < 4; ++j)
{
double fitnessA = compute_fitness<Linear_algebra_traits>(group3[i][j], point_data);
double fitnessB = compute_fitness<Linear_algebra_traits>(group4[i][j], point_data);
double lambda;
if(fitnessA < fitnessB)
lambda = 0.5 + bias;
else
lambda = 0.5 - bias;
// combine information from A and B
offspring[j] = lambda * group3[i][j] + lambda * group4[i][j];
}
// qr factorization of the offspring
Linear_algebra_traits::qr_factorization(offspring);
offspringsB[i] = offspring;
}
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
std::cout << "offspringsB: \n" ;
check_det(offspringsB);
#endif
CGAL_assertion(offspringsA.size() == size_first_group);
CGAL_assertion(offspringsB.size() == size_second_group);
CGAL_assertion(offspringsA.size() + offspringsB.size() == population.size());
// next generatrion
for(std::size_t i = 0; i < size_first_group; ++i)
population[i] = offspringsA[i];
for(std::size_t i = 0; i < size_second_group; ++i)
population[size_first_group + i] = offspringsB[i];
}
void evolve(std::size_t generations)
{
// hardcoded nelder_mead_iterations
std::size_t nelder_mead_iterations = 20;
// stopping criteria prameters
double prev_fit_value = 0;
double new_fit_value = 0;
double tolerance = 1e-2;
int stale = 0;
for(std::size_t t = 0; t < generations; ++t)
{
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
std::cout << "generation= " << t << "\n";
#endif
genetic_algorithm();
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
//std::cout << "pop after genetic" << std::endl;
//pop.show_population();
//std::cout << std::endl;
#endif
for(std::size_t s = 0; s < population.size(); ++s)
nelder_mead<Linear_algebra_traits>(population[s], point_data, nelder_mead_iterations);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
//std::cout << "pop after nelder mead: " << std::endl;
//pop.show_population();
//std::cout << std::endl;
Fitness_map<Linear_algebra_traits, Matrix3d, MatrixXd> fitness_map_debug(population, point_data);
Matrix3d R_now = fitness_map_debug.get_best();
std::cout << "det= " << Linear_algebra_traits::determinant(R_now) << std::endl;
#endif
// stopping criteria
Fitness_map<Linear_algebra_traits, Matrix3d, MatrixXd> fitness_map(population, point_data);
new_fit_value = fitness_map.get_best_fitness_value();
double difference = new_fit_value - prev_fit_value;
if(CGAL::abs(difference) < tolerance * new_fit_value)
stale++;
if(stale == 5)
break;
prev_fit_value = new_fit_value;
}
}
const Matrix3d get_best()
{
Fitness_map<Linear_algebra_traits, Matrix3d, MatrixXd> fitness_map(population, point_data);
return fitness_map.get_best();
}
private:
// data
Population<Linear_algebra_traits> population;
MatrixXd point_data;
};
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
template <typename Simplex>
void check_det(Population<Simplex>& pop)
{
for(std::size_t i = 0; i < pop.size(); ++i)
{
for(std::size_t j = 0; j < 4; ++j)
{
auto A = pop[i][j]; // Simplex
std::cout << Linear_algebra_traits::determinant(A) << std::endl;
}
}
}
#endif
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif // CGAL_OPTIMAL_BOUNDING_BOX_EVOLUTION_H

View File

@ -0,0 +1,117 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H
#define CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/assertions.h>
#include <limits>
namespace CGAL {
namespace Optimal_bounding_box {
template <typename Linear_algebra_traits, typename Vertex, typename Matrix>
double compute_fitness(const Vertex& R, const Matrix& data)
{
// R: rotation matrix
CGAL_assertion(R.cols() == 3);
CGAL_assertion(R.rows() == 3);
// data: points
CGAL_assertion(data.cols() == 3);
CGAL_assertion(data.rows() >= 3);
typedef typename Linear_algebra_traits::Vector3d Vector3d;
typedef typename Linear_algebra_traits::Index Index;
double xmin, xmax, ymin, ymax, zmin, zmax;
for(Index i = 0; i < static_cast<Index>(data.rows()); ++i){
Vector3d vec = Linear_algebra_traits::row3(data, i);
vec = R * vec;
if(i == 0){
xmin = xmax = vec.coeff(0);
ymin = ymax = vec.coeff(1);
zmin = zmax = vec.coeff(2);
}else {
if(vec.coeff(0) < xmin) xmin = vec.coeff(0);
if(vec.coeff(1) < ymin) ymin = vec.coeff(1);
if(vec.coeff(2) < zmin) zmin = vec.coeff(2);
if(vec.coeff(0) > xmax) xmax = vec.coeff(0);
if(vec.coeff(1) > ymax) ymax = vec.coeff(1);
if(vec.coeff(2) > zmax) zmax = vec.coeff(2);
}
}
CGAL_assertion(xmax > xmin);
CGAL_assertion(ymax > ymin);
CGAL_assertion(zmax > zmin);
// volume
return ((xmax - xmin) * (ymax - ymin) * (zmax - zmin));
}
template <typename Linear_algebra_traits, typename Vertex, typename Matrix>
struct Fitness_map
{
Fitness_map(Population<Linear_algebra_traits>& p, Matrix& points)
: pop(p), points(points)
{}
const Vertex get_best()
{
std::size_t simplex_id, vertex_id;
double best_fitness = std::numeric_limits<int>::max();
for(std::size_t i = 0; i < pop.size(); ++i)
{
for(std::size_t j =0; j < 4; ++j)
{
const Vertex vertex = pop[i][j];
const double fitness = compute_fitness<Linear_algebra_traits>(vertex, points);
if (fitness < best_fitness)
{
simplex_id = i;
vertex_id = j;
best_fitness = fitness;
}
}
}
return pop[simplex_id][vertex_id];
}
double get_best_fitness_value()
{
const Vertex best_mat = get_best();
return compute_fitness<Linear_algebra_traits>(best_mat, points);
}
Population<Linear_algebra_traits>& pop;
const Matrix& points;
};
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif // CGAL_OPTIMAL_BOUNDING_FITNESS_FUNCTION_H

View File

@ -0,0 +1,113 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_HELPER_H
#define CGAL_OPTIMAL_BOUNDING_BOX_HELPER_H
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/boost/graph/helpers.h>
#include <CGAL/number_utils.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <fstream>
#include <string>
#include <vector>
namespace CGAL {
namespace Optimal_bounding_box {
template <typename Matrix, typename Point>
void fill_matrix(const std::vector<Point>& v_points, Matrix& points_mat)
{
points_mat.resize(v_points.size(), 3);
for(std::size_t i = 0; i < v_points.size(); ++i)
{
Point p = v_points[i];
points_mat.set_coef(i, 0, CGAL::to_double(p.x()));
points_mat.set_coef(i, 1, CGAL::to_double(p.y()));
points_mat.set_coef(i, 2, CGAL::to_double(p.z()));
}
}
template <typename SurfaceMesh, typename Matrix>
void sm_to_matrix(SurfaceMesh& sm, Matrix& mat)
{
typedef typename boost::property_map<SurfaceMesh, boost::vertex_point_t>::const_type Vpm;
typedef typename boost::property_traits<Vpm>::reference Point_ref;
typedef typename boost::graph_traits<SurfaceMesh>::vertex_descriptor vertex_descriptor;
Vpm vpm = get(boost::vertex_point, sm);
mat.resize(vertices(sm).size(), 3);
std::size_t i = 0;
for(vertex_descriptor v : vertices(sm))
{
Point_ref p = get(vpm, v);
mat.set_coef(i, 0, CGAL::to_double(p.x()));
mat.set_coef(i, 1, CGAL::to_double(p.y()));
mat.set_coef(i, 2, CGAL::to_double(p.z()));
++i;
}
}
template <typename Point>
double calculate_volume(const std::vector<Point>& points)
{
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
CGAL::Bbox_3 bbox = bbox_3(points.begin(), points.end());
K::Iso_cuboid_3 ic(bbox);
return ic.volume();
}
// it is called after post processing in debug only
template <typename Matrix>
void matrix_to_mesh_and_draw(Matrix& data_points, std::string filename)
{
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
// Simplex -> std::vector
std::vector<Point> points;
for(int i = 0; i < data_points.rows(); ++i)
{
Point p(data_points(i, 0), data_points(i, 1), data_points(i, 2));
points.push_back(p);
}
Mesh mesh;
CGAL::make_hexahedron(points[0], points[1], points[2], points[3],
points[4], points[5], points[6], points[7], mesh);
std::ofstream out(filename);
out << mesh;
out.close();
}
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif // CGAL_OPTIMAL_BOUNDING_BOX_HELPER_H

View File

@ -0,0 +1,184 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_NEALDER_MEAD_FUNCTIONS_H
#define CGAL_OPTIMAL_BOUNDING_BOX_NEALDER_MEAD_FUNCTIONS_H
#include <CGAL/assertions.h>
#include <boost/iterator/counting_iterator.hpp>
#include <CGAL/Optimal_bounding_box/fitness_function.h>
#include <vector>
namespace CGAL {
namespace Optimal_bounding_box {
template <typename Linear_algebra_traits, typename Matrix>
const Matrix reflection(const Matrix& S_centroid, const Matrix& S_worst)
{
CGAL_assertion(S_centroid.rows() == 3);
CGAL_assertion(S_centroid.rows() == 3);
CGAL_assertion(S_worst.cols() == 3);
CGAL_assertion(S_worst.cols() == 3);
return S_centroid * Linear_algebra_traits::transpose(S_worst) * S_centroid;
}
template <typename Linear_algebra_traits, typename Matrix>
const Matrix expansion(const Matrix& S_centroid, const Matrix& S_worst, const Matrix& S_reflection)
{
CGAL_assertion(S_centroid.rows() == 3);
CGAL_assertion(S_centroid.rows() == 3);
CGAL_assertion(S_worst.cols() == 3);
CGAL_assertion(S_worst.cols() == 3);
CGAL_assertion(S_reflection.cols() == 3);
CGAL_assertion(S_reflection.cols() == 3);
return S_centroid * Linear_algebra_traits::transpose(S_worst) * S_reflection;
}
template <typename Linear_algebra_traits, typename Matrix>
Matrix mean(const Matrix& m1, const Matrix& m2)
{
// same API for reduction
CGAL_assertion(m1.rows() == 3);
CGAL_assertion(m1.rows() == 3);
CGAL_assertion(m2.cols() == 3);
CGAL_assertion(m2.cols() == 3);
Matrix reduction = 0.5 * m1 + 0.5 * m2;
Matrix Q = Linear_algebra_traits::qr_factorization(reduction);
double det = Linear_algebra_traits::determinant(Q);
return Q / det;
}
template <typename Linear_algebra_traits, typename Matrix>
const Matrix nm_centroid(const Matrix& S1, const Matrix& S2, const Matrix& S3)
{
Matrix mean = (S1 + S2 + S3) / 3.0;
Matrix Q = Linear_algebra_traits::qr_factorization(mean);
double det = Linear_algebra_traits::determinant(Q);
return Q / det;
}
// needed in nelder mead algorithm
struct Comparator
{
Comparator(const std::vector<double>& in) : fitness(in) {}
inline bool operator() (std::size_t& i, std::size_t& j) {
return fitness[i] < fitness[j];
}
const std::vector<double>& fitness;
};
// simplex: 4 rotation matrices are its vertices
template <typename Linear_algebra_traits>
void nelder_mead(std::vector<typename Linear_algebra_traits::Matrix3d>& simplex,
const typename Linear_algebra_traits::MatrixXd& point_data,
std::size_t nelder_mead_iterations)
{
CGAL_assertion(simplex.size() == 4); // tetrahedron
typedef typename Linear_algebra_traits::Matrix3d Matrix3d;
std::vector<double> fitness(4);
std::vector<std::size_t> indices(boost::counting_iterator<std::size_t>(0),
boost::counting_iterator<std::size_t>(simplex.size()));
for(std::size_t t = 0; t < nelder_mead_iterations; ++t)
{
for(std::size_t i = 0; i < 4; ++i)
{
fitness[i] = compute_fitness<Linear_algebra_traits>(simplex[i], point_data);
}
CGAL_assertion(fitness.size() == 4);
CGAL_assertion(indices.size() == 4);
// get indices of sorted sequence
Comparator compare_indices(fitness);
std::sort(indices.begin(), indices.end(), compare_indices);
// new sorted simplex & fitness
std::vector<Matrix3d> s_simplex(4);
std::vector<double> s_fitness(4);
for(int i = 0; i < 4; ++i)
{
s_simplex[i] = simplex[indices[i]];
s_fitness[i] = fitness[indices[i]];
}
simplex = s_simplex;
fitness = s_fitness;
// centroid
const Matrix3d v_centroid = nm_centroid<Linear_algebra_traits>(simplex[0], simplex[1], simplex[2]);
// find worst's vertex reflection
const Matrix3d v_worst = simplex[3];
const Matrix3d v_refl = reflection<Linear_algebra_traits>(v_centroid, v_worst);
const double f_refl = compute_fitness<Linear_algebra_traits>(v_refl, point_data);
if(f_refl < fitness[2])
{
if(f_refl >= fitness[0]) // if reflected point is not better than the best
{
// do reflection
simplex[3] = v_refl;
}
else
{
// expansion
const Matrix3d v_expand = expansion<Linear_algebra_traits>(v_centroid, v_worst, v_refl);
const double f_expand = compute_fitness<Linear_algebra_traits>(v_expand, point_data);
if(f_expand < f_refl)
simplex[3] = v_expand;
else
simplex[3] = v_refl;
}
}
else // if reflected vertex is not better
{
const Matrix3d v_mean = mean<Linear_algebra_traits>(v_centroid, v_worst);
const double f_mean = compute_fitness<Linear_algebra_traits>(v_mean, point_data);
if(f_mean <= fitness[3])
// contraction of worst
simplex[3] = v_mean;
else
{
// reduction: move all vertices towards the best
for(std::size_t i=1; i < 4; ++i)
{
simplex[i] = mean<Linear_algebra_traits>(simplex[i], simplex[0]);
}
}
}
CGAL_assertion(simplex.size() == 4); // tetrahedron
} // iterations
}
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif

View File

@ -0,0 +1,273 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_OBB_H
#define CGAL_OPTIMAL_BOUNDING_BOX_OBB_H
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/Optimal_bounding_box/evolution.h>
#include <CGAL/Optimal_bounding_box/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/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Iso_cuboid_3.h>
#include <CGAL/Simple_cartesian.h>
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
#include <CGAL/Timer.h>
#endif
#if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_linear_algebra_traits.h>
#endif
#include <iostream>
#include <iterator>
#include <vector>
namespace CGAL {
namespace Optimal_bounding_box {
// works on matrices only
/// \cond SKIP_IN_MANUAL
template <typename Linear_algebra_traits, typename Vertex, typename Matrix>
void post_processing(const Matrix& points, Vertex& R, Matrix& obb)
{
CGAL_assertion(points.cols() == 3);
CGAL_assertion(R.rows() == 3);
CGAL_assertion(R.cols() == 3);
CGAL_assertion(obb.rows() == 8);
CGAL_assertion(obb.cols() == 3);
// 1) rotate points with R
Matrix rotated_points(points.rows(), points.cols());
rotated_points = points * Linear_algebra_traits::transpose(R);
// 2) get AABB from rotated points
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point;
typedef typename Linear_algebra_traits::Index index;
// Simplex -> std::vector
std::vector<Point> v_points;
for(index i = 0; i < static_cast<index>(rotated_points.rows()); ++i)
{
Point p(rotated_points(i, 0), rotated_points(i, 1), rotated_points(i, 2));
v_points.push_back(p);
}
CGAL::Bbox_3 bbox;
bbox = bbox_3(v_points.begin(), v_points.end());
K::Iso_cuboid_3 ic(bbox);
Matrix aabb(8, 3);
for(std::size_t i = 0; i < 8; ++i)
{
aabb.set_coef(i, 0, ic[i].x());
aabb.set_coef(i, 1, ic[i].y());
aabb.set_coef(i, 2, ic[i].z());
}
// 3) apply inverse rotation to rotated AABB
obb = aabb * R;
}
/// \endcond
/// \ingroup OBB_grp
/// calculates the optimal bounding box.
///
/// @tparam Point the point type
/// @tparam LinearAlgebraTraits a model of `LinearAlgebraTraits`. If no instance of `LinearAlgebraTraits`
/// is provided, then `CGAL::Eigen_linear_algebra_traits` is used.
///
/// @param points the input points that are included in the optimal bounding box.
/// @param obb_points the eight points of the optimal bounding box to be calculated.
/// @param use_ch a bool flag to indicating whether to use the convex hull of the input points
/// as an optimization step.
template <typename Point, typename LinearAlgebraTraits>
void compute_optimal_bounding_box(const std::vector<Point>& points,
std::vector<Point>& obb_points,
LinearAlgebraTraits&,
bool use_ch)
{
CGAL_assertion(points.size() >= 3);
if(obb_points.size() != 8)
obb_points.resize(8);
CGAL_assertion(obb_points.size() == 8);
// eigen linear algebra traits
typedef typename LinearAlgebraTraits::MatrixXd MatrixXd;
typedef typename LinearAlgebraTraits::Matrix3d Matrix3d;
MatrixXd points_mat;
if(use_ch) // get the ch3
{
std::vector<Point> ch_points;
CGAL::extreme_points_3(points, std::back_inserter(ch_points));
CGAL::Optimal_bounding_box::fill_matrix(ch_points, points_mat);
}
else
{
CGAL::Optimal_bounding_box::fill_matrix(points, points_mat);
}
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
CGAL::Timer timer;
#endif
std::size_t max_generations = 100;
Population<LinearAlgebraTraits> pop(50);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.start();
#endif
CGAL::Optimal_bounding_box::Evolution<LinearAlgebraTraits> search_solution(pop, points_mat);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.stop();
std::cout << "constructor: " << timer.time() << std::endl;
timer.reset();
timer.start();
#endif
search_solution.evolve(max_generations);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.stop();
std::cout << "evolve: " << timer.time() << std::endl;
timer.reset();
timer.start();
#endif
Matrix3d rotation = search_solution.get_best();
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.stop();
std::cout << "get best: " << timer.time() << std::endl;
#endif
MatrixXd obb; // may be preallocated at compile time
obb.resize(8, 3);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.reset();
timer.start();
#endif
post_processing<LinearAlgebraTraits>(points_mat, rotation, obb);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_BENCHMARKS
timer.stop();
std::cout << "post porcessing: " << timer.time() << std::endl;
#endif
// matrix -> vector
for(std::size_t i = 0; i < 8; ++i)
{
Point p(obb(i, 0), obb(i, 1), obb(i, 2));
obb_points[i] = p;
}
}
template <typename Point>
void compute_optimal_bounding_box(const std::vector<Point>& points,
std::vector<Point>& obb_points,
bool use_ch)
{
#if defined(CGAL_EIGEN3_ENABLED)
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
#else
#pragma message("Error: You must either provide linear traits or link CGAL with the Eigen library")
Linear_algebra_traits; // no parameter provided, and Eigen is not enabled --> don't compile!
#endif
Linear_algebra_traits la_traits;
compute_optimal_bounding_box(points, obb_points, la_traits, use_ch);
}
/// \ingroup OBB_grp
/// calculates the optimal bounding box.
///
/// @tparam PolygonMesh a model of `FaceListGraph`
/// @tparam LinearAlgebraTraits a model of `LinearAlgebraTraits`. If no instance of `LinearAlgebraTraits`
/// is provided, then `CGAL::Eigen_linear_algebra_traits` is used.
///
/// @param pmesh the input mesh.
/// @param obbmesh the hexaedron mesh to be built out of the optimal bounding box.
/// @param la_traits an instance of the linear algebra traits.
/// @param use_ch a bool flag to indicating whether to use the convex hull of the input points
/// as an optimization step.
template <typename PolygonMesh, typename LinearAlgebraTraits>
void compute_optimal_bounding_box(const PolygonMesh& pmesh,
PolygonMesh& obbmesh,
LinearAlgebraTraits& la_traits,
bool use_ch)
{
CGAL_assertion(vertices(pmesh).size() >= 3);
if(vertices(pmesh).size() <= 3)
{
std::cerr << "Not enough points in the mesh!\n";
return;
}
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<PolygonMesh, CGAL::vertex_point_t>::type Vpm;
typedef typename boost::property_traits<Vpm>::value_type Point;
std::vector<Point> points;
Vpm pmap = get(boost::vertex_point, pmesh);
BOOST_FOREACH(vertex_descriptor v, vertices(pmesh))
points.push_back(get(pmap, v));
std::vector<Point> obb_points;
compute_optimal_bounding_box(points, obb_points, la_traits, use_ch);
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], obbmesh);
}
template <typename PolygonMesh>
void compute_optimal_bounding_box(const PolygonMesh& pmesh,
PolygonMesh& obbmesh,
bool use_ch)
{
#if defined(CGAL_EIGEN3_ENABLED)
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
#else
#pragma message("Error: You must either provide linear traits or link CGAL with the Eigen library")
Linear_algebra_traits; // no parameter provided, and Eigen is not enabled --> don't compile!
#endif
Linear_algebra_traits la_traits;
compute_optimal_bounding_box(pmesh, obbmesh, la_traits, use_ch);
}
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif // CGAL_OPTIMAL_BOUNDING_BOX_OBB_H

View File

@ -0,0 +1,136 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H
#define CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H
#include <CGAL/assertions.h>
#include <CGAL/Random.h>
#include <vector>
namespace CGAL {
namespace Optimal_bounding_box {
template<typename Linear_algebra_traits>
class Population
{
typedef typename Linear_algebra_traits::Matrix3d Matrix;
typedef std::vector<Matrix> Simplex;
public:
Population(std::size_t size)
: n(size), random_generator(CGAL::Random())
{
// reserve pop space
pop.reserve(n);
// create simplices
for(std::size_t i = 0 ; i < n; ++i)
{
Simplex simplex(4);
create_simplex(simplex);
CGAL_assertion(simplex.size() == 4);
pop.push_back(simplex);
}
}
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
void show_population();
#endif
std::size_t size(){return n;}
// access simplex
Simplex& operator[](std::size_t i)
{
CGAL_assertion(i < n);
return pop[i];
}
const Simplex& operator[](std::size_t i) const
{
CGAL_assertion(i < n);
return pop[i];
}
private:
// create random population
void create_simplex(Simplex& simplex)
{
CGAL_assertion(simplex.size() == 4);
for(std::size_t i = 0; i < 4; ++i)
{
Matrix R;
if(R.cols() == 0 || R.rows() == 0)
R.resize(3, 3);
create_vertex(R);
Matrix Q = Linear_algebra_traits::qr_factorization(R);
simplex[i] = Q;
}
CGAL_assertion(simplex.size() == 4);
}
void create_vertex(Matrix& R)
{
CGAL_assertion(R.rows() == 3);
CGAL_assertion(R.cols() == 3);
for(std::size_t i = 0; i < 3; ++i)
{
for(std::size_t j = 0; j < 3; ++j)
{
R.set_coef(i, j, random_generator.get_double());
}
}
}
std::size_t n;
CGAL::Random random_generator;
std::vector<Simplex> pop;
};
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG
template <typename Matrix>
void Population<Matrix>::show_population()
{
std::size_t id = 0;
for(const Simplex i : pop)
{
CGAL_assertion(i.size() == 4);
std:: cout << "Simplex: "<< id++ << std::endl;
for(const Matrix R : i)
{
std::cout << R; // eigen out
std::cout << "\n\n";
}
std:: cout << std:: endl;
}
}
#endif
} // end namespace Optimal_bounding_box
} // end namespace CGAL
#endif // CGAL_OPTIMAL_BOUNDING_BOX_POPULATION_H

View File

@ -0,0 +1 @@
GeometryFactory (France)

View File

@ -0,0 +1 @@
GPL (v3 or later)

View File

@ -0,0 +1 @@
GeometryFactory

View File

@ -0,0 +1,26 @@
# 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()
else()
include(${EIGEN3_USE_FILE})
endif()
create_single_source_cgal_program("test_linear_algebra_functions.cpp")
create_single_source_cgal_program("test_optimization_algorithms.cpp")

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -0,0 +1,11 @@
OFF
4 4 0
0.866802 0.740808 0.895304
0.912651 0.761565 0.160330
0.093661 0.892578 0.737412
0.166461 0.149912 0.364944
3 0 1 2
3 2 3 0
3 1 3 2
3 0 3 1

View File

@ -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

View File

@ -0,0 +1,301 @@
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/nelder_mead_functions.h>
#include <CGAL/Optimal_bounding_box/fitness_function.h>
#include <CGAL/assertions.h>
bool assert_doubles(double d1, double d2, double epsilon)
{
return (d1 < d2 + epsilon && d1 > d2 - epsilon) ? true : false;
}
void test_qr_factorization()
{
typedef CGAL::Eigen_dense_matrix<double, 3, 3> Mat;
Mat A(3, 3);
A.set_coef(0, 0, 0.3011944);
A.set_coef(0, 1, 0.9932761);
A.set_coef(0, 2, 0.5483701);
A.set_coef(1, 0, 0.5149142);
A.set_coef(1, 1, 0.5973263);
A.set_coef(1, 2, 0.5162336);
A.set_coef(2, 0, 0.0039213);
A.set_coef(2, 1, 0.0202949);
A.set_coef(2, 2, 0.9240308);
CGAL_assertion_code(Mat Q = CGAL::Eigen_linear_algebra_traits::qr_factorization(A));
CGAL_assertion_code(double epsilon = 1e-6);
CGAL_assertion(assert_doubles(Q(0,0), -0.504895, epsilon));
CGAL_assertion(assert_doubles(Q(0,1), 0.862834, epsilon));
CGAL_assertion(assert_doubles(Q(0,2), -0.024447, epsilon));
CGAL_assertion(assert_doubles(Q(1,0), -0.863156, epsilon));
CGAL_assertion(assert_doubles(Q(1,1), -0.504894, epsilon));
CGAL_assertion(assert_doubles(Q(1,2), 0.006687, epsilon));
CGAL_assertion(assert_doubles(Q(2,0), -0.006573, epsilon));
CGAL_assertion(assert_doubles(Q(2,1), 0.024478, epsilon));
CGAL_assertion(assert_doubles(Q(2,2), 0.999679, epsilon));
}
void test_fitness_function()
{
typedef typename CGAL::Eigen_linear_algebra_traits::MatrixXd MatrixXd;
MatrixXd data_points(4, 3);
data_points.set_coef(0, 0, 0.866802);
data_points.set_coef(0, 1, 0.740808);
data_points.set_coef(0, 2, 0.895304);
data_points.set_coef(1, 0, 0.912651);
data_points.set_coef(1, 1, 0.761565);
data_points.set_coef(1, 2, 0.160330);
data_points.set_coef(2, 0, 0.093661);
data_points.set_coef(2, 1, 0.892578);
data_points.set_coef(2, 2, 0.737412);
data_points.set_coef(3, 0, 0.166461);
data_points.set_coef(3, 1, 0.149912);
data_points.set_coef(3, 2, 0.364944);
typedef typename CGAL::Eigen_linear_algebra_traits::Matrix3d Matrix3d;
Matrix3d rotation;
rotation.set_coef(0, 0, -0.809204);
rotation.set_coef(0, 1, 0.124296);
rotation.set_coef(0, 2, 0.574230);
rotation.set_coef(1, 0, -0.574694);
rotation.set_coef(1, 1, 0.035719);
rotation.set_coef(1, 2, -0.817589);
rotation.set_coef(2, 0, -0.122134);
rotation.set_coef(2, 1, -0.991602);
rotation.set_coef(2, 2, 0.042528);
CGAL_assertion_code(typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits);
CGAL_assertion_code(double fitness = CGAL::Optimal_bounding_box::
compute_fitness<Linear_algebra_traits> (rotation, data_points));
CGAL_assertion(assert_doubles(fitness, 0.58606, 1e-5));
}
void test_simplex_operations()
{
CGAL_assertion_code(typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits);
typedef CGAL::Eigen_dense_matrix<double, 3, 3> Matrix;
Matrix Sc(3, 3);
Sc.set_coef(0, 0, -0.809204);
Sc.set_coef(0, 1, 0.124296);
Sc.set_coef(0, 2, 0.574230);
Sc.set_coef(1, 0, -0.574694);
Sc.set_coef(1, 1, 0.035719);
Sc.set_coef(1, 2, -0.817589);
Sc.set_coef(2, 0, -0.122134);
Sc.set_coef(2, 1, -0.991602);
Sc.set_coef(2, 2, 0.042528);
Matrix S_worst(3, 3);
S_worst.set_coef(0, 0, -0.45070);
S_worst.set_coef(0, 1, -0.32769);
S_worst.set_coef(0, 2, -0.83035);
S_worst.set_coef(1, 0, -0.13619);
S_worst.set_coef(1, 1, -0.89406);
S_worst.set_coef(1, 2, 0.42675);
S_worst.set_coef(2, 0, -0.88222);
S_worst.set_coef(2, 1, 0.30543);
S_worst.set_coef(2, 2, 0.35833);
CGAL_assertion_code(Matrix Sr = CGAL::Optimal_bounding_box::reflection<Linear_algebra_traits>(Sc, S_worst));
CGAL_assertion_code(double epsilon = 1e-5);
CGAL_assertion(assert_doubles(Sr(0,0), -0.13359, epsilon));
CGAL_assertion(assert_doubles(Sr(0,1), -0.95986, epsilon));
CGAL_assertion(assert_doubles(Sr(0,2), -0.24664, epsilon));
CGAL_assertion(assert_doubles(Sr(1,0), -0.60307, epsilon));
CGAL_assertion(assert_doubles(Sr(1,1), -0.11875, epsilon));
CGAL_assertion(assert_doubles(Sr(1,2), 0.78880, epsilon));
CGAL_assertion(assert_doubles(Sr(2,0), -0.78642, epsilon));
CGAL_assertion(assert_doubles(Sr(2,1), 0.25411, epsilon));
CGAL_assertion(assert_doubles(Sr(2,2), -0.56300, epsilon));
CGAL_assertion_code(Matrix Se =
CGAL::Optimal_bounding_box::expansion<Linear_algebra_traits>(Sc, S_worst, Sr));
CGAL_assertion(assert_doubles(Se(0,0), -0.87991, epsilon));
CGAL_assertion(assert_doubles(Se(0,1), 0.36105, epsilon));
CGAL_assertion(assert_doubles(Se(0,2), -0.30888, epsilon));
CGAL_assertion(assert_doubles(Se(1,0), -0.11816, epsilon));
CGAL_assertion(assert_doubles(Se(1,1), -0.79593, epsilon));
CGAL_assertion(assert_doubles(Se(1,2), -0.59375, epsilon));
CGAL_assertion(assert_doubles(Se(2,0), -0.460215, epsilon));
CGAL_assertion(assert_doubles(Se(2,1), -0.48595, epsilon));
CGAL_assertion(assert_doubles(Se(2,2), 0.74300, epsilon));
Matrix S_a(3, 3);
S_a.set_coef(0, 0, -0.277970);
S_a.set_coef(0, 1, 0.953559);
S_a.set_coef(0, 2, 0.116010);
S_a.set_coef(1, 0, -0.567497);
S_a.set_coef(1, 1, -0.065576);
S_a.set_coef(1, 2, -0.820760);
S_a.set_coef(2, 0, -0.775035);
S_a.set_coef(2, 1, -0.293982);
S_a.set_coef(2, 2, 0.559370);
Matrix S_b(3, 3);
S_b.set_coef(0, 0, -0.419979);
S_b.set_coef(0, 1, 0.301765);
S_b.set_coef(0, 2, -0.8558940);
S_b.set_coef(1, 0, -0.653011);
S_b.set_coef(1, 1, -0.755415);
S_b.set_coef(1, 2, 0.054087);
S_b.set_coef(2, 0, -0.630234);
S_b.set_coef(2, 1, 0.581624);
S_b.set_coef(2, 2, 0.514314);
CGAL_assertion_code(Matrix S_c =
CGAL::Optimal_bounding_box::mean<Linear_algebra_traits>(S_a, S_b));
CGAL_assertion(assert_doubles(S_c(0,0), -0.35111, epsilon));
CGAL_assertion(assert_doubles(S_c(0,1), 0.79308, epsilon));
CGAL_assertion(assert_doubles(S_c(0,2), -0.49774, epsilon));
CGAL_assertion(assert_doubles(S_c(1,0), -0.61398, epsilon));
CGAL_assertion(assert_doubles(S_c(1,1), -0.59635, epsilon));
CGAL_assertion(assert_doubles(S_c(1,2), -0.51710, epsilon));
CGAL_assertion(assert_doubles(S_c(2,0), -0.70693, epsilon));
CGAL_assertion(assert_doubles(S_c(2,1), 0.12405, epsilon));
CGAL_assertion(assert_doubles(S_c(2,2), 0.69632, epsilon));
}
void test_centroid()
{
CGAL_assertion_code(typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits);
typedef CGAL::Eigen_dense_matrix<double, 3, 3> Matrix;
Matrix S_a;
S_a.set_coef(0, 0, -0.588443);
S_a.set_coef(0, 1, 0.807140);
S_a.set_coef(0, 2, -0.047542);
S_a.set_coef(1, 0, -0.786228);
S_a.set_coef(1, 1, -0.584933);
S_a.set_coef(1, 2, -0.199246);
S_a.set_coef(2, 0, -0.188629);
S_a.set_coef(2, 1, -0.079867);
S_a.set_coef(2, 2, 0.978795);
Matrix S_b(3, 3);
S_b.set_coef(0, 0, -0.2192721);
S_b.set_coef(0, 1, 0.2792986);
S_b.set_coef(0, 2, -0.9348326);
S_b.set_coef(1, 0, -0.7772152);
S_b.set_coef(1, 1, -0.6292092);
S_b.set_coef(1, 2, -0.005686);
S_b.set_coef(2, 0, -0.5897934);
S_b.set_coef(2, 1, 0.7253193);
S_b.set_coef(2, 2, 0.3550431);
Matrix S_c(3, 3);
S_c.set_coef(0, 0, -0.32657);
S_c.set_coef(0, 1, -0.60013);
S_c.set_coef(0, 2, -0.730206);
S_c.set_coef(1, 0, -0.20022);
S_c.set_coef(1, 1, -0.71110);
S_c.set_coef(1, 2, 0.67398);
S_c.set_coef(2, 0, -0.92372);
S_c.set_coef(2, 1, 0.36630);
S_c.set_coef(2, 2, 0.11207);
CGAL_assertion_code(Matrix S_centroid =
CGAL::Optimal_bounding_box::nm_centroid<Linear_algebra_traits>(S_a, S_b, S_c));
CGAL_assertion_code(double epsilon = 1e-5);
CGAL_assertion(assert_doubles(S_centroid(0,0), -0.419979, epsilon));
CGAL_assertion(assert_doubles(S_centroid(0,1), 0.301765, epsilon));
CGAL_assertion(assert_doubles(S_centroid(0,2), -0.855894, epsilon));
CGAL_assertion(assert_doubles(S_centroid(1,0), -0.653011, epsilon));
CGAL_assertion(assert_doubles(S_centroid(1,1), -0.755415, epsilon));
CGAL_assertion(assert_doubles(S_centroid(1,2), 0.054087, epsilon));
CGAL_assertion(assert_doubles(S_centroid(2,0), -0.630234, epsilon));
CGAL_assertion(assert_doubles(S_centroid(2,1), 0.581624, epsilon));
CGAL_assertion(assert_doubles(S_centroid(2,2), 0.514314, epsilon));
}
void test_eigen_matrix_interface()
{
CGAL_assertion_code(typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits);
typedef CGAL::Eigen_dense_matrix<double, 3, 3> Matrix;
Matrix A(3, 3);
A.set_coef(0, 0, 0.1);
A.set_coef(0, 1, 0.2);
A.set_coef(0, 2, 0.3);
A.set_coef(1, 0, 0.4);
A.set_coef(1, 1, 0.5);
A.set_coef(1, 2, 0.6);
A.set_coef(2, 0, 0.7);
A.set_coef(2, 1, 0.8);
A.set_coef(2, 2, 0.9);
CGAL_assertion_code(Matrix B);
CGAL_assertion_code(B = CGAL::Eigen_linear_algebra_traits::transpose(A));
CGAL_assertion_code(Matrix S);
CGAL_assertion_code(S = 0.5 * A);
Matrix C(3,3);
C.set_coef(0, 0, 0.3011944);
C.set_coef(0, 1, 0.9932761);
C.set_coef(0, 2, 0.5483701);
C.set_coef(1, 0, 0.5149142);
C.set_coef(1, 1, 0.5973263);
C.set_coef(1, 2, 0.5162336);
C.set_coef(2, 0, 0.0039213);
C.set_coef(2, 1, 0.0202949);
C.set_coef(2, 2, 0.9240308);
CGAL_assertion_code(Matrix Q = CGAL::Eigen_linear_algebra_traits::qr_factorization(C));
CGAL_assertion_code(double epsilon = 1e-5);
CGAL_assertion(assert_doubles(Q(0,0), -0.504895, epsilon));
CGAL_assertion(assert_doubles(Q(0,1), 0.862834, epsilon));
CGAL_assertion(assert_doubles(Q(0,2), -0.024447, epsilon));
CGAL_assertion(assert_doubles(Q(1,0), -0.863156, epsilon));
CGAL_assertion(assert_doubles(Q(1,1), -0.504894, epsilon));
CGAL_assertion(assert_doubles(Q(1,2), 0.006687, epsilon));
CGAL_assertion(assert_doubles(Q(2,0), -0.006573, epsilon));
CGAL_assertion(assert_doubles(Q(2,1), 0.024478, epsilon));
CGAL_assertion(assert_doubles(Q(2,2), 0.999679, epsilon));
Matrix D(3,3);
D.set_coef(0, 0, -0.809204);
D.set_coef(0, 1, 0.124296);
D.set_coef(0, 2, 0.574230);
D.set_coef(1, 0, -0.574694);
D.set_coef(1, 1, 0.035719);
D.set_coef(1, 2, -0.817589);
D.set_coef(2, 0, -0.122134);
D.set_coef(2, 1, -0.991602);
D.set_coef(2, 2, 0.042528);
Matrix E(3,3);
E.set_coef(0, 0, -0.45070);
E.set_coef(0, 1, -0.32769);
E.set_coef(0, 2, -0.83035);
E.set_coef(1, 0, -0.13619);
E.set_coef(1, 1, -0.89406);
E.set_coef(1, 2, 0.42675);
E.set_coef(2, 0, -0.88222);
E.set_coef(2, 1, 0.30543);
E.set_coef(2, 2, 0.35833);
CGAL_assertion_code(Matrix Sr = CGAL::Optimal_bounding_box::reflection<Linear_algebra_traits>(D, E));
CGAL_assertion(assert_doubles(Sr(0,0), -0.13359, epsilon));
CGAL_assertion(assert_doubles(Sr(0,1), -0.95986, epsilon));
CGAL_assertion(assert_doubles(Sr(0,2), -0.24664, epsilon));
CGAL_assertion(assert_doubles(Sr(1,0), -0.60307, epsilon));
CGAL_assertion(assert_doubles(Sr(1,1), -0.11875, epsilon));
CGAL_assertion(assert_doubles(Sr(1,2), 0.78880, epsilon));
CGAL_assertion(assert_doubles(Sr(2,0), -0.78642, epsilon));
CGAL_assertion(assert_doubles(Sr(2,1), 0.25411, epsilon));
CGAL_assertion(assert_doubles(Sr(2,2), -0.56300, epsilon));
}
int main()
{
test_qr_factorization();
test_fitness_function();
test_simplex_operations();
test_centroid();
test_eigen_matrix_interface();
return 0;
}

View File

@ -0,0 +1,423 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
#include <CGAL/Optimal_bounding_box/population.h>
#include <CGAL/Optimal_bounding_box/optimal_bounding_box.h>
#include <CGAL/Optimal_bounding_box/helper.h>
#include <CGAL/Optimal_bounding_box/nelder_mead_functions.h>
#include <iostream>
#include <fstream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
bool assert_doubles(double d1, double d2, double epsilon)
{
return (d1 < d2 + epsilon && d1 > d2 - epsilon) ? true : false;
}
void test_nelder_mead()
{
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
typedef Linear_algebra_traits::Matrix3d Matrix3d;
typedef Linear_algebra_traits::MatrixXd MatrixXd;
MatrixXd data_points(4,3);
data_points(0,0) = 0.866802;
data_points(0,1) = 0.740808,
data_points(0,2) = 0.895304,
data_points(1,0) = 0.912651;
data_points(1,1) = 0.761565;
data_points(1,2) = 0.160330;
data_points(2,0) = 0.093661;
data_points(2,1) = 0.892578;
data_points(2,2) = 0.737412;
data_points(3,0) = 0.166461;
data_points(3,1) = 0.149912,
data_points(3,2) = 0.364944;
// one simplex
std::vector<Matrix3d> simplex(4);
Matrix3d v0(3,3);
Matrix3d v1(3,3);
Matrix3d v2(3,3);
Matrix3d v3(3,3);
v0(0,0) = -0.2192721;
v0(0,1) = 0.2792986,
v0(0,2) = -0.9348326,
v0(1,0) = -0.7772152;
v0(1,1) = -0.6292092;
v0(1,2) = -0.0056861;
v0(2,0) = -0.5897934;
v0(2,1) = 0.7253193;
v0(2,2) = 0.3550431;
v1(0,0) = -0.588443;
v1(0,1) = 0.807140;
v1(0,2) = -0.047542;
v1(1,0) = -0.786228;
v1(1,1) = -0.584933;
v1(1,2) = -0.199246;
v1(2,0) = -0.188629;
v1(2,1) = -0.079867;
v1(2,2) = 0.978795;
v2(0,0) = -0.277970;
v2(0,1) = 0.953559;
v2(0,2) = 0.116010;
v2(1,0) = -0.567497;
v2(1,1) = -0.065576;
v2(1,2) = -0.820760;
v2(2,0) = -0.775035;
v2(2,1) = -0.293982;
v2(2,2) = 0.559370;
v3(0,0) = -0.32657;
v3(0,1) = -0.60013;
v3(0,2) = -0.73020;
v3(1,0) = -0.20022;
v3(1,1) = -0.71110;
v3(1,2) = 0.67398;
v3(2,0) = -0.92372;
v3(2,1) = 0.36630;
v3(2,2) = 0.11207;
simplex[0] = v0;
simplex[1] = v1;
simplex[2] = v2;
simplex[3] = v3;
std::size_t nm_iterations = 19;
CGAL::Optimal_bounding_box::nelder_mead<Linear_algebra_traits>(simplex, data_points, nm_iterations);
CGAL_assertion_code(double epsilon = 1e-5);
CGAL_assertion_code(Matrix3d v0_new = simplex[0]);
CGAL_assertion(assert_doubles(v0_new(0,0), -0.288975, epsilon));
CGAL_assertion(assert_doubles(v0_new(0,1), 0.7897657, epsilon));
CGAL_assertion(assert_doubles(v0_new(0,2), -0.541076, epsilon));
CGAL_assertion(assert_doubles(v0_new(1,0), -0.9407046, epsilon));
CGAL_assertion(assert_doubles(v0_new(1,1), -0.3391466, epsilon));
CGAL_assertion(assert_doubles(v0_new(1,2), 0.0073817, epsilon));
CGAL_assertion(assert_doubles(v0_new(2,0), -0.1776743, epsilon));
CGAL_assertion(assert_doubles(v0_new(2,1), 0.5111260, epsilon));
CGAL_assertion(assert_doubles(v0_new(2,2), 0.84094, epsilon));
CGAL_assertion_code(Matrix3d v1_new = simplex[1]);
CGAL_assertion(assert_doubles(v1_new(0,0), -0.458749, epsilon));
CGAL_assertion(assert_doubles(v1_new(0,1), 0.823283, epsilon));
CGAL_assertion(assert_doubles(v1_new(0,2), -0.334296, epsilon));
CGAL_assertion(assert_doubles(v1_new(1,0), -0.885235, epsilon));
CGAL_assertion(assert_doubles(v1_new(1,1), -0.455997, epsilon));
CGAL_assertion(assert_doubles(v1_new(1,2), 0.091794, epsilon));
CGAL_assertion(assert_doubles(v1_new(2,0), -0.076866, epsilon));
CGAL_assertion(assert_doubles(v1_new(2,1), 0.338040, epsilon));
CGAL_assertion(assert_doubles(v1_new(2,2), 0.937987, epsilon));
CGAL_assertion_code(Matrix3d v2_new = simplex[2]);
CGAL_assertion(assert_doubles(v2_new(0,0), -0.346582, epsilon));
CGAL_assertion(assert_doubles(v2_new(0,1), 0.878534, epsilon));
CGAL_assertion(assert_doubles(v2_new(0,2), -0.328724, epsilon));
CGAL_assertion(assert_doubles(v2_new(1,0), -0.936885, epsilon));
CGAL_assertion(assert_doubles(v2_new(1,1), -0.341445, epsilon));
CGAL_assertion(assert_doubles(v2_new(1,2), 0.075251, epsilon));
CGAL_assertion(assert_doubles(v2_new(2,0), -0.046131, epsilon));
CGAL_assertion(assert_doubles(v2_new(2,1), 0.334057, epsilon));
CGAL_assertion(assert_doubles(v2_new(2,2), 0.941423, epsilon));
CGAL_assertion_code(Matrix3d v3_new = simplex[3]);
CGAL_assertion(assert_doubles(v3_new(0,0), -0.394713, epsilon));
CGAL_assertion(assert_doubles(v3_new(0,1), 0.791782, epsilon));
CGAL_assertion(assert_doubles(v3_new(0,2), -0.466136, epsilon));
CGAL_assertion(assert_doubles(v3_new(1,0), -0.912112, epsilon));
CGAL_assertion(assert_doubles(v3_new(1,1), -0.398788, epsilon));
CGAL_assertion(assert_doubles(v3_new(1,2), 0.094972, epsilon));
CGAL_assertion(assert_doubles(v3_new(2,0), -0.110692, epsilon));
CGAL_assertion(assert_doubles(v3_new(2,1), 0.462655, epsilon));
CGAL_assertion(assert_doubles(v3_new(2,2), 0.879601, epsilon));
}
void test_genetic_algorithm()
{
CGAL::Eigen_dense_matrix<double, -1, -1> data_points(4, 3); // -1 = dynamic size at run time
data_points(0,0) = 0.866802;
data_points(0,1) = 0.740808,
data_points(0,2) = 0.895304,
data_points(1,0) = 0.912651;
data_points(1,1) = 0.761565;
data_points(1,2) = 0.160330;
data_points(2,0) = 0.093661;
data_points(2,1) = 0.892578;
data_points(2,2) = 0.737412;
data_points(3,0) = 0.166461;
data_points(3,1) = 0.149912,
data_points(3,2) = 0.364944;
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
CGAL::Optimal_bounding_box::Population<Linear_algebra_traits> pop(5);
CGAL::Optimal_bounding_box::Evolution<Linear_algebra_traits> evolution(pop, data_points);
evolution.genetic_algorithm();
CGAL_assertion(pop.size() == 5);
}
void test_random_unit_tetra()
{
// this is dynamic at run times
CGAL::Eigen_dense_matrix<double, -1, -1> data_points(4, 3);
// points are on their convex hull
data_points(0,0) = 0.866802;
data_points(0,1) = 0.740808,
data_points(0,2) = 0.895304,
data_points(1,0) = 0.912651;
data_points(1,1) = 0.761565;
data_points(1,2) = 0.160330;
data_points(2,0) = 0.093661;
data_points(2,1) = 0.892578;
data_points(2,2) = 0.737412;
data_points(3,0) = 0.166461;
data_points(3,1) = 0.149912,
data_points(3,2) = 0.364944;
typedef CGAL::Simple_cartesian<double> K;
typedef K::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
// make a mesh and export it
Mesh mesh;
Point p1(0.866802, 0.740808, 0.895304);
Point p2(0.912651, 0.761565, 0.160330);
Point p3(0.093661, 0.892578, 0.737412);
Point p4(0.166461, 0.149912, 0.364944);
CGAL::make_tetrahedron(p1, p2, p3, p4, mesh);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
std::ofstream out("data/random_unit_tetra.off");
out << mesh;
out.close();
#endif
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
CGAL_assertion_code(typedef Linear_algebra_traits::Matrix3d Matrix3d);
std::size_t generations = 10;
CGAL::Optimal_bounding_box::Population<Linear_algebra_traits> pop(50);
CGAL::Optimal_bounding_box::Evolution<Linear_algebra_traits> evolution(pop, data_points);
evolution.evolve(generations);
CGAL_assertion_code(Matrix3d R = evolution.get_best());
CGAL_assertion_code(double epsilon = 1e-3);
CGAL_assertion(assert_doubles(Linear_algebra_traits::determinant(R), 1, epsilon));
CGAL_assertion(assert_doubles(R(0,0), -0.25791, epsilon));
CGAL_assertion(assert_doubles(R(0,1), 0.796512, epsilon));
CGAL_assertion(assert_doubles(R(0,2), -0.546855, epsilon));
CGAL_assertion(assert_doubles(R(1,0), -0.947128, epsilon));
CGAL_assertion(assert_doubles(R(1,1), -0.320242, epsilon));
CGAL_assertion(assert_doubles(R(1,2), -0.0197553, epsilon));
CGAL_assertion(assert_doubles(R(2,0), -0.190861, epsilon));
CGAL_assertion(assert_doubles(R(2,1), 0.512847, epsilon));
CGAL_assertion(assert_doubles(R(2,2), 0.836992, epsilon));
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
// postprocessing
CGAL::Eigen_dense_matrix<double> obb(8, 3);
CGAL::Optimal_bounding_box::post_processing(data_points, R, obb);
CGAL::Optimal_bounding_box::matrix_to_mesh_and_draw(obb, "data/random_unit_tetra_result.off");
#endif
}
void test_reference_tetrahedron(const char* fname)
{
std::ifstream input(fname);
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty()) {
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
typedef Linear_algebra_traits::MatrixXd MatrixXd;
CGAL_assertion_code(typedef Linear_algebra_traits::Matrix3d Matrix3d);
// points in a matrix
MatrixXd points;
CGAL::Optimal_bounding_box::sm_to_matrix(mesh, points);
std::size_t generations = 10;
CGAL::Optimal_bounding_box::Population<Linear_algebra_traits> pop(50);
CGAL::Optimal_bounding_box::Evolution<Linear_algebra_traits> experiment(pop, points);
experiment.evolve(generations);
CGAL_assertion_code(Matrix3d R = experiment.get_best());
CGAL_assertion_code(double epsilon = 1e-5);
CGAL_assertion(assert_doubles(Linear_algebra_traits::determinant(R), 1, epsilon));
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
// postprocessing
MatrixXd obb(8, 3);
CGAL::Optimal_bounding_box::post_processing(points, R, obb);
CGAL::Optimal_bounding_box::matrix_to_mesh_and_draw(obb, "data/OBB.off");
#endif
}
void test_long_tetrahedron(std::string fname)
{
std::ifstream input(fname);
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty()) {
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
typedef Linear_algebra_traits::MatrixXd MatrixXd;
CGAL_assertion_code(typedef Linear_algebra_traits::Matrix3d Matrix3d);
// points in a matrix
MatrixXd points;
CGAL::Optimal_bounding_box::sm_to_matrix(mesh, points);
std::size_t max_generations = 10;
CGAL::Optimal_bounding_box::Population<Linear_algebra_traits> pop(50);
CGAL::Optimal_bounding_box::Evolution<Linear_algebra_traits> experiment(pop, points);
experiment.evolve(max_generations);
CGAL_assertion_code(Matrix3d R = experiment.get_best());
CGAL_assertion_code(double epsilon = 1e-3);
CGAL_assertion(assert_doubles(Linear_algebra_traits::determinant(R), 1, epsilon));
CGAL_assertion(assert_doubles(R(0,0), -1, epsilon));
CGAL_assertion(assert_doubles(R(0,1), 0, epsilon));
CGAL_assertion(assert_doubles(R(0,2), 0, epsilon));
CGAL_assertion(assert_doubles(R(1,0), 0, epsilon));
CGAL_assertion(assert_doubles(R(1,1), -0.707107, epsilon));
CGAL_assertion(assert_doubles(R(1,2), 0.707106, epsilon) ||
assert_doubles(R(1,2), -0.707106, epsilon));
CGAL_assertion(assert_doubles(R(2,0), 0, epsilon));
CGAL_assertion(assert_doubles(R(2,1), 0.707106, epsilon) ||
assert_doubles(R(1,2), -0.707106, epsilon));
CGAL_assertion(assert_doubles(R(2,2), 0.707107, epsilon));
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
// postprocessing
MatrixXd obb(8, 3);
CGAL::Optimal_bounding_box::post_processing(points, R, obb);
CGAL::Optimal_bounding_box::matrix_to_mesh_and_draw(obb, fname + "result.off");
#endif
}
void test_compute_obb_evolution(std::string fname)
{
std::ifstream input(fname);
typedef CGAL::Surface_mesh<K::Point_3> SMesh;
SMesh mesh;
if (!input || !(input >> mesh) || mesh.is_empty()) {
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
// get mesh points
std::vector<K::Point_3> sm_points;
typedef typename boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<SMesh, boost::vertex_point_t>::const_type PointPMap;
PointPMap pmap = get(boost::vertex_point, mesh);
BOOST_FOREACH(vertex_descriptor v, vertices(mesh))
sm_points.push_back(get(pmap, v));
CGAL::Eigen_linear_algebra_traits la_traits;
std::vector<K::Point_3> obb_points;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(sm_points, obb_points, la_traits, true);
CGAL_assertion_code(double epsilon = 1e-3);
CGAL_assertion_code(double vol = CGAL::Optimal_bounding_box::calculate_volume(obb_points));
CGAL_assertion(assert_doubles(vol, 0.883371, epsilon));
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
/*
for(int i = 0; i < 8; ++i)
std::cout << obb_points[i].x() << " " << obb_points[i].y() << " " << obb_points[i].z() << "\n" ;
*/
CGAL::Surface_mesh<K::Point_3> result_mesh;
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], result_mesh);
std::ofstream out("data/obb_result.off");
out << result_mesh;
out.close();
#endif
}
void test_compute_obb_mesh(std::string fname)
{
std::ifstream input(fname);
CGAL::Surface_mesh<K::Point_3> mesh;
if (!input || !(input >> mesh) || mesh.is_empty())
{
std::cerr << fname << " is not a valid off file.\n";
std::exit(1);
}
CGAL::Eigen_linear_algebra_traits la_traits;
CGAL::Surface_mesh< K::Point_3> obbmesh;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(mesh, obbmesh, la_traits, true);
#ifdef CGAL_OPTIMAL_BOUNDING_BOX_DEBUG_TEST
std::ofstream out("/tmp/result_elephant.off");
out << obbmesh;
out.close();
#endif
}
void test_function_defaults_traits(std::string fname1, std::string fname2)
{
std::ifstream input1(fname1);
CGAL::Surface_mesh<K::Point_3> mesh1;
if (!input1 || !(input1 >> mesh1) || mesh1.is_empty())
{
std::cerr << fname1 << " is not a valid off file.\n";
std::exit(1);
}
std::ifstream input2(fname2);
CGAL::Surface_mesh<K::Point_3> mesh2;
if (!input2 || !(input2 >> mesh2) || mesh2.is_empty())
{
std::cerr << fname2 << " is not a valid off file.\n";
std::exit(1);
}
// test one
std::vector<K::Point_3> sm_points;
typedef CGAL::Surface_mesh<K::Point_3> SMesh;
typedef typename boost::graph_traits<SMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::property_map<SMesh, boost::vertex_point_t>::const_type PointPMap;
PointPMap pmap = get(boost::vertex_point, mesh1);
BOOST_FOREACH(vertex_descriptor v, vertices(mesh1))
sm_points.push_back(get(pmap, v));
std::vector<K::Point_3> obb_points;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(sm_points, obb_points, true);
CGAL_assertion_code(double epsilon = 1e-3);
CGAL_assertion_code(double vol = CGAL::Optimal_bounding_box::calculate_volume(obb_points));
CGAL_assertion(assert_doubles(vol, 0.883371, epsilon));
// test two
CGAL::Surface_mesh< K::Point_3> obbmesh;
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(mesh2, obbmesh, true);
}
int main()
{
test_nelder_mead();
test_genetic_algorithm();
test_random_unit_tetra();
test_reference_tetrahedron("data/reference_tetrahedron.off");
test_long_tetrahedron("data/long_tetrahedron.off");
test_compute_obb_evolution("data/random_unit_tetra.off");
test_compute_obb_mesh("data/elephant.off");
test_function_defaults_traits("data/random_unit_tetra.off", "data/elephant.off");
return 0;
}

View File

@ -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_polyhedron_item scene_polyhedron_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)

View File

@ -0,0 +1,191 @@
#include <QtCore/qglobal.h>
#include <CGAL/Three/Scene_item.h>
#include <CGAL/Three/Scene_interface.h>
#include <QAction>
#include <QMainWindow>
#include <QApplication>
#include "Scene_surface_mesh_item.h"
#include "Polyhedron_type.h"
#include "Scene_polyhedron_item.h"
#include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
#include "Scene_polyhedron_selection_item.h"
#include "Scene_points_with_normal_item.h"
#include <boost/graph/graph_traits.hpp>
#include <CGAL/Optimal_bounding_box/optimal_bounding_box.h>
#include <CGAL/Eigen_linear_algebra_traits.h>
//typedef Scene_surface_mesh_item Scene_facegraph_item;
//typedef Scene_facegraph_item Scene_facegraph_item;
typedef Scene_facegraph_item::Face_graph FaceGraph;
typedef Polyhedron::Point_3 Point_3;
using namespace CGAL::Three;
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->selectionIndices().size() == 1)
{
return qobject_cast<Scene_facegraph_item*>(scene->item(scene->mainSelectionIndex()))
|| qobject_cast<Scene_polyhedron_selection_item*>(scene->item(scene->mainSelectionIndex()));
}
Q_FOREACH(int index, scene->selectionIndices())
{
if (qobject_cast<Scene_facegraph_item*>(scene->item(index)))
return true;
}
return false;
*/
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* poly_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(poly_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(poly_item != NULL)
{
FaceGraph& pmesh = *poly_item->polyhedron();
selected_vertices.assign(vertices(pmesh).begin(), vertices(pmesh).end());
PointPMap pmap = get(CGAL::vertex_point, pmesh);
BOOST_FOREACH(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();
BOOST_FOREACH(face_descriptor f, selection_item->selected_facets)
{
BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, pmesh), pmesh))
{
selected_vertices.push_back(v);
}
}
PointPMap pmap = get(CGAL::vertex_point, pmesh);
BOOST_FOREACH(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;
BOOST_FOREACH(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
CGAL::Eigen_linear_algebra_traits la_traits;
std::vector<Point_3> obb_points(8);
CGAL::Optimal_bounding_box::compute_optimal_bounding_box(points, obb_points, la_traits, true);
Scene_item* item;
if(mw->property("is_polyhedorn_mode").toBool())
{
Polyhedron* p = new Polyhedron;
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_polyhedron_item(p);
}
else {
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_surface_mesh_item(p);
}
item->setName("Optimal bbox mesh");
item->setRenderingMode(Wireframe);
scene->addItem(item);
}
#include "Create_obb_mesh_plugin.moc"

View File

@ -0,0 +1,326 @@
// Copyright (c) 2018 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Konstantinos Katrioplas
#ifndef CGAL_EIGEN_LINEAR_ALGEBRA_TRAITS_H
#define CGAL_EIGEN_LINEAR_ALGEBRA_TRAITS_H
#include <CGAL/basic.h>
#include <Eigen/Dense>
#include <Eigen/QR>
namespace CGAL {
template<typename T, int D = Eigen::Dynamic>
class Eigen_dense_vector;
/*!
\ingroup PkgSolver
The class `Eigen_dense_matrix` is a wrapper around \ref thirdpartyEigen "Eigen" matrix type
<a href="http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html">`Eigen::DenseMatrix`</a>.
\tparam T Number type.
\tparam D1 Number of rows, or Dynamic.
\tparam D1 Number of cols, or Dynamic.
\sa `CGAL::Eigen_dense_vector<T, D>`
\sa `CGAL::Eigen_linear_algebra_traits`
*/
template<typename T, int D1 = Eigen::Dynamic, int D2 = Eigen::Dynamic>
class Eigen_dense_matrix
{
public:
/// The internal matrix type from \ref thirdpartyEigen "Eigen".
typedef Eigen::Matrix<T, D1, D2> EigenType;
/// Create a dense matrix
Eigen_dense_matrix(std::size_t nrows, std::size_t ncols)
: m_matrix(static_cast<int>(nrows), static_cast<int>(ncols))
{
CGAL_assertion(m_matrix.rows() > 0);
CGAL_assertion(m_matrix.cols() > 0);
}
/// Create a dense matrix
Eigen_dense_matrix(int nrows, int ncols)
: m_matrix(nrows, ncols)
{
CGAL_assertion(m_matrix.rows() > 0);
CGAL_assertion(m_matrix.cols() > 0);
}
/// Create a dense matrix out of a \ref thirdpartyEigen "Eigen" matrix type
Eigen_dense_matrix(const EigenType& eigen_mat)
: m_matrix(eigen_mat) {}
Eigen_dense_matrix() : m_matrix() {}
/// Read access to a matrix coefficient.
///
/// \pre 0 <= i < row_dimension().
/// \pre 0 <= j < column_dimension().
T& operator() (int i_, int j_)
{
return m_matrix(i_, j_);
}
/// Write access to a matrix coefficient: a_ij <- val
///
/// \pre 0 <= i < row_dimension().
/// \pre 0 <= j < column_dimension().
void set_coef(std::size_t i_, std::size_t j_, T val)
{
int i = static_cast<int>(i_);
int j = static_cast<int>(j_);
CGAL_precondition(i < m_matrix.rows());
CGAL_precondition(j < m_matrix.cols());
m_matrix.coeffRef(i,j) = val;
}
/// Return the matrix number of rows
std::size_t rows() const {return m_matrix.rows();}
/// Return the matrix number of cols
std::size_t cols() const {return m_matrix.cols();}
/// Resize to i rows and j cols
void resize(int i_, int j_) { m_matrix.resize(i_, j_);}
const T& coeff(int i_) const
{
return m_matrix.coeff(i_);
}
EigenType m_matrix;
};
/*!
\ingroup PkgSolver
The class `Eigen_vector` is a wrapper around \ref thirdpartyEigen "Eigen" dense vector
type <a href="http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html"> </a>,
which is a simple array of numbers.
\cgalModels `SvdTraits::Vector`
\cgalModels `SparseLinearAlgebraTraits_d::Vector`.
\tparam T Number type.
\tparam D Number of colums, or Dynamic.
\sa `CGAL::Eigen_dense_matrix<T>`
\sa `CGAL::Eigen_linear_algebra_traits<T>`
*/
template <typename T, int D>
class Eigen_dense_vector
{
private:
/// The internal vector type from \ref thirdpartyEigen "Eigen".
typedef Eigen::Matrix<T, D, 1> EigenType;
public:
/// Create a dense vector out of a \ref thirdpartyEigen "Eigen" vector type
Eigen_dense_vector(const EigenType& vec) : m_vector(vec) {}
/// Read and write and access to a vector coefficient: `a_i`
const T& coeff(std::size_t i)
{
CGAL_assertion(i >= 0);
CGAL_assertion(i < static_cast<std::size_t>(D));
return m_vector.coeff(i);
}
EigenType m_vector;
};
/*!
\ingroup PkgSolver
The class `Eigen_linear_algebra_traits` provides an interface to linear algebra functionalities of \ref thirdpartyEigen "Eigen".
\ref thirdpartyEigen "Eigen" version 3.1 (or later) must be available on the system.
\sa `CGAL::Eigen_dense_matrix<T, D1, D2>`
\sa `CGAL::Eigen_dense_vector<T, D>`
\sa http://eigen.tuxfamily.org
Example
--------------
\code{.cpp}
typedef CGAL::Eigen_linear_algebra_traits Linear_algebra_traits;
// dynamic matrix at run time to store a large amount of data
typedef Linear_algebra_traits::MatrixXd MatrixXd;
// preallocated 3x3 matrix at compile time
typedef Linear_algebra_traits::Matrix3d Matrix3d;
// preallocated 3-cols vector at compile time
typedef Linear_algebra_traits::Vector3d Vector3d;
\endcode
*/
class Eigen_linear_algebra_traits
{
public:
typedef double NT;
typedef int Index;
// dynamic size at run time
typedef CGAL::Eigen_dense_matrix<NT> MatrixXd;
// dynamic rows in run time, fixed cols in compile time
typedef CGAL::Eigen_dense_matrix<NT, Eigen::Dynamic, 3> MatrixX3d;
// fixed at compile time
typedef CGAL::Eigen_dense_matrix<NT, 3, 3> Matrix3d;
// fixed at compile time
typedef CGAL::Eigen_dense_vector<NT, 3> Vector3d;
/// Get the transpose of a `CGAL::Eigen_dense_matrix<T, D1, D2>` matrix
template <class Matrix>
static Matrix transpose(const Matrix& mat)
{
return Matrix(mat.m_matrix.transpose());
}
/// Get the determinant of a `CGAL::Eigen_dense_matrix<T, D1, D2>` matrix
template <class Matrix>
static NT determinant(const Matrix& mat)
{
return mat.m_matrix.determinant();
}
/// Performs QR decomposition of matrix A to a unitary matrix and an upper triagonal
/// and returns the unitary matrix.
template <class NT, int D1, int D2>
static CGAL::Eigen_dense_matrix<NT, D1, D2> qr_factorization(const CGAL::Eigen_dense_matrix<NT, D1, D2>& A)
{
Eigen::HouseholderQR<Eigen::Matrix<NT, D1, D2> > qr(A.m_matrix);
return CGAL::Eigen_dense_matrix<NT, D1, D2>(qr.householderQ());
}
template <class Matrix>
static void qr_factorization(std::vector<Matrix>& simplex)
{
for(std::size_t i = 0; i < simplex.size(); ++i)
{
Matrix mat = simplex[i].m_matrix;
simplex[i] = qr_factorization(mat);
}
}
// CGAL::Eigen_dense_vector<NT, D2> : the returned type with D2 may be -1 in compile time,
// and may not be equal to the expected type.
// Eigen manages to return a precompiled row out of a dynamic matrix but I don't know how.
/// Get the row vector out of a `CGAL::Eigen_dense_matrix<T, D1, D2>`. The result is stored in a
/// preallocated at compile time 3-column `CGAL::Eigen_dense_vector<T, 3>`
template <class NT, int D1, int D2>
static CGAL::Eigen_dense_vector<NT, 3> row3(const CGAL::Eigen_dense_matrix<NT, D1, D2>& A,
int i)
{
return CGAL::Eigen_dense_vector<NT, 3>(A.m_matrix.row(i));
}
};
/// Matrix multiplication. If the columns of A and the rows of B are equal at compile time,
/// the product is stored at a preallocated at compile time `CGAL::Eigen_dense_matrix`. Otherwise,
/// the product is stored in a dynamic at run time matrix.
template <class NT, int D1, int D2, int D3>
const CGAL::Eigen_dense_matrix<NT, D1, D3> operator* (const CGAL::Eigen_dense_matrix<NT, D1, D2 >& A,
const CGAL::Eigen_dense_matrix<NT, D2, D3 >& B)
{
return CGAL::Eigen_dense_matrix<NT, D1, D3>(A.m_matrix * B.m_matrix);
}
// D2 and D3 may not be equal at compile time, but equal at run time!
// This overload returns a dynamic matrix.
template <class NT, int D1, int D2, int D3, int D4>
const CGAL::Eigen_dense_matrix<NT> operator* (const CGAL::Eigen_dense_matrix<NT, D1, D2 >& A,
const CGAL::Eigen_dense_matrix<NT, D3, D4 >& B)
{
return CGAL::Eigen_dense_matrix<NT>(A.m_matrix * B.m_matrix);
}
// scalar - matrix multiplication
template <class NT, int D1, int D2>
const CGAL::Eigen_dense_matrix<NT, D1, D2> operator* (const NT& scalar,
const CGAL::Eigen_dense_matrix<NT, D1, D2>& B)
{
return CGAL::Eigen_dense_matrix<NT, D1, D2>(scalar * B.m_matrix);
}
template <class NT, int D1, int D2>
const CGAL::Eigen_dense_matrix<NT, D1, D2> operator* (const CGAL::Eigen_dense_matrix<NT, D1, D2>& A,
const NT& scalar)
{
return CGAL::Eigen_dense_matrix<NT, D1, D2>(A.m_matrix * scalar);
}
template <class NT, int D1, int D2>
const CGAL::Eigen_dense_matrix<NT, D1, D2> operator/ (const CGAL::Eigen_dense_matrix<NT, D1, D2>& A,
const double& scalar)
{
return CGAL::Eigen_dense_matrix<NT, D1, D2>(A.m_matrix / scalar);
}
template <class NT, int D1, int D2>
const CGAL::Eigen_dense_matrix<NT, D1, D2> operator/ (const double& scalar,
const CGAL::Eigen_dense_matrix<NT, D1, D2> & A)
{
return CGAL::Eigen_dense_matrix<NT, D1, D2> (scalar / A.m_matrix);
}
// addition
template <class NT, int D1, int D2>
const CGAL::Eigen_dense_matrix<NT, D1, D2> operator+ (const CGAL::Eigen_dense_matrix<NT, D1, D2> & A,
const CGAL::Eigen_dense_matrix<NT, D1, D2> & B)
{
return CGAL::Eigen_dense_matrix<NT, D1, D2> (A.m_matrix + B.m_matrix);
}
// vector - matrix multiplication
template <class NT, int D1, int D2>
const Eigen_dense_vector<NT, D1> operator* (const CGAL::Eigen_dense_matrix<NT, D1, D2>& A,
const CGAL::Eigen_dense_vector<NT, D2>& V)
{
return Eigen_dense_vector<NT, D1>(A.m_matrix * V.m_vector);
}
}
// end namespace
#endif // CGAL_EIGEN_LINEAR_ALGEBRA_TRAITS_H