Merge branch 'Tangential_complex-cjamin-old' into Tangential_complex-cjamin

This commit is contained in:
Clement Jamin 2016-06-01 13:35:18 +02:00
commit 4958fcc746
55 changed files with 13914 additions and 127 deletions

View File

@ -2651,7 +2651,7 @@ rebuild_restricted_delaunay(OutdatedCells& outdated_cells,
# ifdef CGAL_MESH_3_PROFILING
std::cerr << std::endl << " Updating cells...";
WallClockTimer t;
Wall_clock_timer t;
size_t num_cells = c3t3_.number_of_cells_in_complex();
# endif

View File

@ -309,7 +309,7 @@ private:
#ifdef CGAL_MESH_3_PROFILING
std::cerr << "Computing moves...";
WallClockTimer t;
Wall_clock_timer t;
#endif
@ -688,7 +688,7 @@ operator()(int nb_iterations, Visitor visitor)
running_time_.start();
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
// Fill set containing moving vertices
@ -899,7 +899,7 @@ update_mesh(const Moves_vector& moves,
#ifdef CGAL_MESH_3_PROFILING
std::cerr << "Moving vertices...";
WallClockTimer t;
Wall_clock_timer t;
#endif
#ifdef CGAL_LINKED_WITH_TBB

View File

@ -325,7 +325,7 @@ Mesher_3<C3T3,MC,MD>::refine_mesh(std::string dump_after_refine_surface_prefix)
#ifdef CGAL_MESH_3_PROFILING
std::cerr << "Refining facets..." << std::endl;
WallClockTimer t;
Wall_clock_timer t;
#endif
facets_mesher_.refine(facets_visitor_);
#ifdef CGAL_MESH_3_PROFILING
@ -481,7 +481,7 @@ initialize()
{
#ifdef CGAL_MESH_3_PROFILING
std::cerr << "Initializing... ";
WallClockTimer t;
Wall_clock_timer t;
#endif
//=====================================
// Bounding box estimation

View File

@ -194,7 +194,7 @@ protected:
#ifdef CGAL_MESH_3_PROFILING
protected:
WallClockTimer m_timer;
Wall_clock_timer m_timer;
#endif
public:

View File

@ -28,10 +28,10 @@
// TBB timers
#ifdef CGAL_LINKED_WITH_TBB
#include <tbb/tick_count.h>
struct WallClockTimer
struct Wall_clock_timer
{
tbb::tick_count t;
WallClockTimer()
Wall_clock_timer()
{
t = tbb::tick_count::now();
}
@ -48,10 +48,10 @@
#else
#include <CGAL/Real_timer.h>
struct WallClockTimer
struct Wall_clock_timer
{
CGAL::Real_timer t;
WallClockTimer()
Wall_clock_timer()
{
t.start();
}

View File

@ -632,7 +632,7 @@ scan_triangulation_impl()
typedef typename Tr::Finite_cells_iterator Finite_cell_iterator;
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif

View File

@ -930,7 +930,7 @@ scan_triangulation_impl()
typedef typename Tr::Finite_facets_iterator Finite_facet_iterator;
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
#ifdef CGAL_MESH_3_VERY_VERBOSE

View File

@ -797,7 +797,7 @@ operator()(Visitor visitor)
running_time_.start();
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
// Build priority queue (we use one queue for all steps)

View File

@ -453,7 +453,7 @@ public: // methods
operator()(Visitor visitor = Visitor())
{
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
Mesh_optimization_return_code ret =
@ -964,7 +964,7 @@ pump_vertices(double sliver_criterion_limit,
Visitor& visitor)
{
#ifdef CGAL_MESH_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
init(sliver_criterion_limit);

View File

@ -0,0 +1,53 @@
// Copyright (c) 2014
// INRIA Saclay-Ile de France (France)
//
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 3 of the License,
// or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
//
// Author(s) : Marc Glisse
#ifndef CGAL_EPECK_D_H
#define CGAL_EPECK_D_H
#include <CGAL/NewKernel_d/Cartesian_base.h>
#include <CGAL/NewKernel_d/Wrapper/Cartesian_wrap.h>
#include <CGAL/NewKernel_d/Kernel_d_interface.h>
#include <CGAL/internal/Exact_type_selector.h>
namespace CGAL {
#define CGAL_BASE \
Cartesian_base_d<internal::Exact_field_selector<double>::Type, Dim>
template<class Dim>
struct Epeck_d_help1
: CGAL_BASE
{
CGAL_CONSTEXPR Epeck_d_help1(){}
CGAL_CONSTEXPR Epeck_d_help1(int d):CGAL_BASE(d){}
};
#undef CGAL_BASE
#define CGAL_BASE \
Kernel_d_interface< \
Cartesian_wrap< \
Epeck_d_help1<Dim>, \
Epeck_d<Dim> > >
template<class Dim>
struct Epeck_d
: CGAL_BASE
{
CGAL_CONSTEXPR Epeck_d(){}
CGAL_CONSTEXPR Epeck_d(int d):CGAL_BASE(d){}
};
#undef CGAL_BASE
}
#endif

View File

@ -66,6 +66,8 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
typedef typename Get_functor<Base, Point_dimension_tag>::type Point_dimension_d;
typedef typename Get_functor<Base, Side_of_oriented_sphere_tag>::type Side_of_oriented_sphere_d;
typedef typename Get_functor<Base, Power_side_of_power_sphere_tag>::type Power_side_of_power_sphere_d;
typedef typename Get_functor<Base, Power_center_tag>::type Power_center_d;
typedef typename Get_functor<Base, Power_distance_tag>::type Power_distance_d;
typedef typename Get_functor<Base, Contained_in_affine_hull_tag>::type Contained_in_affine_hull_d;
typedef typename Get_functor<Base, Construct_flat_orientation_tag>::type Construct_flat_orientation_d;
typedef typename Get_functor<Base, In_flat_orientation_tag>::type In_flat_orientation_d;
@ -73,6 +75,7 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
typedef typename Get_functor<Base, In_flat_power_side_of_power_sphere_tag>::type In_flat_power_side_of_power_sphere_d;
typedef typename Get_functor<Base, Point_to_vector_tag>::type Point_to_vector_d;
typedef typename Get_functor<Base, Vector_to_point_tag>::type Vector_to_point_d;
typedef typename Get_functor<Base, Translated_point_tag>::type Translated_point_d;
typedef typename Get_functor<Base, Scaled_vector_tag>::type Scaled_vector_d;
typedef typename Get_functor<Base, Difference_of_vectors_tag>::type Difference_of_vectors_d;
typedef typename Get_functor<Base, Difference_of_points_tag>::type Difference_of_points_d;
@ -188,6 +191,8 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
Point_of_sphere_d point_of_sphere_d_object()const{ return Point_of_sphere_d(*this); }
Side_of_oriented_sphere_d side_of_oriented_sphere_d_object()const{ return Side_of_oriented_sphere_d(*this); }
Power_side_of_power_sphere_d power_side_of_power_sphere_d_object()const{ return Power_side_of_power_sphere_d(*this); }
Power_center_d power_center_d_object()const{ return Power_center_d(*this); }
Power_distance_d power_distance_d_object()const{ return Power_distance_d(*this); }
Side_of_bounded_sphere_d side_of_bounded_sphere_d_object()const{ return Side_of_bounded_sphere_d(*this); }
Contained_in_affine_hull_d contained_in_affine_hull_d_object()const{ return Contained_in_affine_hull_d(*this); }
Contained_in_linear_hull_d contained_in_linear_hull_d_object()const{ return Contained_in_linear_hull_d(*this); }
@ -198,6 +203,7 @@ template <class Base_> struct Kernel_d_interface : public Base_ {
In_flat_power_side_of_power_sphere_d in_flat_power_side_of_power_sphere_d_object()const{ return In_flat_power_side_of_power_sphere_d(*this); }
Point_to_vector_d point_to_vector_d_object()const{ return Point_to_vector_d(*this); }
Vector_to_point_d vector_to_point_d_object()const{ return Vector_to_point_d(*this); }
Translated_point_d translated_point_d_object()const{ return Translated_point_d(*this); }
Scaled_vector_d scaled_vector_d_object()const{ return Scaled_vector_d(*this); }
Difference_of_vectors_d difference_of_vectors_d_object()const{ return Difference_of_vectors_d(*this); }
Difference_of_points_d difference_of_points_d_object()const{ return Difference_of_points_d(*this); }

View File

@ -52,7 +52,6 @@ template <class R_> struct Construct_sphere : Store_kernel<R_> {
}
template <class Iter>
result_type operator()(Iter f, Iter e)const{
typedef typename Get_type<R_, Point_tag>::type Point;
typename Get_functor<R_, Construct_circumcenter_tag>::type cc(this->kernel());
typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel());

View File

@ -75,6 +75,33 @@ template <class R_> struct Point_weight {
}
};
template <class R_> struct Power_distance : private Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Power_distance)
typedef typename Get_type<R_, Weighted_point_tag>::type first_argument_type;
typedef first_argument_type second_argument_type;
typedef typename Get_type<R_, FT_tag>::type result_type;
result_type operator()(first_argument_type const&a, second_argument_type const&b)const{
typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel());
typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel());
typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel());
return sd(pdw(a),pdw(b))-pw(a)-pw(b);
}
};
template <class R_> struct Power_distance_to_point : private Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Power_distance_to_point)
typedef typename Get_type<R_, Weighted_point_tag>::type first_argument_type;
typedef typename Get_type<R_, Point_tag>::type second_argument_type;
typedef typename Get_type<R_, FT_tag>::type result_type;
result_type operator()(first_argument_type const&a, second_argument_type const&b)const{
typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel());
typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel());
typename Get_functor<R_, Squared_distance_tag>::type sd(this->kernel());
return sd(pdw(a),b)-pw(a);
}
};
template<class R_> struct Power_side_of_power_sphere : private Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Power_side_of_power_sphere)
typedef R_ R;
@ -114,6 +141,56 @@ template<class R_> struct In_flat_power_side_of_power_sphere : private Store_ker
}
};
// Construct a point at (weighted) distance 0 from all the input
template <class R_> struct Power_center : Store_kernel<R_> {
CGAL_FUNCTOR_INIT_STORE(Power_center)
typedef typename Get_type<R_, Weighted_point_tag>::type WPoint;
typedef WPoint result_type;
typedef typename Get_type<R_, Point_tag>::type Point;
typedef typename Get_type<R_, FT_tag>::type FT;
template <class Iter>
result_type operator()(Iter f, Iter e)const{
// 2*(x-y).c == (x^2-wx^2)-(y^2-wy^2)
typedef typename R_::LA LA;
typedef typename LA::Square_matrix Matrix;
typedef typename LA::Vector Vec;
typedef typename LA::Construct_vector CVec;
typename Get_functor<R_, Compute_point_cartesian_coordinate_tag>::type c(this->kernel());
typename Get_functor<R_, Construct_ttag<Point_tag> >::type cp(this->kernel());
typename Get_functor<R_, Point_dimension_tag>::type pd(this->kernel());
typename Get_functor<R_, Squared_distance_to_origin_tag>::type sdo(this->kernel());
typename Get_functor<R_, Power_distance_to_point_tag>::type pdp(this->kernel());
typename Get_functor<R_, Point_drop_weight_tag>::type pdw(this->kernel());
typename Get_functor<R_, Point_weight_tag>::type pw(this->kernel());
typename Get_functor<R_, Construct_ttag<Weighted_point_tag> >::type cwp(this->kernel());
WPoint const& wp0 = *f;
Point const& p0 = pdw(wp0);
int d = pd(p0);
FT const& n0 = sdo(p0) - pw(wp0);
Matrix m(d,d);
Vec b = typename CVec::Dimension()(d);
// Write the point coordinates in lines.
int i;
for(i=0; ++f!=e; ++i) {
WPoint const& wp=*f;
Point const& p=pdw(wp);
FT const& np = sdo(p) - pw(wp);
for(int j=0;j<d;++j) {
m(i,j)=2*(c(p,j)-c(p0,j));
b[i] = np - n0;
}
}
CGAL_assertion (i == d);
Vec res = typename CVec::Dimension()(d);;
//std::cout << "Mat: " << m << "\n Vec: " << one << std::endl;
LA::solve(res, CGAL_MOVE(m), CGAL_MOVE(b));
//std::cout << "Sol: " << res << std::endl;
Point center = cp(d,LA::vector_begin(res),LA::vector_end(res));
FT const& r2 = pdp (wp0, center);
return cwp(CGAL_MOVE(center), r2);
}
};
}
CGAL_KD_DEFAULT_TYPE(Weighted_point_tag,(CGAL::KerD::Weighted_point<K>),(Point_tag),());
CGAL_KD_DEFAULT_FUNCTOR(Construct_ttag<Weighted_point_tag>,(CartesianDKernelFunctors::Construct_weighted_point<K>),(Weighted_point_tag,Point_tag),());
@ -121,5 +198,8 @@ CGAL_KD_DEFAULT_FUNCTOR(Point_drop_weight_tag,(CartesianDKernelFunctors::Point_d
CGAL_KD_DEFAULT_FUNCTOR(Point_weight_tag,(CartesianDKernelFunctors::Point_weight<K>),(Weighted_point_tag,Point_tag),());
CGAL_KD_DEFAULT_FUNCTOR(Power_side_of_power_sphere_tag,(CartesianDKernelFunctors::Power_side_of_power_sphere<K>),(Weighted_point_tag),(Power_side_of_power_sphere_raw_tag,Point_drop_weight_tag,Point_weight_tag));
CGAL_KD_DEFAULT_FUNCTOR(In_flat_power_side_of_power_sphere_tag,(CartesianDKernelFunctors::In_flat_power_side_of_power_sphere<K>),(Weighted_point_tag),(In_flat_power_side_of_power_sphere_raw_tag,Point_drop_weight_tag,Point_weight_tag));
CGAL_KD_DEFAULT_FUNCTOR(Power_distance_tag,(CartesianDKernelFunctors::Power_distance<K>),(Weighted_point_tag,Point_tag),(Squared_distance_tag,Point_drop_weight_tag,Point_weight_tag));
CGAL_KD_DEFAULT_FUNCTOR(Power_distance_to_point_tag,(CartesianDKernelFunctors::Power_distance_to_point<K>),(Weighted_point_tag,Point_tag),(Squared_distance_tag,Point_drop_weight_tag,Point_weight_tag));
CGAL_KD_DEFAULT_FUNCTOR(Power_center_tag,(CartesianDKernelFunctors::Power_center<K>),(Weighted_point_tag,Point_tag),(Compute_point_cartesian_coordinate_tag,Construct_ttag<Point_tag>,Construct_ttag<Weighted_point_tag>,Point_dimension_tag,Squared_distance_to_origin_tag,Point_drop_weight_tag,Point_weight_tag,Power_distance_to_point_tag));
} // namespace CGAL
#endif

View File

@ -216,6 +216,8 @@ namespace CGAL {
CGAL_DECL_COMPUTE(Hyperplane_translation);
CGAL_DECL_COMPUTE(Value_at);
CGAL_DECL_COMPUTE(Point_weight);
CGAL_DECL_COMPUTE(Power_distance);
CGAL_DECL_COMPUTE(Power_distance_to_point);
#undef CGAL_DECL_COMPUTE
#define CGAL_DECL_ITER_OBJ(X,Y,Z,C) struct X##_tag {}; \
@ -269,6 +271,7 @@ namespace CGAL {
CGAL_DECL_CONSTRUCT(Construct_max_vertex,Point);
CGAL_DECL_CONSTRUCT(Construct_circumcenter,Point);
CGAL_DECL_CONSTRUCT(Point_drop_weight,Point);
CGAL_DECL_CONSTRUCT(Power_center,Weighted_point);
#undef CGAL_DECL_CONSTRUCT
#if 0
#define CGAL_DECL_ITER_CONSTRUCT(X,Y) struct X##_tag {}; \

View File

@ -24,6 +24,7 @@ int main()
#include <iostream>
#include <sstream>
#include <CGAL/NewKernel_d/Types/Weighted_point.h>
#include <cmath>
//typedef CGAL::Cartesian_base_d<double,CGAL::Dimension_tag<2> > K0;
//typedef CGAL::Cartesian_base_d<CGAL::Interval_nt_advanced,CGAL::Dimension_tag<2> > KA;
@ -84,6 +85,7 @@ void test2(){
typedef typename K1::Ray_d R;
typedef typename K1::Iso_box_d IB;
typedef typename K1::Flat_orientation_d FO;
typedef typename K1::Weighted_point_d WP;
//typedef K1::Construct_point CP;
typedef typename K1::Construct_point_d CP;
@ -135,6 +137,13 @@ void test2(){
typedef typename K1::Construct_min_vertex_d CmV;
typedef typename K1::Construct_max_vertex_d CMV;
typedef typename K1::Compute_squared_radius_d SR;
typedef typename K1::Translated_point_d TP;
typedef typename K1::Power_center_d PC;
typedef typename K1::Power_distance_d PoD;
typedef typename K1::Weighted_point_d WP;
typedef typename K1::Construct_weighted_point_d CWP;
typedef typename K1::Point_drop_weight_d PDW;
typedef typename K1::Point_weight_d PW;
CGAL_USE_TYPE(AT);
CGAL_USE_TYPE(D);
@ -196,6 +205,12 @@ void test2(){
CmV cmv Kinit(construct_min_vertex_d_object);
CMV cMv Kinit(construct_max_vertex_d_object);
SR sr Kinit(compute_squared_radius_d_object);
TP tp Kinit(translated_point_d_object);
PC pc Kinit(power_center_d_object);
CWP cwp Kinit(construct_weighted_point_d_object);
PDW pdw Kinit(point_drop_weight_d_object);
PW pw Kinit(point_weight_d_object);
PoD pod Kinit(power_distance_d_object);
CGAL_USE(bc);
CGAL_USE(pol);
@ -203,11 +218,12 @@ void test2(){
CGAL_USE(cd);
CGAL_USE(cli);
CGAL_USE(cr);
using std::abs;
P a=cp(3,4);
assert(pd(a)==2);
assert(pv(a)[1]==4);
P b=vp(cv(5,6,7));
assert(fabs(b[0]-5./7)<.0001);
assert(abs(b[0]-5./7)<.0001);
assert(lc(b,a,1));
assert(!lc(a,b,0));
int rr[]={3,5,2};
@ -221,8 +237,8 @@ void test2(){
assert(cl(a,c)==CGAL::SMALLER);
assert(ll(b,c));
assert(cl(c,b)==CGAL::LARGER);
assert(fabs(m(a,c)[0]-3)<.0001);
assert(fabs(m(a,c)[1]-4.5)<.0001);
assert(abs(m(a,c)[0]-3)<.0001);
assert(abs(m(a,c)[1]-4.5)<.0001);
P d=cp(r,r+3,CGAL::Homogeneous_tag());
S s=cs(c,d);
std::cout << cc(a,1) << std::endl;
@ -277,9 +293,9 @@ void test2(){
assert(v.size()==1);
assert(lr(tab3+0,tab3+2)==1);
H h=ch(tab2+1,tab2+3,tab2[0]);
assert(fabs(va(h,x2)-1)<.0001);
assert(fabs(va(h,x3)-1)<.0001);
assert(fabs(va(h,x1)+1)<.0001);
assert(abs(va(h,x2)-1)<.0001);
assert(abs(va(h,x3)-1)<.0001);
assert(abs(va(h,x1)+1)<.0001);
H h2=ch(tab2+1,tab2+3,x1,CGAL::ON_POSITIVE_SIDE);
assert(hops(h2,x1));
assert(os(h2,x1)==CGAL::ON_POSITIVE_SIDE);
@ -340,20 +356,35 @@ void test2(){
Sp sp = csp(tabz+0,tabz+3);
P cent0=cos(sp);
P cent1=cos(tabz+0,tabz+3);
assert(fabs(cent0[0]-2)<.0001);
assert(fabs(cent0[1]+3)<.0001);
assert(fabs(cent1[0]-2)<.0001);
assert(fabs(cent1[1]+3)<.0001);
assert(fabs(sp.squared_radius()-25)<.0001);
assert(abs(cent0[0]-2)<.0001);
assert(abs(cent0[1]+3)<.0001);
assert(abs(cent1[0]-2)<.0001);
assert(abs(cent1[1]+3)<.0001);
assert(abs(sp.squared_radius()-25)<.0001);
#if 1
// Fails for an exact kernel
P psp0=ps(sp,0);
P psp1=ps(sp,1);
P psp2=ps(sp,2);
assert(!ed(psp0,psp1));
assert(!ed(psp0,psp2));
assert(!ed(psp2,psp1));
assert(fabs(sd(cent0,psp0)-25)<.0001);
assert(fabs(sd(cent0,psp1)-25)<.0001);
assert(fabs(sd(cent0,psp2)-25)<.0001);
assert(abs(sd(cent0,psp0)-25)<.0001);
assert(abs(sd(cent0,psp1)-25)<.0001);
assert(abs(sd(cent0,psp2)-25)<.0001);
#endif
P x2py1 = tp(x2,y1);
assert(x2py1[1]==-2);
WP tw[]={cwp(cp(5,0),1.5),cwp(cp(2,std::sqrt(3)),1),cwp(cp(2,-std::sqrt(3)),1)};
WP xw=pc(tw+0,tw+3);
assert(abs(pod(xw,tw[0]))<.0001);
assert(abs(pod(xw,tw[1]))<.0001);
assert(abs(pod(xw,tw[2]))<.0001);
assert(pdw(xw)[0]<2.95);
assert(pdw(xw)[0]>2.5);
assert(pw(xw)<2.95);
assert(pw(xw)>2.5);
P tl=cp(2,5);
P br=cp(4,-1);
@ -459,6 +490,7 @@ void test3(){
PD pd Kinit(point_dimension_d_object);
AI ai Kinit(affinely_independent_d_object);
SBDS sbds Kinit(side_of_bounded_sphere_d_object);
using std::abs;
P a; // Triangulation needs this :-(
a=cp(2,3,4);
assert(pd(a)==3);
@ -482,7 +514,7 @@ void test3(){
std::cout << *i << ' ';
std::cout << '\n';
P e=cp(-2,3,0);
assert(fabs(sd(e,a)-32)<.0001);
assert(abs(sd(e,a)-32)<.0001);
P tab[]={a,b,c,d,e};
std::cout << po (&tab[0],tab+4) << ' ';
std::cout << sos(&tab[0],tab+5) << ' ';

View File

@ -91,16 +91,26 @@ public:
struct Construct_cartesian_const_iterator_d: public Base_traits::Construct_cartesian_const_iterator_d{
PointPropertyMap ppmap;
using Base_traits::Construct_cartesian_const_iterator_d::operator();
Construct_cartesian_const_iterator_d(const typename Base_traits::Construct_cartesian_const_iterator_d& base, const PointPropertyMap& ppmap_)
:Base_traits::Construct_cartesian_const_iterator_d(base), ppmap(ppmap_){}
typename Base_traits::Cartesian_const_iterator_d operator()(const Point_with_info& p) const
{ return this->operator() (get(ppmap,p)); }
{ return Base_traits::Construct_cartesian_const_iterator_d::operator() (get(ppmap,p)); }
typename Base_traits::Cartesian_const_iterator_d operator()(const Point_with_info& p, int) const
{ return this->operator() (get(ppmap,p),0); }
{ return Base_traits::Construct_cartesian_const_iterator_d::operator() (get(ppmap,p),0); }
// These 2 additional operators forward the call to Base_traits.
// This is needed because of an undocumented requirement of
// Orthogonal_k_neighbor_search and Orthogonal_incremental_neighbor_search:
// Traits::Construct_cartesian_const_iterator should be callable
// on the query point type
typename Base_traits::Cartesian_const_iterator_d operator()(const typename Base_traits::Point_d& p) const
{ return Base_traits::Construct_cartesian_const_iterator_d::operator() (p); }
typename Base_traits::Cartesian_const_iterator_d operator()(const typename Base_traits::Point_d& p, int) const
{ return Base_traits::Construct_cartesian_const_iterator_d::operator() (p,0); }
};
struct Construct_iso_box_d: public Base::Construct_iso_box_d{

View File

@ -0,0 +1,39 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
project( Tangential_complex_apps )
cmake_minimum_required(VERSION 2.6.2)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
cmake_policy(VERSION 2.8.4)
else()
cmake_policy(VERSION 2.6)
endif()
endif()
find_package(CGAL QUIET COMPONENTS Core )
if ( CGAL_FOUND )
include( ${CGAL_USE_FILE} )
find_package(Eigen3 3.1.0)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
include_directories (BEFORE "../../include")
include( CGAL_CreateSingleSourceCGALProgram )
create_single_source_cgal_program( "euler_charact.cpp" )
else()
message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.")
endif()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()

View File

@ -0,0 +1,19 @@
#include <CGAL/Tangential_complex/Simplicial_complex.h>
using namespace CGAL::Tangential_complex_;
int main(int argc, char *argv[])
{
if (argc != 2)
{
std::cout << "Usage: euler_charact <input.off>\n";
return 0;
}
Simplicial_complex complex;
complex.load_simplices_from_OFF(argv[1]);
complex.euler_characteristic(true);
return 0;
}

View File

@ -0,0 +1,81 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
project( Tangential_complex_benchmark )
cmake_minimum_required(VERSION 2.6.2)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
cmake_policy(VERSION 2.8.4)
else()
cmake_policy(VERSION 2.6)
endif()
endif()
# Creates a new CMake option, turned ON by default
option(ACTIVATE_MSVC_PRECOMPILED_HEADERS
"Activate precompiled headers in MSVC"
OFF)
# Macro to add precompiled headers for MSVC
# This function does two things:
# 1. Enable precompiled headers on each file which is listed in "SourcesVar".
# 2. Add the content of "PrecompiledSource" (e.g. "StdAfx.cpp") to "SourcesVar".
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(Sources ${${SourcesVar}})
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\"")
SET_SOURCE_FILES_PROPERTIES(${Sources}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeader}\"")
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
# The compiler might need more memory because of precompiled headers
if(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS AND NOT(MSVC_VERSION LESS 1310))
set(CGAL_C_FLAGS "${CGAL_C_FLAGS} /Zm1000")
set(CGAL_CXX_FLAGS "${CGAL_CXX_FLAGS} /Zm1000")
endif()
find_package(CGAL QUIET COMPONENTS Core )
if ( CGAL_FOUND )
include( ${CGAL_USE_FILE} )
find_package( TBB QUIET )
if( TBB_FOUND )
include(${TBB_USE_FILE})
list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES})
endif()
include( CGAL_CreateSingleSourceCGALProgram )
find_package(Eigen3 3.1.0)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
include_directories (BEFORE "../../include")
include_directories (BEFORE "include")
set (SOURCE_FILES "benchmark_tc.cpp")
ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" SOURCE_FILES)
create_single_source_cgal_program( ${SOURCE_FILES} )
set (SOURCE_FILES "benchmark_mesh_d.cpp")
ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" SOURCE_FILES)
create_single_source_cgal_program( ${SOURCE_FILES} )
else()
message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.")
endif()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()

View File

@ -0,0 +1,2 @@
// Build the precompiled headers.
#include "StdAfx.h"

View File

@ -0,0 +1,14 @@
#ifndef STDAFX_H
#define STDAFX_H
// CGAL
#include <CGAL/Tangential_complex/config.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Regular_triangulation_euclidean_traits.h>
#include <CGAL/Regular_triangulation.h>
#include <CGAL/Delaunay_triangulation.h>
#include <CGAL/Tangential_complex/utilities.h>
#include <CGAL/Tangential_complex/Point_cloud.h>
#include <CGAL/Combination_enumerator.h>
#endif //STDAFX_H

View File

@ -0,0 +1,236 @@
// Copyright (c) 2012 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
//
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <ctime>
template<typename value_type = std::string>
class Simple_XML_exporter
{
public:
typedef value_type Value_type;
typedef std::vector<value_type> Element;
typedef std::map<std::string, value_type> Element_with_map;
typedef std::vector<Element> List_of_elements;
Simple_XML_exporter(
const std::string &list_name,
const std::string &element_name,
const std::vector<std::string> &subelement_names,
bool add_timestamp = true)
: m_list_name(list_name),
m_element_name(element_name),
m_subelement_names(subelement_names),
m_add_timestamp(add_timestamp)
{}
bool add_element(const Element &element)
{
if (element.size() == m_subelement_names.size())
{
m_list_of_elements.push_back(element);
return true;
}
else
{
std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl;
return false;
}
}
bool add_element(Element_with_map &element)
{
Element elt;
std::vector<std::string>::const_iterator
it_subelement_name = m_subelement_names.begin();
std::vector<std::string>::const_iterator
it_subelement_name_end = m_subelement_names.end();
for ( ; it_subelement_name != it_subelement_name_end ; ++it_subelement_name)
{
elt.push_back(element[*it_subelement_name]);
}
return add_element(elt);
}
bool export_to_xml(const std::string &filename) const
{
std::ofstream xmlfile;
xmlfile.open(filename.c_str());
xmlfile << "<?xml version='1.0'?>" << std::endl;
xmlfile << "<" << m_list_name << ">" << std::endl;
typename List_of_elements::const_iterator it_element = m_list_of_elements.begin();
typename List_of_elements::const_iterator it_element_end = m_list_of_elements.end();
for (int id = 1 ; it_element != it_element_end ; ++it_element, ++id)
{
xmlfile << " <" << m_element_name << ">" << std::endl;
std::vector<std::string>::const_iterator
it_subelement_name = m_subelement_names.begin();
std::vector<std::string>::const_iterator
it_subelement_name_end = m_subelement_names.end();
if (m_add_timestamp)
xmlfile << " <id> " << time(NULL) << " </id>" << std::endl;
for (int i = 0 ;
it_subelement_name != it_subelement_name_end ;
++it_subelement_name, ++i)
{
xmlfile
<< " <" << *it_subelement_name << "> "
<< (*it_element)[i]
<< " </" << *it_subelement_name << ">" << std::endl;
}
xmlfile << " </" << m_element_name << ">" << std::endl;
}
xmlfile << "</" << m_list_name << ">" << std::endl;
xmlfile.close();
return 0;
}
protected:
std::string m_list_name;
std::string m_element_name;
std::vector<std::string> m_subelement_names;
List_of_elements m_list_of_elements;
bool m_add_timestamp;
};
template<typename value_type = std::string>
class Streaming_XML_exporter
{
public:
typedef value_type Value_type;
typedef std::vector<value_type> Element;
typedef std::map<std::string, value_type> Element_with_map;
typedef std::vector<Element> List_of_elements;
Streaming_XML_exporter(
const std::string &filename,
const std::string &list_name,
const std::string &element_name,
const std::vector<std::string> &subelement_names,
bool add_timestamp = true)
: m_list_name(list_name),
m_element_name(element_name),
m_subelement_names(subelement_names),
m_add_timestamp(add_timestamp)
{
m_xml_fstream.open(filename.c_str());
if (m_xml_fstream.good())
{
m_xml_fstream << "<?xml version='1.0'?>" << std::endl;
m_xml_fstream << "<" << m_list_name << ">" << std::endl;
}
else
{
std::cerr << "Could not open file '" << filename << "'." << std::endl;
}
}
virtual ~Streaming_XML_exporter()
{
close_file();
}
void close_file()
{
m_xml_fstream.close();
}
bool add_element(const Element &element)
{
if (element.size() == m_subelement_names.size())
{
m_xml_fstream << " <" << m_element_name << ">" << std::endl;
std::vector<std::string>::const_iterator
it_subelement_name = m_subelement_names.begin();
std::vector<std::string>::const_iterator
it_subelement_name_end = m_subelement_names.end();
if (m_add_timestamp)
{
m_xml_fstream << " <id> " << time(NULL) << " </id>" << std::endl;
}
for (int i = 0 ;
it_subelement_name != it_subelement_name_end ;
++it_subelement_name, ++i)
{
m_xml_fstream
<< " <" << *it_subelement_name << "> "
<< element[i]
<< " </" << *it_subelement_name << ">" << std::endl;
}
m_xml_fstream << " </" << m_element_name << ">" << std::endl;
// Save current pointer position
std::ofstream::streampos pos = m_xml_fstream.tellp();
// Close the XML file (temporarily) so that the XML file is always correct
m_xml_fstream << "</" << m_list_name << ">" << std::endl;
// Restore the pointer position so that the next "add_element" will overwrite
// the end of the file
m_xml_fstream.seekp(pos);
m_xml_fstream.flush();
return true;
}
else
{
std::cerr << "ERROR: element.size() == m_subelement_names.size()" << std::endl;
return false;
}
}
bool add_element(Element_with_map &element)
{
Element elt;
std::vector<std::string>::const_iterator
it_subelement_name = m_subelement_names.begin();
std::vector<std::string>::const_iterator
it_subelement_name_end = m_subelement_names.end();
for ( ; it_subelement_name != it_subelement_name_end ; ++it_subelement_name)
{
elt.push_back(element[*it_subelement_name]);
}
return add_element(elt);
}
protected:
std::ofstream m_xml_fstream;
std::string m_list_name;
std::string m_element_name;
std::vector<std::string> m_subelement_names;
bool m_add_timestamp;
};

View File

@ -0,0 +1,430 @@
//#undef CGAL_LINKED_WITH_TBB // CJTODO TEMP
// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB
// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/)
#ifdef _DEBUG
# define TBB_USE_THREADING_TOOL
#endif
#include <cstddef>
const std::size_t ONLY_LOAD_THE_FIRST_N_POINTS = 100000000;
#include <CGAL/assertions_behaviour.h>
#include <CGAL/Mesh_d.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Random.h>
#include <CGAL/Mesh_3/Profiling_tools.h>
#include "../../test/Tangential_complex/testing_utilities.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <boost/range/adaptor/strided.hpp>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <math.h>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/task_scheduler_init.h>
#endif
using namespace CGAL::Tangential_complex_;
const char * const BENCHMARK_SCRIPT_FILENAME = "benchmark_script.txt";
typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_d Point;
typedef CGAL::Mesh_d<Kernel, Kernel, CGAL::Parallel_tag> Mesh;
//#define CHECK_IF_ALL_SIMPLICES_ARE_IN_THE_AMBIENT_DELAUNAY
//#define MESH_D_INPUT_STRIDES 10 // only take one point every MESH_D_INPUT_STRIDES points
//#define MESH_D_NO_EXPORT
//#define CGAL_MESH_D_USE_LINEAR_PROG_TO_COMPUTE_INTERSECTION
//#define CGAL_MESH_D_FILTER_BY_TESTING_ALL_VERTICES_TANGENT_PLANES
template <typename Mesh, typename Indexed_simplex_range = void>
bool export_to_off(
Mesh const& mesh,
std::string const& input_name_stripped,
std::string const& suffix,
Indexed_simplex_range const *p_simpl_to_color_in_red = NULL,
Indexed_simplex_range const *p_simpl_to_color_in_green = NULL,
Indexed_simplex_range const *p_simpl_to_color_in_blue = NULL)
{
#ifdef MESH_D_NO_EXPORT
return true;
#endif
if (mesh.intrinsic_dimension() <= 3)
{
std::stringstream output_filename;
output_filename << "output/" << input_name_stripped << "_"
<< mesh.intrinsic_dimension() << "_in_R"
<< mesh.ambient_dimension() << "_"
<< mesh.number_of_vertices() << "v"
<< suffix << ".off";
std::ofstream off_stream(output_filename.str().c_str());
mesh.export_to_off(
off_stream,
p_simpl_to_color_in_red,
p_simpl_to_color_in_green,
p_simpl_to_color_in_blue);
return true;
}
return false;
}
void make_mesh(
std::vector<Point> &points,
int intrinsic_dim,
bool sparsify = true,
double sparsity = 0.01,
const char *input_name = "mesh")
{
Kernel k;
Kernel lk; // local kernel (intrinsic dim)
//===========================================================================
// Init
//===========================================================================
Wall_clock_timer t;
// Get input_name_stripped
std::string input_name_stripped(input_name);
size_t slash_index = input_name_stripped.find_last_of('/');
if (slash_index == std::string::npos)
slash_index = input_name_stripped.find_last_of('\\');
if (slash_index == std::string::npos)
slash_index = 0;
else
++slash_index;
input_name_stripped = input_name_stripped.substr(
slash_index, input_name_stripped.find_last_of('.') - slash_index);
int ambient_dim = k.point_dimension_d_object()(*points.begin());
#ifdef CGAL_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
std::vector<Point> points_not_sparse = points;
#endif
//===========================================================================
// Sparsify point set if requested
//===========================================================================
if (sparsify)
{
std::size_t num_points_before = points.size();
points = sparsify_point_set(k, points, sparsity*sparsity);
std::cerr << "Number of points before/after sparsification: "
<< num_points_before << " / " << points.size() << "\n";
}
//===========================================================================
// Compute Tangential Complex
//===========================================================================
#ifdef CGAL_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
Mesh mesh(points.begin(), points.end(), sparsity, intrinsic_dim,
points_not_sparse.begin(), points_not_sparse.end(), k, lk);
#else
Mesh mesh(points.begin(), points.end(), sparsity, intrinsic_dim, k, lk);
#endif
double init_time = t.elapsed(); t.reset();
std::vector<std::set<std::size_t> > uncertain_simplices;
mesh.compute_mesh(&uncertain_simplices);
double computation_time = t.elapsed(); t.reset();
mesh.display_stats();
//=========================================================================
// Export to OFF
//=========================================================================
t.reset();
bool exported = export_to_off(
mesh, input_name_stripped, "", &uncertain_simplices);
double export_time = (exported ? t.elapsed() : -1);
t.reset();
//===========================================================================
// Is the result a pure pseudomanifold?
//===========================================================================
std::size_t num_wrong_dim_simplices,
num_wrong_number_of_cofaces,
num_unconnected_stars;
std::set<std::set<std::size_t> > wrong_dim_simplices;
std::set<std::set<std::size_t> > wrong_number_of_cofaces_simplices;
std::set<std::set<std::size_t> > unconnected_stars_simplices;
bool is_pure_pseudomanifold = mesh.complex().is_pure_pseudomanifold(
intrinsic_dim, mesh.number_of_vertices(), false, false, 1,
&num_wrong_dim_simplices, &num_wrong_number_of_cofaces,
&num_unconnected_stars,
&wrong_dim_simplices, &wrong_number_of_cofaces_simplices,
&unconnected_stars_simplices);
// Stats about the simplices
mesh.complex().display_stats();
std::size_t num_edges = mesh.complex().num_K_simplices<1>();
std::size_t num_triangles = mesh.complex().num_K_simplices<2>();
std::cerr << "Euler caract.: V - E + F = "
<< mesh.number_of_vertices()
<< " - " << (std::ptrdiff_t) num_edges
<< " + " << (std::ptrdiff_t) num_triangles
<< " = "
<< yellow
<< (std::ptrdiff_t) mesh.number_of_vertices()
- (std::ptrdiff_t) num_edges
+ (std::ptrdiff_t) num_triangles
<< white << "\n";
//===========================================================================
// Display info
//===========================================================================
std::cerr
<< "\n================================================\n"
<< "Number of vertices: " << mesh.number_of_vertices() << "\n"
<< "Pure pseudomanifold: " << yellow
<< (is_pure_pseudomanifold ? "YES" : "NO") << white << "\n"
<< "Computation times (seconds): \n"
<< " * Mesh: " << init_time + computation_time << "\n"
<< " - Init + kd-tree = " << init_time << "\n"
<< " - Mesh computation = " << computation_time << "\n"
//<< " * Export to OFF : " << export_before_time << "\n"
<< "================================================\n\n";
}
int main()
{
CGAL::set_error_behaviour(CGAL::ABORT);
#ifdef CGAL_LINKED_WITH_TBB
# ifdef _DEBUG
int num_threads = 1;
# else
int num_threads = 8;
# endif
#endif
unsigned int seed = static_cast<unsigned int>(time(NULL));
CGAL::default_random = CGAL::Random(seed);
std::cerr << "Random seed = " << seed << "\n";
std::ifstream script_file;
script_file.open(BENCHMARK_SCRIPT_FILENAME);
// Script?
// Script file format: each line gives
// - Filename (point set) or "generate_XXX" (point set generation)
// - Ambient dim
// - Intrinsic dim
// - Number of iterations with these parameters
if (script_file.is_open())
{
int i = 1;
#ifdef CGAL_LINKED_WITH_TBB
# ifdef BENCHMARK_WITH_1_TO_MAX_THREADS
for(num_threads = 1 ;
num_threads <= tbb::task_scheduler_init::default_num_threads() ;
++num_threads)
# endif
#endif
{
#ifdef CGAL_LINKED_WITH_TBB
tbb::task_scheduler_init init(
num_threads > 0 ? num_threads : tbb::task_scheduler_init::automatic);
#endif
std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME
<< "' found.\n";
script_file.seekg(0);
while (script_file.good())
{
std::string line;
std::getline(script_file, line);
if (line.size() > 1 && line[0] != '#')
{
boost::replace_all(line, "\t", " ");
boost::trim_all(line);
std::cerr << "\n\n";
std::cerr << "*****************************************\n";
std::cerr << "******* " << line << "\n";
std::cerr << "*****************************************\n";
std::stringstream sstr(line);
std::string input;
std::string param1;
std::string param2;
std::string param3;
std::size_t num_points;
int ambient_dim;
int intrinsic_dim;
char sparsify;
double sparsity;
char perturb, add_high_dim_simpl, collapse;
double time_limit_for_perturb;
int num_iteration;
sstr >> input;
sstr >> param1;
sstr >> param2;
sstr >> param3;
sstr >> num_points;
sstr >> ambient_dim;
sstr >> intrinsic_dim;
sstr >> sparsify;
sstr >> sparsity;
sstr >> perturb;
sstr >> add_high_dim_simpl;
sstr >> collapse;
sstr >> time_limit_for_perturb;
sstr >> num_iteration;
for (int j = 0 ; j < num_iteration ; ++j)
{
std::string input_stripped = input;
size_t slash_index = input_stripped.find_last_of('/');
if (slash_index == std::string::npos)
slash_index = input_stripped.find_last_of('\\');
if (slash_index == std::string::npos)
slash_index = 0;
else
++slash_index;
input_stripped = input_stripped.substr(
slash_index, input_stripped.find_last_of('.') - slash_index);
std::cerr << "\nMesh #" << i << "...\n";
#ifdef CGAL_MESH_D_PROFILING
Wall_clock_timer t_gen;
#endif
std::vector<Point> points;
Mesh::TS_container tangent_spaces;
if (input == "generate_moment_curve")
{
points = generate_points_on_moment_curve<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_plane")
{
points = generate_points_on_plane<Kernel>(
num_points, intrinsic_dim, ambient_dim);
}
else if (input == "generate_sphere_d")
{
points = generate_points_on_sphere_d<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()), // radius
std::atof(param2.c_str())); // radius_noise_percentage
}
else if (input == "generate_two_spheres_d")
{
points = generate_points_on_two_spheres_d<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()),
std::atof(param2.c_str()),
std::atof(param3.c_str()));
}
else if (input == "generate_3sphere_and_circle_d")
{
CGAL_assertion(intrinsic_dim == 3);
CGAL_assertion(ambient_dim == 5);
points = generate_points_on_3sphere_and_circle<Kernel>(
num_points,
std::atof(param1.c_str()));
}
else if (input == "generate_torus_3D")
{
points = generate_points_on_torus_3D<Kernel>(
num_points,
std::atof(param1.c_str()),
std::atof(param2.c_str()),
param3 == "Y");
}
else if (input == "generate_torus_d")
{
points = generate_points_on_torus_d<Kernel>(
num_points,
intrinsic_dim,
param1 == "Y", // uniform
std::atof(param2.c_str())); // radius_noise_percentage
}
else if (input == "generate_klein_bottle_3D")
{
points = generate_points_on_klein_bottle_3D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_klein_bottle_4D")
{
points = generate_points_on_klein_bottle_4D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_klein_bottle_variant_5D")
{
points = generate_points_on_klein_bottle_variant_5D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else
{
load_points_from_file<Kernel, typename Mesh::Tangent_space_basis>(
input, std::back_inserter(points),
std::back_inserter(tangent_spaces),
ONLY_LOAD_THE_FIRST_N_POINTS);
}
#ifdef CGAL_MESH_D_PROFILING
std::cerr << "Point set generated/loaded in " << t_gen.elapsed()
<< " seconds.\n";
#endif
if (!points.empty())
{
#if defined(MESH_D_INPUT_STRIDES) && MESH_D_INPUT_STRIDES > 1
auto p = points | boost::adaptors::strided(MESH_D_INPUT_STRIDES); // CJTODO C++11 (auto)
std::vector<Point> points(p.begin(), p.end());
std::cerr << "****************************************\n"
<< "WARNING: taking 1 point every " << MESH_D_INPUT_STRIDES
<< " points.\n"
<< "****************************************\n";
#endif
make_mesh(
points, intrinsic_dim, sparsify == 'Y', sparsity,
input.c_str());
std::cerr << "Mesh #" << i++ << " done.\n";
std::cerr << "\n---------------------------------\n\n";
}
else
{
std::cerr << "Mesh #" << i++ << ": no points loaded.\n";
}
}
}
}
script_file.seekg(0);
script_file.clear();
}
script_file.close();
}
// Or not script?
else
{
std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' NOT found.\n";
}
system("pause");
return 0;
}

View File

@ -0,0 +1,136 @@
#---------------------------------------------------------------------------------------------------------------------------------------------------------
# Input PARAM1 PARAM2 PARAM3 NUM_P AMB INTR SPARSIFY SPARSITY PERTURB ADD_HDIM COLLAPSE FIX_TIME_LIMIT NUM_ITERATIONS
#---------------------------------------------------------------------------------------------------------------------------------------------------------
#---------------------------------------------------------------- Alpha TC tests ------------------------------------------------------------------------
#generate_sphere_d 1 0 - 8 2 1 Y 0.005 N Y N 3 1 #No noise => OK: 6 2d with a perturb sometimes
#generate_sphere_d 1 0 - 50 2 1 Y 0.005 N Y N 3 1 #No noise => OK: 49 1d
#generate_sphere_d 1 1 - 50 2 1 Y 0.005 N Y N 3 1 #Noise => OK: 45 2d + 3 3d
#generate_torus_d N - - 15 2 1 Y 0.05 N Y N 10 1
#generate_sphere_d 0.302 0 - 8 3 2 Y 0.005 N Y N 60 1 #No noise => OK: 7 3d with a perturb sometimes
#generate_sphere_d 0.302 0 - 50 3 2 Y 0.005 N Y N 60 1 #No noise => no inconsitencies
#generate_sphere_d 0.302 3 - 50 3 2 Y 0.005 N Y N 60 1 #Noise => OK: 90 2d + 3 3d
#generate_sphere_d 1 1 - 500 4 3 Y 0.005 N Y N 60 1 #Noise 1% => OK: 3113 3d + 35 4d
#generate_sphere_d 1 2 - 500 4 3 Y 0.005 N Y N 60 1 #Noise 2% => OK: 2969 3d + 91 4d
#generate_sphere_d 1 2 - 5000 4 3 Y 0.005 N Y N 60 1 #Noise 2% => OK: 27905 3d + 2485 4d
#generate_sphere_d 0.302 2 - 300 2 1 Y 0.005 N Y N 60 1
#generate_torus_3D 2 1 N 200 3 2 Y 0.05 N Y N 600 1 #OK: 1048 3d ~170s
#generate_torus_3D 2 1 N 2000 3 2 Y 0.05 N Y N 600 1 #OK: 3545 2d + 27 3d ~35s
#generate_torus_d N 1 - 50 4 2 Y 0.05 N Y N 3 1 #OK: 431 4d
#generate_torus_d N 1 - 500 4 2 Y 0.05 N Y N 3 1 #OK: 881 2d + 37 3d
#generate_torus_d Y 1 - 250 4 2 Y 0.05 N Y N 3 1 #OK: 80 d2 + 185 d3
#generate_torus_d N - - 50 6 3 Y 0.05 Y Y N 10 1 #
#generate_torus_d Y - - 700 6 3 Y 0.05 Y Y N 100 1 #Grid
#generate_torus_d N - - 50000 6 3 Y 0.05 Y Y N 0 1 #Too long...
#generate_moment_curve 0 1 - 10 3 1 Y 0.005 N Y N 60 1
#generate_two_spheres_d 3 4 - 500 3 2 Y 0.05 N Y N 10 1 #OK: 320 2d + 1167 3d
#generate_klein_bottle_4D 40 15 - 500 4 2 Y 0.2 N Y N 60 1 #OK: 901 d2 + 50 d3 + 1 d4
#data/SO3_10000.txt - - - 0 9 3 Y 0.05 Y Y N 300 1 #Too long. Be careful with the memory consumption!
#data/buddha_100kv.txt - - - 0 3 2 Y 0.005 Y Y N 120 1 #Too long...
#data/fandisk.txt - - - 0 3 2 Y 0.005 Y Y N 5 1 #NOT OK: Tq & V do not intersect
#---------------------------------------------------------------- Fixed-alpha TC tests ------------------------------------------------------------------------
#generate_sphere_d 0.302 - - 70 2 1 Y 0.005 N N N 60 1
#generate_sphere_d 0.304 0 - 100 3 2 Y 0.05 N N N 60 1
#generate_sphere_d 3 0 - 100 4 3 Y 0.05 N N N 60 1
#generate_sphere_d 3 0 - 1000 5 4 Y 0.05 N N N 60 1
#generate_two_spheres_d 3 4 - 1000 3 2 Y 0.05 N N N 10 1
#generate_two_spheres_d 3 10 - 1000 4 3 Y 0.05 N N N 10 1
#generate_two_spheres_d 3 10 - 2000 5 4 Y 0.05 N N N 10 1
#generate_3sphere_and_circle_d 3 - - 100000 5 3 Y 0.05 N N N 7000 1
#generate_plane - - - 100 4 3 Y 0.005 N N N 3000 1
#generate_plane - - - 10 5 4 Y 0.005 N N N 3000 1
#generate_klein_bottle_4D 40 15 - 500 4 2 Y 0.2 N N N 60 1
#generate_klein_bottle_4D 40 15 - 2000 4 2 Y 0.2 N N N 60 1
#generate_klein_bottle_4D 8 5 - 5000 4 2 Y 0.2 N N N 60 1 #Takes forever
#generate_torus_3D 2 1 Y 150 3 2 Y 0.05 N N N 600 1
#generate_torus_3D 2 1 N 100000 3 2 Y 0.55 N N N 600 1
#generate_torus_d N - - 18 2 1 Y 0.01 N N N 30 1
#generate_torus_d N - - 50000 2 1 Y 0.7 N N N 30 1
#generate_torus_d Y - - 2 2 1 N 0.01 N N N 30 1
#generate_torus_d Y - - 15 4 2 Y 0.05 N N N 30 1
#generate_torus_d N 0 - 150 4 2 Y 0.05 N N N 10 1
#generate_torus_d N - - 20000 4 2 Y 1.0 N N N 30 1
#generate_torus_d Y 0 - 5000 6 3 Y 0.05 N N N 300 1
#generate_torus_d N - - 20000 6 3 Y 0.05 N N N 60 1
#generate_torus_d N - - 100000 6 3 Y 0.05 N N N 3000 1
#generate_torus_d N - - 1000000 6 3 Y 0.3 N N N 3000 1
#generate_torus_d Y - - 1000 8 4 Y 0.05 N N N 60 1
#data/SO3_10000.txt - - - 0 9 3 Y 0.1 N N N 60 1
#---------------------------------------------------------- Spatial search benchmarking --------------------------------------------------------------
#generate_torus_3D 2 1 Y 10000 3 2 N 0 Y N N 600 1
#data/buddha_100kv.txt - - - 0 3 2 N 0 N Y N 120 1
#generate_torus_d N - - 10000 30 15 N 0 Y N N 3600 1
#generate_torus_d N - - 100000 12 6 N 0 Y N N 3600 1
#data/SO3_50000.txt - - - 0 9 3 N 0 Y N N 60 1
#data/Cy8.txt - - - 0 24 2 N 0 N Y N 60 1
#generate_sphere_d 0.5 - - 10000 2 1 N 0 N N Y 60 1
#generate_sphere_d 0.5 - - 10000 3 2 N 0 N N Y 60 1
#generate_sphere_d 0.5 - - 10000 4 3 N 0 N N Y 60 1
#generate_sphere_d 0.5 - - 10000 5 4 N 0 N N Y 60 1
#generate_sphere_d 0.5 - - 10000 6 5 N 0 N N Y 60 1
#generate_sphere_d 0.5 - - 10000 7 6 N 0 N N Y 60 1
#---------------------------------------------------------- Very small cases for Debug mode --------------------------------------------------------------
#generate_sphere_d 4 - - 20 3 2 Y 0.05 N N N 60 1
#generate_sphere_d 3 - - 70 3 2 Y 0.05 N N N 60 1
#generate_sphere_d 3 - - 1000 3 2 Y 0.05 N N N 60 1
#generate_sphere_d 3 - - 70 4 3 Y 0.05 N N N 60 1
#generate_sphere_d 3 - - 70 5 4 Y 0.05 N N N 60 1
#generate_klein_bottle_variant_5D 4 3 - 70 5 2 Y 0.05 N N N 60 1
#data/SO3_10000.txt - - - 0 9 3 Y 0.7 N N N 60 1
#generate_moment_curve 0 1 - 30 3 1 Y 0.005 N N N 60 1
#------------------------------------------------------------------ From files --------------------------------------------------------------------------
#data/SO3_50000.txt - - - 0 9 3 Y 0.05 Y Y N 60 1
#data/SO3_10000.txt - - - 0 9 3 Y 0.05 Y N N 60 1
#data/cube3D_eps_0.1.txt - - - 0 3 2 Y 0.05 N Y N 3000 1
#data/cube4D_eps_0.1.txt - - - 0 4 3 Y 0.05 N Y N 3000 1
#data/cube5D_eps_0.1.txt - - - 0 5 4 Y 0.05 N Y N 3000 1
#data/Cy8.txt - - - 0 24 2 Y 0.1 N Y N 60 1
#data/Kl.txt - - - 0 5 2 Y 0.05 N Y N 60 1
#data/S3.txt - - - 0 4 3 Y 0.05 N Y N 60 1
data/Alvarez_variete_k2_D4_29700p.txt - - - 0 4 2 Y 0.01 Y N N 36000 1
#data/Alvarez_variete_k2_D4_300k_random.txt - - - 0 4 2 Y 0.01 Y N N 36000 1
#data/Alvarez_variete_k2_D4_29700p.txt - - - 0 4 2 Y 0.01 Y N N 500000 1
#data/Alvarez_variete_k2_D4_297k.txt - - - 0 4 2 Y 0.001 Y N N 500000 1
#data/Alvarez_variete_k2_D4_297k.txt - - - 0 4 2 Y 0.5 Y N N 500000 1
#data/Alvarez_variete_k2_D4_300k_random.txt - - - 0 4 2 Y 0.001 Y N N 500000 1
#data/Alvarez_variete_k2_D4_300k_random.txt - - - 0 4 2 Y 0.2 Y N N 500000 1
# With pre-computed tangent spaces
#data/test.pwt - - - 0 4 2 Y 0.01 N N N 500000 1
#data/Alvarez_variete_k2_D4_30000p.txt - - - 0 4 2 Y 0.01 Y N N 500000 1
#data/Alvarez_variete_k2_D4_30000p_with_TSB.pwt - - - 0 4 2 N 0.01 Y N N 500000 1
#---------------------------------------------------------------------- 3D meshes -----------------------------------------------------------------------
#data/buddha_100kv.txt - - - 0 3 2 Y 0.005 N Y N 120 1
#data/fandisk.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#data/fertility.txt - - - 0 3 2 Y 0.4 N Y N 60 1
#data/bunny.txt - - - 0 3 2 Y 0.5 Y N N 60 1
#data/blob.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#data/3holes.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#data/785_hand_2500v.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#data/785_hand_50kv.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#data/bumpy_sphere.txt - - - 0 3 2 Y 0.01 N Y N 60 1
#----------------------------------------------------------- Generated point sets -----------------------------------------------------------------------
#generate_sphere_d 3 - - 4 3 2 Y 0.05 N N N 3000 1
#generate_sphere_d 3 - - 30000 2 1 Y 0.005 N N N 3000 1
#generate_sphere_d 3 - - 30000 3 2 Y 0.005 N N N 3000 1
#generate_sphere_d 3 - - 30000 4 3 Y 0.05 N N N 3000 1
#generate_sphere_d 3 0 - 300 3 2 Y 0.005 N N N 60 1
#generate_sphere_d 3 4 - 3000 3 2 Y 0.005 N N N 60 1
#generate_sphere_d 3 7 - 3000 3 2 Y 0.005 N N N 60 1
#generate_plane - - - 30000 3 2 Y 0.005 N N N 3000 1
#generate_moment_curve 0 1 - 30000 6 1 Y 0.005 N N N 60 1
#generate_klein_bottle_4D 4 3 - 1000 4 2 Y 0.01 N N N 3 1
#generate_klein_bottle_variant_5D 4 3 - 30000 5 2 Y 0.05 N N N 60 1
#generate_klein_bottle_4D 8 5 - 5000 4 2 Y 0.2 N N N 60 1 #Takes forever
#----------------------------------------------------------- Performance testing ------------------------------------------------------------------------
# TC: 5.55 / 1st fix step : 0.2
#data/fertility.txt - - - 0 3 2 Y 0.1 N Y N 100 1

View File

@ -0,0 +1,871 @@
//#undef CGAL_LINKED_WITH_TBB // CJTODO TEMP
// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB
// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/)
#ifdef _DEBUG
# define TBB_USE_THREADING_TOOL
#endif
#include <cstddef>
//#define CGAL_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
//#define TC_PROTECT_POINT_SET_DELTA 0.003
//#define JUST_BENCHMARK_SPATIAL_SEARCH // CJTODO: test
//#define CHECK_IF_ALL_SIMPLICES_ARE_IN_THE_AMBIENT_DELAUNAY
//#define TC_INPUT_STRIDES 3 // only take one point every TC_INPUT_STRIDES points
//#define TC_NO_EXPORT
//#define CGAL_TC_ALVAREZ_SURFACE_WINDOW 0.95 // 1.9 - 0.95
//#define CGAL_TC_EXPORT_SPARSIFIED_POINT_SET
//#define CGAL_TC_EXPORT_ALL_COORDS_IN_OFF
const std::size_t ONLY_LOAD_THE_FIRST_N_POINTS = 500000; // 1e10
#include <CGAL/assertions_behaviour.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Tangential_complex.h>
#include <CGAL/Random.h>
#include <CGAL/Mesh_3/Profiling_tools.h>
#include "../../test/Tangential_complex/testing_utilities.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/trim_all.hpp>
#include <boost/range/adaptor/strided.hpp>
#include <cstdlib>
#include <ctime>
#include <fstream>
#include <math.h>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/task_scheduler_init.h>
#endif
#include "XML_exporter.h"
#define CGAL_TC_EXPORT_PERFORMANCE_DATA
#define CGAL_TC_SET_PERFORMANCE_DATA(value_name, value) \
XML_perf_data::set(value_name, value);
const char * const BENCHMARK_SCRIPT_FILENAME = "benchmark_script.txt";
typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_d Point;
typedef Kernel::Vector_d Vector;
typedef CGAL::Tangential_complex<
Kernel, CGAL::Dynamic_dimension_tag,
CGAL::Parallel_tag> TC;
#ifdef TC_PROTECT_POINT_SET_DELTA
# include <CGAL/Tangential_complex/protected_sets.h> // CJTODO TEST
#endif
#ifdef JUST_BENCHMARK_SPATIAL_SEARCH
std::ofstream spatial_search_csv_file("benchmark_spatial_search.csv");
#endif
using namespace CGAL::Tangential_complex_;
class XML_perf_data
{
public:
typedef Streaming_XML_exporter<std::string> XML_exporter;
XML_perf_data(const std::string &filename)
: m_xml(filename, "ContainerPerformance", "Perf",
construct_subelements_names())
{}
virtual ~XML_perf_data()
{
}
static XML_perf_data &get()
{
static XML_perf_data singleton(build_filename());
return singleton;
}
template <typename Value_type>
static void set(const std::string &name, Value_type value)
{
get().set_data(name, value);
}
static void commit()
{
get().commit_current_element();
}
protected:
static std::string build_filename()
{
std::stringstream sstr;
sstr << "perf_logs/Performance_log_" << time(0) << ".xml";
return sstr.str();
}
static std::vector<std::string> construct_subelements_names()
{
std::vector<std::string> subelements;
subelements.push_back("Input");
subelements.push_back("Intrinsic_dim");
subelements.push_back("Ambient_dim");
subelements.push_back("Sparsity");
subelements.push_back("Num_points_in_input");
subelements.push_back("Num_points");
subelements.push_back("Initial_num_inconsistent_local_tr");
subelements.push_back("Best_num_inconsistent_local_tr");
subelements.push_back("Final_num_inconsistent_local_tr");
subelements.push_back("Init_time");
subelements.push_back("Comput_time");
subelements.push_back("Perturb_successful");
subelements.push_back("Perturb_time");
subelements.push_back("Perturb_steps");
subelements.push_back("Add_higher_dim_simpl_time");
subelements.push_back("Result_pure_pseudomanifold");
subelements.push_back("Result_num_wrong_dim_simplices");
subelements.push_back("Result_num_wrong_number_of_cofaces");
subelements.push_back("Result_num_unconnected_stars");
subelements.push_back("Info");
return subelements;
}
void set_data(const std::string &name, const std::string &value)
{
m_current_element[name] = value;
}
template <typename Value_type>
void set_data(const std::string &name, Value_type value)
{
std::stringstream sstr;
sstr << value;
set_data(name, sstr.str());
}
void commit_current_element()
{
m_xml.add_element(m_current_element);
m_current_element.clear();
}
XML_exporter m_xml;
XML_exporter::Element_with_map m_current_element;
};
class Test_dim
{
public:
Test_dim(
int min_allowed_dim = 0,
int max_allowed_dim = std::numeric_limits<int>::max())
: m_min_allowed_dim(min_allowed_dim), m_max_allowed_dim(max_allowed_dim)
{}
template <typename Simplex>
bool operator()(Simplex const& s)
{
return s.size() - 1 >= m_min_allowed_dim
&& s.size() - 1 <= m_max_allowed_dim;
}
private:
int m_min_allowed_dim;
int m_max_allowed_dim;
};
// color_inconsistencies: only works if p_complex = NULL
template <typename TC>
bool export_to_off(
TC const& tc,
std::string const& input_name_stripped,
std::string const& suffix,
bool color_inconsistencies = false,
typename TC::Simplicial_complex const* p_complex = NULL,
std::set<std::set<std::size_t> > const *p_simpl_to_color_in_red = NULL,
std::set<std::set<std::size_t> > const *p_simpl_to_color_in_green = NULL,
std::set<std::set<std::size_t> > const *p_simpl_to_color_in_blue = NULL)
{
#ifdef TC_NO_EXPORT
return true;
#endif
#if 0
Kernel k;
FT center_pt[] = { -0.5, -CGAL::sqrt(3.) / 2, -0.5, CGAL::sqrt(3.) / 2 };
FT proj_pt[] = { 0., 0., 0., 0.2 };
S3_to_R3_stereographic_projection<Kernel>
proj_functor(0.2,
Point(4, &center_pt[0], &center_pt[4]),
k);
#else
CGAL::Identity<Point> proj_functor;
//Kernel k;
//std::array<int, 3> sel = { 1, 3, 5 };
//Orthogonal_projection<Kernel> proj_functor(sel, k);
#endif
if (tc.intrinsic_dimension() <= 3)
{
std::stringstream output_filename;
output_filename << "output/" << input_name_stripped << "_"
<< tc.intrinsic_dimension() << "_in_R"
<< tc.ambient_dimension() << "_"
<< tc.number_of_vertices() << "v"
<< suffix << ".off";
std::ofstream off_stream(output_filename.str().c_str());
if (p_complex)
{
#ifndef TC_NO_EXPORT
tc.export_to_off(
*p_complex, off_stream,
p_simpl_to_color_in_red,
p_simpl_to_color_in_green,
p_simpl_to_color_in_blue,
proj_functor);
#endif
}
else
{
/*#ifdef CGAL_ALPHA_TC
TC::Simplicial_complex complex;
tc.export_TC(complex, false);
tc.export_to_off(
complex, off_stream,
p_simpl_to_color_in_red,
p_simpl_to_color_in_green,
p_simpl_to_color_in_blue);
#else*/
tc.export_to_off(
off_stream, color_inconsistencies,
p_simpl_to_color_in_red,
p_simpl_to_color_in_green,
p_simpl_to_color_in_blue,
NULL,
proj_functor);
//#endif
}
return true;
}
return false;
}
void make_tc(std::vector<Point> &points,
TC::TS_container const& tangent_spaces, // can be empty
int intrinsic_dim,
bool sparsify = true,
double sparsity = 0.01,
bool perturb = true,
bool add_high_dim_simpl = false,
bool collapse = false,
double time_limit_for_perturb = 0.,
const char *input_name = "tc")
{
Kernel k;
if (sparsify && !tangent_spaces.empty())
{
std::cerr << "Error: cannot sparsify point set with pre-computed normals.\n";
return;
}
// CJTODO TEMP TEST
//TC::Simplicial_complex compl;
//{std::size_t ss[] = {0, 1, 2}; compl.add_simplex(std::set<std::size_t>(ss, ss + 3)); }
//{std::size_t ss[] = {0, 2, 3}; compl.add_simplex(std::set<std::size_t>(ss, ss + 3)); }
//{std::size_t ss[] = {0, 3, 4}; compl.add_simplex(std::set<std::size_t>(ss, ss + 3)); }
//{std::size_t ss[] = {0, 4, 1}; compl.add_simplex(std::set<std::size_t>(ss, ss + 3)); }
//{std::size_t ss[] = {0, 5, 6}; compl.add_simplex(std::set<std::size_t>(ss, ss + 3)); }
//compl.is_pure_pseudomanifold(2, 7, false, 10);
//TC::Simplicial_complex compl;
//{std::size_t ss[] = {0, 1, 2, 5}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 2, 3, 5}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 3, 4, 5}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 4, 1, 5}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 1, 2, 6}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 2, 3, 6}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 3, 4, 6}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 4, 1, 6}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//{std::size_t ss[] = {0, 4, 7, 8}; compl.add_simplex(std::set<std::size_t>(ss, ss + 4)); }
//compl.is_pure_pseudomanifold(3, 9, false, 10);
// /CJTODO TEMP TEST
#ifdef JUST_BENCHMARK_SPATIAL_SEARCH
benchmark_spatial_search(points, k, spatial_search_csv_file);
return;
#endif
//===========================================================================
// Init
//===========================================================================
Wall_clock_timer t;
// Get input_name_stripped
std::string input_name_stripped(input_name);
size_t slash_index = input_name_stripped.find_last_of('/');
if (slash_index == std::string::npos)
slash_index = input_name_stripped.find_last_of('\\');
if (slash_index == std::string::npos)
slash_index = 0;
else
++slash_index;
input_name_stripped = input_name_stripped.substr(
slash_index, input_name_stripped.find_last_of('.') - slash_index);
int ambient_dim = k.point_dimension_d_object()(*points.begin());
CGAL_TC_SET_PERFORMANCE_DATA("Num_points_in_input", points.size());
#ifdef CGAL_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
std::vector<Point> points_not_sparse = points;
#endif
//===========================================================================
// Sparsify point set if requested
//===========================================================================
if (sparsify)
{
std::size_t num_points_before = points.size();
points = sparsify_point_set(k, points, sparsity*sparsity);
std::cerr << "Number of points before/after sparsification: "
<< num_points_before << " / " << points.size() << "\n";
#ifdef CGAL_TC_EXPORT_SPARSIFIED_POINT_SET
std::ofstream ps_stream("output/sparsified_point_set.txt");
export_point_set(k, points, ps_stream);
#endif
}
#ifdef TC_PROTECT_POINT_SET_DELTA
// CJTODO TEST
# ifdef CGAL_TC_PROFILING
Wall_clock_timer t_protection;
# endif
std::vector<Point> points2;
std::vector<int> dummy;
std::vector<std::vector<int> > dummy2;
landmark_choice_protected_delaunay(
points, points.size(), points2, dummy, TC_PROTECT_POINT_SET_DELTA, dummy2, false, true);
points = points2;
# ifdef CGAL_TC_PROFILING
std::cerr << "Point set protected in " << t_protection.elapsed()
<< " seconds.\n";
# endif
std::cerr << "Number of points after PROTECTION: " << points.size() << "\n";
#endif
CGAL_TC_SET_PERFORMANCE_DATA("Sparsity", sparsity);
CGAL_TC_SET_PERFORMANCE_DATA("Num_points", points.size());
//===========================================================================
// Compute Tangential Complex
//===========================================================================
#ifdef CGAL_TC_USE_ANOTHER_POINT_SET_FOR_TANGENT_SPACE_ESTIM
TC tc(points.begin(), points.end(), sparsity, intrinsic_dim,
points_not_sparse.begin(), points_not_sparse.end(), k);
#else
TC tc(points.begin(), points.end(), sparsity, intrinsic_dim, k);
#endif
if (!tangent_spaces.empty())
{
tc.set_tangent_planes(tangent_spaces);
}
double init_time = t.elapsed(); t.reset();
tc.compute_tangential_complex();
double computation_time = t.elapsed(); t.reset();
#ifdef CHECK_IF_ALL_SIMPLICES_ARE_IN_THE_AMBIENT_DELAUNAY
if (ambient_dim <= 4)
tc.check_if_all_simplices_are_in_the_ambient_delaunay();
#endif
//tc.check_correlation_between_inconsistencies_and_fatness();
//===========================================================================
// Export to OFF
//===========================================================================
// Create complex
int max_dim = -1;
TC::Simplicial_complex complex;
std::set<std::set<std::size_t> > inconsistent_simplices;
max_dim = tc.export_TC(complex, false, 2, &inconsistent_simplices);
t.reset();
double export_before_time =
(export_to_off(tc, input_name_stripped, "_INITIAL_TC", true,
&complex, &inconsistent_simplices) ? t.elapsed() : -1);
t.reset();
unsigned int num_perturb_steps = 0;
double perturb_time = -1;
double export_after_perturb_time = -1.;
CGAL::Fix_inconsistencies_status perturb_ret = CGAL::FIX_NOT_PERFORMED;
if (perturb)
{
//=========================================================================
// Try to fix inconsistencies by perturbing points
//=========================================================================
t.reset();
std::size_t initial_num_inconsistent_local_tr;
std::size_t best_num_inconsistent_local_tr;
std::size_t final_num_inconsistent_local_tr;
perturb_ret = tc.fix_inconsistencies_using_perturbation(
num_perturb_steps, initial_num_inconsistent_local_tr,
best_num_inconsistent_local_tr, final_num_inconsistent_local_tr,
time_limit_for_perturb);
perturb_time = t.elapsed(); t.reset();
CGAL_TC_SET_PERFORMANCE_DATA("Initial_num_inconsistent_local_tr",
initial_num_inconsistent_local_tr);
CGAL_TC_SET_PERFORMANCE_DATA("Best_num_inconsistent_local_tr",
best_num_inconsistent_local_tr);
CGAL_TC_SET_PERFORMANCE_DATA("Final_num_inconsistent_local_tr",
final_num_inconsistent_local_tr);
//tc.check_correlation_between_inconsistencies_and_fatness();
// DEBUGGING: confirm that all stars were actually refreshed
//std::cerr << yellow << "FINAL CHECK...\n" << white;
//std::size_t num_inc = tc.number_of_inconsistent_simplices(true).second;
//tc.refresh_tangential_complex();
//if (CGAL::cpp11::get<1>(tc.number_of_inconsistent_simplices(true)) != num_inc)
// std::cerr << red << "FINAL CHECK: FAILED.\n" << white;
//else
// std::cerr << green << "FINAL CHECK: PASSED.\n" << white;
//=========================================================================
// Export to OFF
//=========================================================================
// Re-build the complex
std::set<std::set<std::size_t> > inconsistent_simplices;
max_dim = tc.export_TC(complex, false, 2, &inconsistent_simplices);
t.reset();
bool exported = export_to_off(
tc, input_name_stripped, "_AFTER_FIX", true, &complex,
&inconsistent_simplices);
double export_after_perturb_time = (exported ? t.elapsed() : -1);
t.reset();
//std::string fn = "output/inc_stars/";
//fn += input_name_stripped;
//tc.export_inconsistent_stars_to_OFF_files(fn);
}
else
{
CGAL_TC_SET_PERFORMANCE_DATA("Initial_num_inconsistent_local_tr", "N/A");
CGAL_TC_SET_PERFORMANCE_DATA("Best_num_inconsistent_local_tr", "N/A");
CGAL_TC_SET_PERFORMANCE_DATA("Final_num_inconsistent_local_tr", "N/A");
}
// CJTODO TEST
//tc.check_and_solve_inconsistencies_by_filtering_simplices_out();
double fix2_time = -1;
double export_after_fix2_time = -1.;
if (add_high_dim_simpl)
{
//=========================================================================
// Try to fix inconsistencies by adding higher-dimension simplices
//=========================================================================
t.reset();
// Try to solve the remaining inconstencies
#ifdef CGAL_ALPHA_TC
tc.solve_inconsistencies_using_alpha_TC();
#else
tc.check_and_solve_inconsistencies_by_adding_higher_dim_simplices();
#endif
fix2_time = t.elapsed(); t.reset();
/*std::set<std::set<std::size_t> > not_delaunay_simplices;
if (ambient_dim <= 4)
{
tc.check_if_all_simplices_are_in_the_ambient_delaunay(
&complex, true, &not_delaunay_simplices);
}*/
//=========================================================================
// Export to OFF
//=========================================================================
// Re-build the complex
std::set<std::set<std::size_t> > inconsistent_simplices;
max_dim = tc.export_TC(complex, false, 2, &inconsistent_simplices);
t.reset();
bool exported = export_to_off(
tc, input_name_stripped, "_AFTER_FIX2", false, &complex,
&inconsistent_simplices);
double export_after_fix2_time = (exported ? t.elapsed() : -1);
t.reset();
}
else
{
std::set<std::set<std::size_t> > inconsistent_simplices;
max_dim = tc.export_TC(complex, false, 2, &inconsistent_simplices);
}
complex.display_stats();
if (intrinsic_dim == 2)
complex.euler_characteristic(true);
// CJTODO TEMP: Export to OFF with higher-dim simplices colored
/*std::set<std::set<std::size_t> > higher_dim_simplices;
complex.get_simplices_matching_test(
Test_dim(intrinsic_dim + 1),
std::inserter(higher_dim_simplices, higher_dim_simplices.begin()));
export_to_off(
tc, input_name_stripped, "_BEFORE_COLLAPSE", false, &complex,
&inconsistent_simplices, &higher_dim_simplices);*/
//===========================================================================
// Collapse
//===========================================================================
if (collapse)
{
complex.collapse(max_dim);
complex.display_stats();
}
//===========================================================================
// Is the result a pure pseudomanifold?
//===========================================================================
std::size_t num_wrong_dim_simplices,
num_wrong_number_of_cofaces,
num_unconnected_stars;
std::set<std::set<std::size_t> > wrong_dim_simplices;
std::set<std::set<std::size_t> > wrong_number_of_cofaces_simplices;
std::set<std::set<std::size_t> > unconnected_stars_simplices;
bool is_pure_pseudomanifold = complex.is_pure_pseudomanifold(
intrinsic_dim, tc.number_of_vertices(),
#ifdef CGAL_TC_ALVAREZ_SURFACE_WINDOW
true, // allow borders
#else
false, // do NOT allow borders
#endif
false, 1,
&num_wrong_dim_simplices, &num_wrong_number_of_cofaces,
&num_unconnected_stars,
&wrong_dim_simplices, &wrong_number_of_cofaces_simplices,
&unconnected_stars_simplices);
//===========================================================================
// Export to OFF
//===========================================================================
double export_after_collapse_time = -1.;
if (collapse)
{
t.reset();
bool exported = export_to_off(
tc, input_name_stripped, "_AFTER_COLLAPSE", false, &complex,
&wrong_dim_simplices, &wrong_number_of_cofaces_simplices,
&unconnected_stars_simplices);
std::cerr
<< " OFF colors:\n"
<< " * Red: wrong dim simplices\n"
<< " * Green: wrong number of cofaces simplices\n"
<< " * Blue: not-connected stars\n";
double export_after_collapse_time = (exported ? t.elapsed() : -1.);
t.reset();
}
//===========================================================================
// Display info
//===========================================================================
std::cerr
<< "\n================================================\n"
<< "Number of vertices: " << tc.number_of_vertices() << "\n"
<< "Computation times (seconds): \n"
<< " * Tangential complex: " << init_time + computation_time << "\n"
<< " - Init + kd-tree = " << init_time << "\n"
<< " - TC computation = " << computation_time << "\n"
<< " * Export to OFF (before perturb): " << export_before_time << "\n"
<< " * Fix inconsistencies 1: " << perturb_time
<< " (" << num_perturb_steps << " steps) ==> "
<< (perturb_ret == CGAL::TC_FIXED ? "FIXED" : "NOT fixed") << "\n"
<< " * Fix inconsistencies 2: " << fix2_time << "\n"
<< " * Export to OFF (after perturb): " << export_after_perturb_time << "\n"
<< " * Export to OFF (after fix2): "<< export_after_fix2_time << "\n"
<< " * Export to OFF (after collapse): "
<< export_after_collapse_time << "\n"
<< "================================================\n";
//===========================================================================
// Export info
//===========================================================================
CGAL_TC_SET_PERFORMANCE_DATA("Init_time", init_time);
CGAL_TC_SET_PERFORMANCE_DATA("Comput_time", computation_time);
CGAL_TC_SET_PERFORMANCE_DATA("Perturb_successful",
(perturb_ret == CGAL::TC_FIXED ? "Y" : "N"));
CGAL_TC_SET_PERFORMANCE_DATA("Perturb_time", perturb_time);
CGAL_TC_SET_PERFORMANCE_DATA("Perturb_steps", num_perturb_steps);
CGAL_TC_SET_PERFORMANCE_DATA("Add_higher_dim_simpl_time", fix2_time);
CGAL_TC_SET_PERFORMANCE_DATA("Result_pure_pseudomanifold",
(is_pure_pseudomanifold ? "Y" : "N"));
CGAL_TC_SET_PERFORMANCE_DATA("Result_num_wrong_dim_simplices",
num_wrong_dim_simplices);
CGAL_TC_SET_PERFORMANCE_DATA("Result_num_wrong_number_of_cofaces",
num_wrong_number_of_cofaces);
CGAL_TC_SET_PERFORMANCE_DATA("Result_num_unconnected_stars",
num_unconnected_stars);
CGAL_TC_SET_PERFORMANCE_DATA("Info", "");
}
int main()
{
CGAL::set_error_behaviour(CGAL::ABORT);
#ifdef CGAL_LINKED_WITH_TBB
# ifdef _DEBUG
int num_threads = 1;
# else
int num_threads = 8;
# endif
#endif
unsigned int seed = static_cast<unsigned int>(time(NULL));
CGAL::default_random = CGAL::Random(seed);
std::cerr << "Random seed = " << seed << "\n";
std::ifstream script_file;
script_file.open(BENCHMARK_SCRIPT_FILENAME);
// Script?
// Script file format: each line gives
// - Filename (point set) or "generate_XXX" (point set generation)
// - Ambient dim
// - Intrinsic dim
// - Number of iterations with these parameters
if (script_file.is_open())
{
int i = 1;
#ifdef CGAL_LINKED_WITH_TBB
# ifdef BENCHMARK_WITH_1_TO_MAX_THREADS
for(num_threads = 1 ;
num_threads <= tbb::task_scheduler_init::default_num_threads() ;
++num_threads)
# endif
#endif
/*for (Concurrent_mesher_config::get().num_work_items_per_batch = 5 ;
Concurrent_mesher_config::get().num_work_items_per_batch < 100 ;
Concurrent_mesher_config::get().num_work_items_per_batch += 5)*/
{
#ifdef CGAL_LINKED_WITH_TBB
tbb::task_scheduler_init init(
num_threads > 0 ? num_threads : tbb::task_scheduler_init::automatic);
#endif
std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' found.\n";
script_file.seekg(0);
while (script_file.good())
{
std::string line;
std::getline(script_file, line);
if (line.size() > 1 && line[0] != '#')
{
boost::replace_all(line, "\t", " ");
boost::trim_all(line);
std::cerr << "\n\n";
std::cerr << "*****************************************\n";
std::cerr << "******* " << line << "\n";
std::cerr << "*****************************************\n";
std::stringstream sstr(line);
std::string input;
std::string param1;
std::string param2;
std::string param3;
std::size_t num_points;
int ambient_dim;
int intrinsic_dim;
char sparsify;
double sparsity;
char perturb, add_high_dim_simpl, collapse;
double time_limit_for_perturb;
int num_iteration;
sstr >> input;
sstr >> param1;
sstr >> param2;
sstr >> param3;
sstr >> num_points;
sstr >> ambient_dim;
sstr >> intrinsic_dim;
sstr >> sparsify;
sstr >> sparsity;
sstr >> perturb;
sstr >> add_high_dim_simpl;
sstr >> collapse;
sstr >> time_limit_for_perturb;
sstr >> num_iteration;
for (int j = 0 ; j < num_iteration ; ++j)
{
std::string input_stripped = input;
size_t slash_index = input_stripped.find_last_of('/');
if (slash_index == std::string::npos)
slash_index = input_stripped.find_last_of('\\');
if (slash_index == std::string::npos)
slash_index = 0;
else
++slash_index;
input_stripped = input_stripped.substr(
slash_index, input_stripped.find_last_of('.') - slash_index);
CGAL_TC_SET_PERFORMANCE_DATA("Input", input_stripped);
CGAL_TC_SET_PERFORMANCE_DATA("Ambient_dim", ambient_dim);
CGAL_TC_SET_PERFORMANCE_DATA("Intrinsic_dim", intrinsic_dim);
#ifdef CGAL_LINKED_WITH_TBB
CGAL_TC_SET_PERFORMANCE_DATA(
"Num_threads",
(num_threads == -1 ? tbb::task_scheduler_init::default_num_threads() : num_threads));
#else
CGAL_TC_SET_PERFORMANCE_DATA("Num_threads", "N/A");
#endif
std::cerr << "\nTC #" << i << "...\n";
#ifdef CGAL_TC_PROFILING
Wall_clock_timer t_gen;
#endif
std::vector<Point> points;
TC::TS_container tangent_spaces;
if (input == "generate_moment_curve")
{
points = generate_points_on_moment_curve<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_plane")
{
points = generate_points_on_plane<Kernel>(
num_points, intrinsic_dim, ambient_dim);
}
else if (input == "generate_sphere_d")
{
points = generate_points_on_sphere_d<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()), // radius
std::atof(param2.c_str())); // radius_noise_percentage
}
else if (input == "generate_two_spheres_d")
{
points = generate_points_on_two_spheres_d<Kernel>(
num_points, ambient_dim,
std::atof(param1.c_str()),
std::atof(param2.c_str()),
std::atof(param3.c_str()));
}
else if (input == "generate_3sphere_and_circle_d")
{
CGAL_assertion(intrinsic_dim == 3);
CGAL_assertion(ambient_dim == 5);
points = generate_points_on_3sphere_and_circle<Kernel>(
num_points,
std::atof(param1.c_str()));
}
else if (input == "generate_torus_3D")
{
points = generate_points_on_torus_3D<Kernel>(
num_points,
std::atof(param1.c_str()),
std::atof(param2.c_str()),
param3 == "Y");
}
else if (input == "generate_torus_d")
{
points = generate_points_on_torus_d<Kernel>(
num_points,
intrinsic_dim,
param1 == "Y", // uniform
std::atof(param2.c_str())); // radius_noise_percentage
}
else if (input == "generate_klein_bottle_3D")
{
points = generate_points_on_klein_bottle_3D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_klein_bottle_4D")
{
points = generate_points_on_klein_bottle_4D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else if (input == "generate_klein_bottle_variant_5D")
{
points = generate_points_on_klein_bottle_variant_5D<Kernel>(
num_points,
std::atof(param1.c_str()), std::atof(param2.c_str()));
}
else
{
load_points_from_file<Kernel, typename TC::Tangent_space_basis>(
input, std::back_inserter(points),
std::back_inserter(tangent_spaces),
ONLY_LOAD_THE_FIRST_N_POINTS);
}
#ifdef CGAL_TC_PROFILING
std::cerr << "Point set generated/loaded in " << t_gen.elapsed()
<< " seconds.\n";
#endif
if (!points.empty())
{
#if defined(TC_INPUT_STRIDES) && TC_INPUT_STRIDES > 1
auto p = points | boost::adaptors::strided(TC_INPUT_STRIDES); // CJTODO C++11 (auto)
std::vector<Point> points(p.begin(), p.end());
std::cerr << "****************************************\n"
<< "WARNING: taking 1 point every " << TC_INPUT_STRIDES
<< " points.\n"
<< "****************************************\n";
#endif
make_tc(points, tangent_spaces, intrinsic_dim, sparsify=='Y',
sparsity, perturb=='Y', add_high_dim_simpl=='Y',
collapse=='Y', time_limit_for_perturb, input.c_str());
std::cerr << "TC #" << i++ << " done.\n";
std::cerr << "\n---------------------------------\n";
}
else
{
std::cerr << "TC #" << i++ << ": no points loaded.\n";
}
XML_perf_data::commit();
}
}
}
script_file.seekg(0);
script_file.clear();
}
script_file.close();
}
// Or not script?
else
{
std::cerr << "Script file '" << BENCHMARK_SCRIPT_FILENAME << "' NOT found.\n";
}
system("pause");
return 0;
}

View File

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,400 @@
// Copyright (c) 2014 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
#ifndef POINT_CLOUD_H
#define POINT_CLOUD_H
#include <CGAL/Orthogonal_k_neighbor_search.h>
#include <CGAL/Orthogonal_incremental_neighbor_search.h>
#include <CGAL/Search_traits.h>
#include <CGAL/Search_traits_adapter.h>
#include <boost/iterator/counting_iterator.hpp>
#include <cstddef>
#include <vector>
#ifdef CGAL_TC_ANN_IS_AVAILABLE
# include <ANN/ANN.h>
#endif
#ifdef CGAL_TC_NANOFLANN_IS_AVAILABLE
# include "nanoflann.hpp"
#endif
namespace CGAL {
namespace Tangential_complex_ {
template <typename K, typename Point_container_>
class Point_cloud_data_structure
{
public:
typedef typename Point_container_::value_type Point;
typedef K Kernel;
typedef typename Kernel::FT FT;
typedef CGAL::Search_traits<
FT, Point,
typename Kernel::Cartesian_const_iterator_d,
typename Kernel::Construct_cartesian_const_iterator_d> Traits_base;
// using a pointer as a special property map type
typedef CGAL::Search_traits_adapter<
std::ptrdiff_t, Point*, Traits_base> STraits;
typedef CGAL::Orthogonal_k_neighbor_search<STraits> K_neighbor_search;
typedef typename K_neighbor_search::Tree Tree;
typedef typename K_neighbor_search::Distance Distance;
typedef typename K_neighbor_search::iterator KNS_iterator;
typedef K_neighbor_search KNS_range;
typedef CGAL::Orthogonal_incremental_neighbor_search<
STraits, Distance, CGAL::Sliding_midpoint<STraits>, Tree>
Incremental_neighbor_search;
typedef typename Incremental_neighbor_search::iterator INS_iterator;
typedef Incremental_neighbor_search INS_range;
/// Constructor
Point_cloud_data_structure(Point_container_ const& points)
: m_points(points),
m_tree(boost::counting_iterator<std::ptrdiff_t>(0),
boost::counting_iterator<std::ptrdiff_t>(points.size()),
typename Tree::Splitter(),
STraits((Point*)&(points[0])) )
{
// Build the tree now (we don't want to wait for the first query)
m_tree.build();
}
/// Constructor
template <typename Point_indices_range>
Point_cloud_data_structure(
Point_container_ const& points,
Point_indices_range const& only_these_points)
: m_points(points),
m_tree(
only_these_points.begin(), only_these_points.end(),
typename Tree::Splitter(),
STraits((Point*)&(points[0])))
{
// Build the tree now (we don't want to wait for the first query)
m_tree.build();
}
/// Constructor
Point_cloud_data_structure(
Point_container_ const& points,
std::size_t begin_idx, std::size_t past_the_end_idx)
: m_points(points),
m_tree(
boost::counting_iterator<std::ptrdiff_t>(begin_idx),
boost::counting_iterator<std::ptrdiff_t>(past_the_end_idx),
typename Tree::Splitter(),
STraits((Point*)&(points[0])) )
{
// Build the tree now (we don't want to wait for the first query)
m_tree.build();
}
/*Point_container_ &points()
{
return m_points;
}
const Point_container_ &points() const
{
return m_points;
}*/
// Be careful, this function invalidates the tree,
// which will be recomputed at the next query
void insert(std::ptrdiff_t point_idx)
{
m_tree.insert(point_idx);
}
KNS_range query_ANN(const
Point &sp,
unsigned int k,
bool sorted = true) const
{
// Initialize the search structure, and search all N points
// Note that we need to pass the Distance explicitly since it needs to
// know the property map
K_neighbor_search search(
m_tree,
sp,
k,
FT(0),
true,
Distance_adapter<std::ptrdiff_t,Point*,Euclidean_distance<Traits_base> >(
(Point*)&(m_points[0])),
sorted);
return search;
}
INS_range query_incremental_ANN(const Point &sp) const
{
// Initialize the search structure, and search all N points
// Note that we need to pass the Distance explicitly since it needs to
// know the property map
Incremental_neighbor_search search(
m_tree,
sp,
FT(0),
true,
Distance_adapter<std::ptrdiff_t,Point*,Euclidean_distance<Traits_base> >(
(Point*)&(m_points[0])) );
return search;
}
protected:
Point_container_ const& m_points;
Tree m_tree;
};
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
#ifdef CGAL_TC_NANOFLANN_IS_AVAILABLE
// "dataset to kd-tree" adaptor class
template <typename K, typename Point_container_>
class Point_cloud_adaptator__nanoflann
{
public:
typedef typename Point_container_::value_type Point;
typedef K Kernel;
typedef typename Kernel::FT FT;
/// The constructor that sets the data set source
Point_cloud_adaptator__nanoflann(Point_container_ const& points, Kernel const& k)
: m_points(points), m_k(k)
{}
/// CRTP helper method
inline Point_container_ const& points() const
{
return m_points;
}
inline Point_container_& points()
{
return m_points;
}
// Must return the number of data points
inline size_t kdtree_get_point_count() const
{
return m_points.size();
}
// Returns the distance between the vector "p1[0:size-1]"
// and the data point with index "idx_p2" stored in the class:
inline FT kdtree_distance(
const FT *p1, const size_t idx_p2, size_t size) const
{
Point sp(p1, p1 + size);
return m_k.squared_distance_d_object()(sp, points()[idx_p2]);
}
// Returns the dim'th component of the idx'th point in the class:
// Since this is inlined and the "dim" argument is typically an
// immediate value, the "if/else's" are actually solved at compile time.
inline FT kdtree_get_pt(const size_t idx, int dim) const
{
return m_k.compute_coordinate_d_object()(points()[idx], dim);
}
// Optional bounding-box computation: return false to default to a standard
// bbox computation loop.
// Return true if the BBOX was already computed by the class and returned
// in "bb" so it can be avoided to redo it again.
// Look at bb.size() to find out the expected dimensionality
// (e.g. 2 or 3 for point clouds)
template <class Bbox>
bool kdtree_get_bbox(Bbox &bb) const
{
return false;
}
Kernel const& kernel() const
{
return m_k;
}
protected:
Point_container_ const& m_points; //!< A const ref to the data set origin
Kernel const& m_k; //!< A const ref to the kernel
};
template <typename K, typename Point_container_>
class Point_cloud_data_structure__nanoflann
{
public:
typedef typename Point_container_::value_type Point;
typedef typename K Kernel;
typedef typename Kernel::FT FT;
/// Constructor
/// "points" must not be empty
Point_cloud_data_structure__nanoflann(
Point_container_ const& points, Kernel const& k)
: m_adaptor(points, k),
m_kd_tree(k.point_dimension_d_object()(*points.begin()),
m_adaptor,
nanoflann::KDTreeSingleIndexAdaptorParams(10 /* max leaf */) )
{
m_kd_tree.buildIndex();
}
/*Point_container_ &points()
{
return m_adaptor.points();
}
const Point_container_ &points() const
{
return m_adaptor.points();
}*/
void query_ANN(const Point &sp,
std::size_t k,
size_t *neighbor_indices,
FT *squared_distance) const
{
std::vector<FT> sp_vec(
m_adaptor.kernel().construct_cartesian_const_iterator_d_object()(sp),
m_adaptor.kernel().construct_cartesian_const_iterator_d_object()(sp, 0));
nanoflann::KNNResultSet<FT> result_set(k);
result_set.init(neighbor_indices, squared_distance);
m_kd_tree.findNeighbors(result_set,
&sp_vec[0],
nanoflann::SearchParams());
/*std::cout << "knnSearch(nn="<< num_results <<"): \n";
for (int i = 0 ; i < num_results ; ++i)
{
std::cout << " * neighbor_indices = " << neighbor_indices [i]
<< " (out_dist_sqr = " << squared_distance[i] << ")"
<< std::endl;
}*/
}
void query_ball(const Point &sp,
const FT radius,
std::vector<std::pair<std::size_t, FT> > &neighbors,
bool sort_output = true)
{
std::vector<FT> sp_vec(
m_adaptor.kernel().construct_cartesian_const_iterator_d_object()(sp),
m_adaptor.kernel().construct_cartesian_const_iterator_d_object()(sp, 0));
m_kd_tree.radiusSearch(&sp_vec[0],
radius,
neighbors,
nanoflann::SearchParams(32, 0.f, sort_output));
/*std::cout << "radiusSearch(num="<< neighbors.size() <<"): \n";
for (const auto idx_and_dist : neighbors)
{
std::cout << " * neighbor_indices = " << idx_and_dist.first
<< " (out_dist_sqr = " << idx_and_dist.second << ")"
<< std::endl;
}*/
}
protected:
typedef Point_cloud_adaptator__nanoflann<Kernel, Point_container_> Adaptor;
typedef nanoflann::KDTreeSingleIndexAdaptor<
nanoflann::L2_Simple_Adaptor<FT, Adaptor> ,
Adaptor,
-1 // dim
> Kd_tree;
Adaptor m_adaptor;
Kd_tree m_kd_tree;
};
#endif //CGAL_TC_NANOFLANN_IS_AVAILABLE
//*****************************************************************************
//*****************************************************************************
//*****************************************************************************
#ifdef CGAL_TC_ANN_IS_AVAILABLE
template <typename K, typename Point_container_>
class Point_cloud_data_structure__ANN
{
public:
typedef typename Point_container_::value_type Point;
typedef K Kernel;
typedef typename Kernel::FT FT;
/// Constructor
Point_cloud_data_structure__ANN(
Point_container_ const& points, Kernel const& k)
: m_dim(k.point_dimension_d_object()(*points.begin())),
m_k(k),
m_points(annAllocPts(points.size(), m_dim)),
m_tree(m_points, points.size(), m_dim)
{
for (int i = 0 ; i < points.size() ; ++i)
{
for (int j = 0 ; j < m_dim ; ++j)
m_points[i][j] = m_k.compute_coordinate_d_object()(points[i], j);
}
}
void query_ANN(
Point const& p,
unsigned int k,
ANNidxArray neighbors_indices,
ANNdistArray neighbors_sq_distances)
{
// Create an ANN query point
ANNpoint query_pt = annAllocPt(m_dim);
for (int j = 0 ; j < m_dim ; ++j)
query_pt[j] = m_k.compute_coordinate_d_object()(p, j);
m_tree.annkSearch( // search
query_pt, // query point
k, // number of near neighbors
neighbors_indices, // nearest neighbors (returned)
neighbors_sq_distances, // distance (returned)
0); // error bound
}
protected:
int m_dim;
Kernel const& m_k;
ANNpointArray m_points;
ANNkd_tree m_tree;
};
#endif // CGAL_TC_ANN_IS_AVAILABLE
} // namespace Tangential_complex_
} //namespace CGAL
#endif // POINT_CLOUD_H

View File

@ -0,0 +1,288 @@
// Copyright (c) 2016 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
#ifndef CGAL_TC_WRITE_RIB_FILE_H
#define CGAL_TC_WRITE_RIB_FILE_H
#include "utilities.h"
#include <CGAL/basic.h>
#include <tuple>
#include <string>
namespace CGAL {
namespace Tangential_complex_ {
template <typename PointRandomAccessRange, typename SimplexRange>
class RIB_exporter
{
typedef typename PointRandomAccessRange::value_type Point;
public:
typedef std::tuple<double, double, double, double> Color; // RGBA
// Constructor
RIB_exporter(
PointRandomAccessRange const& points,
SimplexRange const& simplices,
std::ofstream &out,
std::string const& rendered_image_filename = "export.tif",
bool is_preview = false, // low-quality
int image_width = 1920,
int image_height = 1080,
Color const& triangle_color = std::make_tuple(0., 1., 1., 1.),
bool ambient_light = true,
double ambient_intensity = 0.20,
bool shadow = true,
double shadow_intensity = 0.85)
: m_points(points),
m_simplices(simplices),
m_out(out),
m_rendered_image_filename(rendered_image_filename),
m_is_preview(is_preview),
m_image_width(image_width),
m_image_height(image_height),
m_current_color(0., 0., 0., 0.),
m_current_alpha(1),
m_triangle_color(triangle_color),
m_ambient_light(ambient_light),
m_ambient_intensity(ambient_intensity),
m_shadow(shadow),
m_shadow_intensity(shadow_intensity)
{
m_out.precision(8);
}
void write_file()
{
write_header();
write_lights();
write_triangles();
m_out << "WorldEnd\n";
}
private:
void write_header()
{
m_out << "Option \"searchpath\" \"shader\" "
"\".:./shaders:%PIXIE_SHADERS%:%PIXIEHOME%/shaders\"\n";
if (m_is_preview)
{
m_out << "Attribute \"visibility\" \"specular\" 1\n"
<< "Attribute \"visibility\" \"transmission\" 1\n\n";
}
m_out << "Display \"" << m_rendered_image_filename << "\" \"file\" \"rgb\"\n";
if (!m_is_preview)
{
m_out << "Format " << m_image_width << " " << m_image_height << " 1\n";
}
else
{
double ratio = double(m_image_height) / double(m_image_width);
int width = (ratio < 1.) ? 300 : int(300. / ratio);
int height = (ratio < 1.) ? int(ratio * 300.) : 300;
m_out << "Format " << width << " " << height << " 1\n";
}
if (m_image_width > m_image_height)
{
double ratio = double(m_image_height) / double(m_image_width);
m_out << "ScreenWindow -1 1 " << -ratio << " " << ratio << "\n";
}
else if (m_image_height > m_image_width)
{
double ratio = double(m_image_width) / double(m_image_height);
m_out << "ScreenWindow " << -ratio << " " << ratio << " -1 1\n";
}
m_out << "Projection \"perspective\" \"fov\" 45\n"
<< "Translate 0 0 15\n"
<< "PixelSamples 4 4\n"
<< "PixelFilter \"catmull-rom\" 3 3\n"
<< "ShadingInterpolation \"smooth\"\n"
<< "Rotate 180 0 0 1\n"
<< "WorldBegin\n";
}
void write_lights()
{
if (!m_is_preview)
{
// ShadowLight
m_out << "LightSource \"shadowdistant\" 1 \"from\" [0 0 0] \"to\" [0 0 1]"
<< " \"shadowname\" \"raytrace\" \"intensity\" "
<< m_shadow_intensity << "\n";
// Ambient light
m_out << "LightSource \"ambientlight\" 2 \"intensity\" "
<< m_ambient_intensity << "\n";
}
else
{
m_out << "LightSource \"distantLight\" 1 \"from\" [0 0 0] \"to\" [0 0 1]"
<< " \"intensity\" 0.85\n";
}
// Background light
m_out << "LightSource \"ambientlight\" 99 \"intensity\" 1\n";
// Turn background light OFF
turn_background_light(false);
}
void turn_background_light(bool turn_on)
{
if (!turn_on)
{
m_out << "Illuminate 1 1" << std::endl;
if (!m_is_preview)
m_out << "Illuminate 2 1" << std::endl;
m_out << "Illuminate 99 0" << std::endl;
}
else
{
m_out << "Illuminate 1 0" << std::endl;
if (!m_is_preview)
m_out << "Illuminate 2 0" << std::endl;
m_out << "Illuminate 99 1" << std::endl;
}
}
// CJTODO
void write_background(const Color& color)
{
write_turn_background_light(false);
/*m_out << "Surface \"constant\"" << std::endl;
write_color(color, false);
double corner = zmax_ * 2.;
double depth_pos = zmax_ * 1.6;
m_out << "Polygon \"P\" [";
m_out << " " << -corner << " " << -corner << " " << depth_pos << " ";
m_out << " " << corner << " " << -corner << " " << depth_pos << " ";
m_out << " " << corner << " " << corner << " " << depth_pos << " ";
m_out << " " << -corner << " " << corner << " " << depth_pos << " ";
m_out << "]" << std::endl;*/
}
void write_color(Color const& color, bool use_transparency)
{
if (m_current_color == color)
return;
m_current_color = color;
// Write opacity data
if (use_transparency)
write_opacity(std::get<3>(color));
// Write color data
m_out << "Color [ " << std::get<0>(color) << " " << std::get<1>(color)
<< " " << std::get<2>(color) << " ]\n";
}
void write_opacity(const double alpha)
{
if (m_current_alpha == alpha)
return;
m_current_alpha = alpha;
// Write opacity data
m_out << "Opacity " << alpha << " " << alpha << " " << alpha << std::endl;
}
void write_point(Point const& p)
{
m_out << " " << p[0] << " " << p[1] << " " << p[2] << " ";
}
void write_triangles()
{
m_out << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl;
for (auto simplex : m_simplices)
{
std::vector<std::set<std::size_t> > triangles;
// Get the triangles composing the simplex
combinations(simplex, 3, std::back_inserter(triangles));
for (auto const& t : triangles)
write_triangle(t);
}
}
template <typename PointIndexRange>
void write_triangle(PointIndexRange const& t)
{
// Color
write_color(m_triangle_color, true);
// Triangle
m_out << "Polygon \"P\" [";
for (auto idx : t)
write_point(m_points[idx]);
m_out << "]" << std::endl;
// Edges (will be drawn later on)
/*add_edge(p, q, edge_color);
add_edge(p, r, edge_color);
add_edge(q, r, edge_color);
// Vertices (will be drawn later on)
add_vertex(p, edge_color);
add_vertex(q, edge_color);
add_vertex(r, edge_color);*/
}
//===========================================================================
PointRandomAccessRange const& m_points;
SimplexRange const& m_simplices;
std::ofstream &m_out;
std::string m_rendered_image_filename;
bool m_is_preview;
int m_image_width;
int m_image_height;
Color m_current_color;
Color m_triangle_color;
double m_current_alpha;
bool m_ambient_light;
double m_ambient_intensity;
bool m_shadow;
double m_shadow_intensity;
};
} // namespace Tangential_complex_
} //namespace CGAL
#endif // CGAL_TC_WRITE_RIB_FILE_H

View File

@ -0,0 +1,643 @@
// Copyright (c) 2014 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
#ifndef SIMPLICIAL_COMPLEX_H
#define SIMPLICIAL_COMPLEX_H
#include <CGAL/Tangential_complex/config.h>
#include <CGAL/Tangential_complex/utilities.h>
#include "CGAL/Tangential_complex/console_color.h"
#include <CGAL/basic.h>
#include <CGAL/iterator.h>
// For is_pure_pseudomanifold
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/container/flat_map.hpp>
#include <algorithm>
#include <string>
#include <fstream>
namespace CGAL {
namespace Tangential_complex_ {
class Simplicial_complex
{
public:
typedef std::set<std::size_t> Simplex;
typedef std::set<Simplex> Simplex_set;
// If perform_checks = true, the function:
// - won't insert the simplex if it is already in a higher dim simplex
// - will erase any lower-dim simplices that are faces of the new simplex
// Returns true if the simplex was added
bool add_simplex(
const std::set<std::size_t> &s, bool perform_checks = true)
{
if (perform_checks)
{
unsigned int num_pts = static_cast<int>(s.size());
std::vector<Complex::iterator> to_erase;
bool check_higher_dim_simpl = true;
for (Complex::iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
// Check if the simplex is not already in a higher dim simplex
if (check_higher_dim_simpl
&& it_simplex->size() > num_pts
&& std::includes(it_simplex->begin(), it_simplex->end(),
s.begin(), s.end()))
{
// No need to insert it, then
return false;
}
// Check if the simplex includes some lower-dim simplices
if (it_simplex->size() < num_pts
&& std::includes(s.begin(), s.end(),
it_simplex->begin(), it_simplex->end()))
{
to_erase.push_back(it_simplex);
// We don't need to check higher-sim simplices any more
check_higher_dim_simpl = false;
}
}
for (std::vector<Complex::iterator>::const_iterator it= to_erase.begin();
it != to_erase.end() ; ++it)
{
m_complex.erase(*it);
}
}
return m_complex.insert(s).second;
}
// Ignore the point coordinates
bool load_simplices_from_OFF(const char *filename)
{
std::ifstream in(filename);
if (!in.is_open())
{
std::cerr << "Could not open '" << filename << "'" << std::endl;
return false;
}
std::string line;
std::getline(in, line); // Skip first line
std::size_t num_points, num_triangles, dummy;
in >> num_points;
in >> num_triangles;
std::getline(in, line); // Skip the rest of the line
// Skip points
for (std::size_t i = 0 ; i < num_points ; ++i)
std::getline(in, line);
// Read triangles
for (std::size_t i = 0 ; i < num_triangles ; ++i)
{
in >> dummy;
CGAL_assertion(dummy == 3);
std::set<std::size_t> tri;
std::size_t idx;
for (int j = 0 ; j < 3 ; ++j)
{
in >> idx;
tri.insert(idx);
}
std::getline(in, line); // Skip the rest of the line
add_simplex(tri, false);
}
return true;
}
const Simplex_set &simplex_range() const
{
return m_complex;
}
bool empty()
{
return m_complex.empty();
}
void clear()
{
m_complex.clear();
}
template <typename Test, typename Output_it>
void get_simplices_matching_test(Test test, Output_it out)
{
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
if (test(*it_simplex))
*out++ = *it_simplex;
}
}
// When a simplex S has only one co-face C, we can remove S and C
// without changing the topology
void collapse(int max_simplex_dim, bool quiet = false)
{
#ifdef CGAL_TC_VERBOSE
if (!quiet)
std::cerr << "Collapsing... ";
#endif
// We note k = max_simplex_dim - 1
int k = max_simplex_dim - 1;
typedef Complex::iterator Simplex_iterator;
typedef std::vector<Simplex_iterator> Simplex_iterator_list;
typedef std::map<Simplex, Simplex_iterator_list> Cofaces_map;
std::size_t num_collapsed_maximal_simplices = 0;
do
{
num_collapsed_maximal_simplices = 0;
// Create a map associating each non-maximal k-faces to the list of its
// maximal cofaces
Cofaces_map cofaces_map;
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
if (it_simplex->size() > k + 1)
{
std::vector<Simplex> k_faces;
// Get the k-faces composing the simplex
combinations(*it_simplex, k + 1, std::back_inserter(k_faces));
for (const auto &comb : k_faces) // CJTODO C++1
cofaces_map[comb].push_back(it_simplex);
}
}
// For each non-maximal k-face F, if F has only one maximal coface Cf:
// - Look for the other k-faces F2, F3... of Cf in the map and:
// * if the list contains only Cf, clear the list (we don't remove the
// list since it creates troubles with the iterators) and add the F2,
// F3... to the complex
// * otherwise, remove Cf from the associated list
// - Remove Cf from the complex
for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
it_map_end = cofaces_map.end() ;
it_map_elt != it_map_end ;
++it_map_elt)
{
if (it_map_elt->second.size() == 1)
{
std::vector<Simplex> k_faces;
const Simplex_iterator_list::value_type &it_Cf =
*it_map_elt->second.begin();
CGAL_assertion(it_Cf->size() == max_simplex_dim + 1);
// Get the k-faces composing the simplex
combinations(*it_Cf, k + 1, std::back_inserter(k_faces));
for (const auto &f2 : k_faces) // CJTODO C++1
{
// Skip F
if (f2 != it_map_elt->first)
{
Cofaces_map::iterator it_comb_in_map = cofaces_map.find(f2);
if (it_comb_in_map->second.size() == 1)
{
it_comb_in_map->second.clear();
m_complex.insert(f2);
}
else // it_comb_in_map->second.size() > 1
{
Simplex_iterator_list::iterator it = std::find(
it_comb_in_map->second.begin(),
it_comb_in_map->second.end(),
it_Cf);
CGAL_assertion(it != it_comb_in_map->second.end());
it_comb_in_map->second.erase(it);
}
}
}
m_complex.erase(it_Cf);
++num_collapsed_maximal_simplices;
}
}
// Repeat until no maximal simplex got removed
} while (num_collapsed_maximal_simplices > 0);
// Collapse the lower dimension simplices
if (k > 0)
collapse(max_simplex_dim - 1, true);
#ifdef CGAL_TC_VERBOSE
if (!quiet)
std::cerr << "done.\n";
#endif
}
void display_stats() const
{
std::cerr << yellow << "Complex stats:\n" << white;
if (m_complex.empty())
{
std::cerr << " * No simplices.\n";
}
else
{
// Number of simplex for each dimension
std::map<int, std::size_t> simplex_stats;
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
++simplex_stats[static_cast<int>(it_simplex->size()) - 1];
}
for (std::map<int, std::size_t>::const_iterator it_map = simplex_stats.begin() ;
it_map != simplex_stats.end() ; ++it_map)
{
std::cerr << " * " << it_map->first << "-simplices: "
<< it_map->second << "\n";
}
}
}
// verbose_level = 0, 1 or 2
bool is_pure_pseudomanifold__do_not_check_if_stars_are_connected(
int simplex_dim,
bool allow_borders = false,
bool exit_at_the_first_problem = false,
int verbose_level = 0,
std::size_t *p_num_wrong_dim_simplices = NULL,
std::size_t *p_num_wrong_number_of_cofaces = NULL) const
{
typedef std::set<std::size_t> K_1_face;
typedef std::map<K_1_face, std::size_t> Cofaces_map;
std::size_t num_wrong_dim_simplices = 0;
std::size_t num_wrong_number_of_cofaces = 0;
// Counts the number of cofaces of each K_1_face
// Create a map associating each non-maximal k-faces to the list of its
// maximal cofaces
Cofaces_map cofaces_map;
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
if (it_simplex->size() != simplex_dim + 1)
{
if (verbose_level >= 2)
std::cerr << "Found a simplex with dim = "
<< it_simplex->size() - 1 << "\n";
++num_wrong_dim_simplices;
}
else
{
std::vector<K_1_face> k_1_faces;
// Get the facets composing the simplex
combinations(
*it_simplex, simplex_dim, std::back_inserter(k_1_faces));
for (const auto &k_1_face : k_1_faces) // CJTODO C++1
{
++cofaces_map[k_1_face];
}
}
}
for (Cofaces_map::const_iterator it_map_elt = cofaces_map.begin(),
it_map_end = cofaces_map.end() ;
it_map_elt != it_map_end ;
++it_map_elt)
{
if (it_map_elt->second != 2
&& (!allow_borders || it_map_elt->second != 1))
{
if (verbose_level >= 2)
std::cerr << "Found a k-1-face with "
<< it_map_elt->second << " cofaces\n";
if (exit_at_the_first_problem)
return false;
else
++num_wrong_number_of_cofaces;
}
}
bool ret = num_wrong_dim_simplices == 0 && num_wrong_number_of_cofaces == 0;
if (verbose_level >= 1)
{
std::cerr << "Pure pseudo-manifold: ";
if (ret)
{
std::cerr << green << "YES" << white << "\n";
}
else
{
std::cerr << red << "NO" << white << "\n"
<< " * Number of wrong dimension simplices: "
<< num_wrong_dim_simplices << "\n"
<< " * Number of wrong number of cofaces: "
<< num_wrong_number_of_cofaces << "\n";
}
}
if (p_num_wrong_dim_simplices)
*p_num_wrong_dim_simplices = num_wrong_dim_simplices;
if (p_num_wrong_number_of_cofaces)
*p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
return ret;
}
template <int K>
std::size_t num_K_simplices() const
{
std::set<Simplex> k_simplices;
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
if (it_simplex->size() == K + 1)
{
k_simplices.insert(*it_simplex);
}
else if (it_simplex->size() > K + 1)
{
// Get the k-faces composing the simplex
combinations(
*it_simplex, K + 1, std::inserter(k_simplices, k_simplices.begin()));
}
}
return k_simplices.size();
}
std::ptrdiff_t euler_characteristic(bool verbose = false) const
{
if (verbose)
std::cerr << "\nComputing Euler characteristic of the complex...\n";
std::size_t num_vertices = num_K_simplices<0>();
std::size_t num_edges = num_K_simplices<1>();
std::size_t num_triangles = num_K_simplices<2>();
std::ptrdiff_t ec =
(std::ptrdiff_t) num_vertices
- (std::ptrdiff_t) num_edges
+ (std::ptrdiff_t) num_triangles;
if (verbose)
std::cerr << "Euler characteristic: V - E + F = "
<< num_vertices << " - " << num_edges << " + " << num_triangles << " = "
<< blue
<< ec
<< white << "\n";
return ec;
}
// CJTODO: ADD COMMENTS
bool is_pure_pseudomanifold(
int simplex_dim,
std::size_t num_vertices,
bool allow_borders = false,
bool exit_at_the_first_problem = false,
int verbose_level = 0,
std::size_t *p_num_wrong_dim_simplices = NULL,
std::size_t *p_num_wrong_number_of_cofaces = NULL,
std::size_t *p_num_unconnected_stars = NULL,
Simplex_set *p_wrong_dim_simplices = NULL,
Simplex_set *p_wrong_number_of_cofaces_simplices = NULL,
Simplex_set *p_unconnected_stars_simplices = NULL) const
{
// If simplex_dim == 1, we do not need to check if stars are connected
if (simplex_dim == 1)
{
if (p_num_unconnected_stars)
*p_num_unconnected_stars = 0;
return is_pure_pseudomanifold__do_not_check_if_stars_are_connected(
simplex_dim,
allow_borders,
exit_at_the_first_problem,
verbose_level,
p_num_wrong_dim_simplices,
p_num_wrong_number_of_cofaces);
}
// Associates each vertex (= the index in the vector)
// to its star (list of simplices)
typedef std::vector<std::vector<Complex::const_iterator> > Stars;
std::size_t num_wrong_dim_simplices = 0;
std::size_t num_wrong_number_of_cofaces = 0;
std::size_t num_unconnected_stars = 0;
// Fills a Stars data structure
Stars stars;
stars.resize(num_vertices);
for (Complex::const_iterator it_simplex = m_complex.begin(),
it_simplex_end = m_complex.end() ;
it_simplex != it_simplex_end ;
++it_simplex)
{
if (it_simplex->size() != simplex_dim + 1)
{
if (verbose_level >= 2)
std::cerr << "Found a simplex with dim = "
<< it_simplex->size() - 1 << "\n";
++num_wrong_dim_simplices;
if (p_wrong_dim_simplices)
p_wrong_dim_simplices->insert(*it_simplex);
}
else
{
for (Simplex::const_iterator it_point_idx = it_simplex->begin() ;
it_point_idx != it_simplex->end() ;
++it_point_idx)
{
stars[*it_point_idx].push_back(it_simplex);
}
}
}
// Now, for each star, we have a vector of its d-simplices
// i.e. one index for each d-simplex
// Boost Graph only deals with indexes, so we also need indexes for the
// (d-1)-simplices
std::size_t center_vertex_index = 0;
for (Stars::const_iterator it_star = stars.begin() ;
it_star != stars.end() ;
++it_star, ++center_vertex_index)
{
typedef std::map<Simplex, std::vector<std::size_t> >
Dm1_faces_to_adj_D_faces;
Dm1_faces_to_adj_D_faces dm1_faces_to_adj_d_faces;
for (int i_dsimpl = 0 ; i_dsimpl < it_star->size() ; ++i_dsimpl)
{
Simplex dm1_simpl_of_link = *((*it_star)[i_dsimpl]);
dm1_simpl_of_link.erase(center_vertex_index);
// Copy it to a vector so that we can use operator[] on it
std::vector<std::size_t> dm1_simpl_of_link_vec(
dm1_simpl_of_link.begin(), dm1_simpl_of_link.end());
CGAL::Combination_enumerator<int> dm2_simplices(
simplex_dim - 1, 0, simplex_dim);
for ( ; !dm2_simplices.finished() ; ++dm2_simplices)
{
Simplex dm2_simpl;
for (int j = 0 ; j < simplex_dim - 1 ; ++j)
dm2_simpl.insert(dm1_simpl_of_link_vec[dm2_simplices[j]]);
dm1_faces_to_adj_d_faces[dm2_simpl].push_back(i_dsimpl);
}
}
Adj_graph adj_graph;
std::vector<Graph_vertex> d_faces_descriptors;
d_faces_descriptors.resize(it_star->size());
for (int j = 0 ; j < it_star->size() ; ++j)
d_faces_descriptors[j] = boost::add_vertex(adj_graph);
Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it =
dm1_faces_to_adj_d_faces.begin();
Dm1_faces_to_adj_D_faces::const_iterator dm1_to_d_it_end =
dm1_faces_to_adj_d_faces.end();
for (std::size_t i_km1_face = 0 ;
dm1_to_d_it != dm1_to_d_it_end ;
++dm1_to_d_it, ++i_km1_face)
{
Graph_vertex km1_gv = boost::add_vertex(adj_graph);
for (std::vector<std::size_t>::const_iterator kface_it =
dm1_to_d_it->second.begin() ;
kface_it != dm1_to_d_it->second.end() ;
++kface_it)
{
boost::add_edge(km1_gv, *kface_it, adj_graph);
}
if (dm1_to_d_it->second.size() != 2
&& (!allow_borders || dm1_to_d_it->second.size() != 1))
{
++num_wrong_number_of_cofaces;
if (p_wrong_number_of_cofaces_simplices)
{
for (auto idx : dm1_to_d_it->second)
p_wrong_number_of_cofaces_simplices->insert(*((*it_star)[idx]));
}
}
}
// What is left is to check the connexity
bool is_connected = true;
if (boost::num_vertices(adj_graph) > 0)
{
std::vector<int> components(boost::num_vertices(adj_graph));
is_connected =
(boost::connected_components(adj_graph, &components[0]) == 1);
}
if (!is_connected)
{
if (verbose_level >= 2)
std::cerr << "Error: star #" << center_vertex_index
<< " is not connected\n";
++num_unconnected_stars;
if (p_unconnected_stars_simplices)
{
for (std::vector<Complex::const_iterator>::const_iterator
it_simpl = it_star->begin(),
it_simpl_end = it_star->end();
it_simpl != it_simpl_end ;
++it_simpl)
{
p_unconnected_stars_simplices->insert(**it_simpl);
}
}
}
}
// Each one has been counted several times ("simplex_dim" times)
num_wrong_number_of_cofaces /= simplex_dim;
bool ret =
num_wrong_dim_simplices == 0
&& num_wrong_number_of_cofaces == 0
&& num_unconnected_stars == 0;
if (verbose_level >= 1)
{
std::cerr << "Pure pseudo-manifold: ";
if (ret)
{
std::cerr << green << "YES" << white << "\n";
}
else
{
std::cerr << red << "NO" << white << "\n"
<< " * Number of wrong dimension simplices: "
<< num_wrong_dim_simplices << "\n"
<< " * Number of wrong number of cofaces: "
<< num_wrong_number_of_cofaces << "\n"
<< " * Number of not-connected stars: "
<< num_unconnected_stars << "\n";
}
}
if (p_num_wrong_dim_simplices)
*p_num_wrong_dim_simplices = num_wrong_dim_simplices;
if (p_num_wrong_number_of_cofaces)
*p_num_wrong_number_of_cofaces = num_wrong_number_of_cofaces;
if (p_num_unconnected_stars)
*p_num_unconnected_stars = num_unconnected_stars;
return ret;
}
private:
typedef Simplex_set Complex;
// graph is an adjacency list
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> Adj_graph;
// map that gives to a certain simplex its node in graph and its dimension
typedef boost::graph_traits<Adj_graph>::vertex_descriptor Graph_vertex;
typedef boost::graph_traits<Adj_graph>::edge_descriptor Graph_edge;
Complex m_complex;
}; // /class Simplicial_complex
} // namespace Tangential_complex_
} //namespace CGAL
#endif // SIMPLICIAL_COMPLEX_H

View File

@ -0,0 +1,82 @@
// Copyright (c) 2014 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
#ifndef CGAL_TC_CONFIG_H
#define CGAL_TC_CONFIG_H
#include <CGAL/config.h>
// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false
// positives in Intel TBB
// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/)
#ifdef _DEBUG
# define TBB_USE_THREADING_TOOL
#endif
//=========================== Alpha-TC or not? ================================
//#define CGAL_ALPHA_TC
//#define CGAL_USE_A_FIXED_ALPHA
const double CGAL_TC_ALPHA_VALUE = 0.3;
//========================= Debugging & profiling =============================
#define CGAL_TC_PROFILING
#define CGAL_TC_VERBOSE
//#define CGAL_TC_VERY_VERBOSE
//#define CGAL_TC_PERFORM_EXTRA_CHECKS
#define CGAL_TC_SHOW_DETAILED_STATS_FOR_INCONSISTENCIES
// Solving inconsistencies: only perturb the vertex, the simplex or more?
//#define CGAL_TC_PERTURB_THE_CENTER_VERTEX_ONLY
//#define CGAL_TC_PERTURB_THE_SIMPLEX_ONLY
//#define CGAL_TC_PERTURB_THE_1_STAR
#define CGAL_TC_PERTURB_N_CLOSEST_POINTS // perturb the CGAL_TC_NUMBER_OF_PERTURBED_POINTS closest points
// Otherwise, perturb one random point of the simplex
// Only used if CGAL_TC_PERTURB_N_CLOSEST_POINTS is defined
#define CGAL_TC_NUMBER_OF_PERTURBED_POINTS(intr_dim) (1)
//#define CGAL_TC_NUMBER_OF_PERTURBED_POINTS(intr_dim) (intr_dim + 2)
#define CGAL_MESH_D_PROFILING
#define CGAL_MESH_D_VERBOSE
//========================= Strategy ==========================================
#define CGAL_TC_NANOFLANN_IS_AVAILABLE
//#define CGAL_TC_ANN_IS_AVAILABLE
//#define CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
#define CGAL_TC_GLOBAL_REFRESH
//#define CGAL_TC_ON_DEMAND_REFRESH // CJTODO: not implemented yet
// The idea is to perform a global refresh + some local refreshes, just
// for local tri where there are some inconsistencies
// But be careful: refreshing the TC may invalidate cells, so the
// incident cells have to be recomputed again
#define CGAL_TC_PERTURB_POSITION
# define CGAL_TC_PERTURB_POSITION_TANGENTIAL // default
//# define CGAL_TC_PERTURB_POSITION_GLOBAL
//#define CGAL_TC_PERTURB_WEIGHT
//#define CGAL_TC_PERTURB_TANGENT_SPACE
//========================= Parameters ========================================
// PCA will use BASE_VALUE_FOR_PCA^intrinsic_dim points
const std::size_t BASE_VALUE_FOR_PCA = 5;
const unsigned int BASE_VALUE_FOR_ALPHA_TC_NEIGHBORHOOD = 5;
#endif // CGAL_TC_CONFIG_H

View File

@ -0,0 +1,81 @@
#ifndef CONSOLE_COLOR_H_
#define CONSOLE_COLOR_H_
#include <iostream>
#if defined(WIN32)
#include <windows.h>
#endif
inline std::ostream& blue(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout,
FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
#else
s << "\x1b[0;34m";
#endif
return s;
}
inline std::ostream& red(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout, FOREGROUND_RED|FOREGROUND_INTENSITY);
#else
s << "\x1b[0;31m";
#endif
return s;
}
inline std::ostream& green(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN|FOREGROUND_INTENSITY);
#else
s << "\x1b[0;32m";
#endif
return s;
}
inline std::ostream& yellow(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout,
FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_INTENSITY);
#else
s << "\x1b[0;33m";
#endif
return s;
}
inline std::ostream& white(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout,
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
#else
s << "\x1b[0;37m";
#endif
return s;
}
inline std::ostream& black_on_white(std::ostream &s)
{
#if defined(WIN32)
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdout,
BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
#else
s << "\x1b[0;33m";
#endif
return s;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,564 @@
#ifndef PROTECTED_SETS_H
#define PROTECTED_SETS_H
#include <CGAL/Cartesian_d.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Euclidean_distance.h>
#include <CGAL/Kernel_d/Sphere_d.h>
#include <CGAL/Kernel_d/Hyperplane_d.h>
#include <CGAL/Kernel_d/Vector_d.h>
#include <CGAL/Delaunay_triangulation.h>
#include <algorithm>
#include <list>
#include <chrono>
#include <random>
typedef CGAL::Epick_d<CGAL::Dynamic_dimension_tag> K;
typedef K::FT FT;
typedef K::Point_d Point_d;
typedef K::Vector_d Vector_d;
typedef K::Oriented_side_d Oriented_side_d;
typedef K::Has_on_positive_side_d Has_on_positive_side_d;
typedef K::Sphere_d Sphere_d;
typedef K::Hyperplane_d Hyperplane_d;
typedef CGAL::Delaunay_triangulation<K> Delaunay_triangulation;
typedef Delaunay_triangulation::Facet Facet;
typedef Delaunay_triangulation::Vertex_handle Delaunay_vertex;
typedef Delaunay_triangulation::Full_cell_handle Full_cell_handle;
typedef std::vector<Point_d> Point_Vector;
typedef CGAL::Euclidean_distance<K> Euclidean_distance;
FT _sfty = pow(10,-14);
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// AUXILLARY FUNCTIONS
///////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Insert a point in Delaunay triangulation. If you are working in a flat torus, the procedure adds all the 3^d copies in adjacent cubes as well
*
* W is the initial point vector
* chosen_landmark is the index of the chosen point in W
* landmarks_ind is the vector of indices of already chosen points in W
* delaunay is the Delaunay triangulation
* landmark_count is the current number of chosen vertices
* torus is true iff you are working on a flat torus [-1,1]^d
* OUT: Vertex handle to the newly inserted point
*/
Delaunay_vertex insert_delaunay_landmark_with_copies(Point_Vector& W, int chosen_landmark, std::vector<int>& landmarks_ind, Delaunay_triangulation& delaunay, int& landmark_count, bool torus)
{
if (!torus)
{
Delaunay_vertex v =delaunay.insert(W[chosen_landmark]);
landmarks_ind.push_back(chosen_landmark);
landmark_count++;
return v;
}
else
{
int D = W[0].size();
int nb_cells = pow(3, D);
Delaunay_vertex v;
for (int i = 0; i < nb_cells; ++i)
{
std::vector<FT> point;
int cell_i = i;
for (int l = 0; l < D; ++l)
{
point.push_back(W[chosen_landmark][l] + 2.0*(cell_i%3-1));
cell_i /= 3;
}
v = delaunay.insert(point);
}
landmarks_ind.push_back(chosen_landmark);
landmark_count++;
return v;
}
}
/** Small check if the vertex v is in the full cell fc
*/
bool vertex_is_in_full_cell(Delaunay_triangulation::Vertex_handle v, Full_cell_handle fc)
{
for (auto v_it = fc->vertices_begin(); v_it != fc->vertices_end(); ++v_it)
if (*v_it == v)
return true;
return false;
}
/** Fill chosen point vector from indices with copies if you are working on a flat torus
*
* IN: W is the point vector
* OUT: landmarks is the output vector
* IN: landmarks_ind is the vector of indices
* IN: torus is true iff you are working on a flat torus [-1,1]^d
*/
void fill_landmarks(Point_Vector& W, Point_Vector& landmarks, std::vector<int>& landmarks_ind, bool torus)
{
if (!torus)
for (unsigned j = 0; j < landmarks_ind.size(); ++j)
landmarks.push_back(W[landmarks_ind[j]]);
else
{
int D = W[0].size();
int nb_cells = pow(3, D);
int nbL = landmarks_ind.size();
// Fill landmarks
for (int i = 0; i < nb_cells-1; ++i)
for (int j = 0; j < nbL; ++j)
{
int cell_i = i;
Point_d point;
for (int l = 0; l < D; ++l)
{
point.push_back(W[landmarks_ind[j]][l] + 2.0*(cell_i-1));
cell_i /= 3;
}
landmarks.push_back(point);
}
}
}
/** Fill a vector of all simplices in the Delaunay triangulation giving integer indices to vertices
*
* IN: t is the Delaunay triangulation
* OUT: full_cells is the output vector
*/
void fill_full_cell_vector(Delaunay_triangulation& t, std::vector<std::vector<int>>& full_cells)
{
// Store vertex indices in a map
int ind = 0; //index of a vertex
std::map<Delaunay_triangulation::Vertex_handle, int> index_of_vertex;
for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
if (t.is_infinite(v_it))
continue;
else
index_of_vertex[v_it] = ind++;
// Write full cells as vectors in full_cells
for (auto fc_it = t.full_cells_begin(); fc_it != t.full_cells_end(); ++fc_it)
{
if (t.is_infinite(fc_it))
continue;
Point_Vector vertices;
for (auto fc_v_it = fc_it->vertices_begin(); fc_v_it != fc_it->vertices_end(); ++fc_v_it)
vertices.push_back((*fc_v_it)->point());
Sphere_d cs( vertices.begin(), vertices.end());
Point_d csc = cs.center();
bool in_cube = true;
for (auto xi = csc.cartesian_begin(); xi != csc.cartesian_end(); ++xi)
if (*xi > 1.0 || *xi < -1.0)
{
in_cube = false; break;
}
if (!in_cube)
continue;
std::vector<int> cell;
for (auto v_it = fc_it->vertices_begin(); v_it != fc_it->vertices_end(); ++v_it)
cell.push_back(index_of_vertex[*v_it]);
full_cells.push_back(cell);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// IS VIOLATED TEST
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/** Check if a newly created cell is protected from old vertices
*
* t is the Delaunay triangulation
* vertices is the vector containing the point to insert and a facet f in t
* v1 is the vertex of t, such that f and v1 form a simplex
* v2 is the vertex of t, such that f and v2 form another simplex
* delta is the protection constant
* power_protection is true iff the delta-power protection is used
*/
bool new_cell_is_violated(Delaunay_triangulation& t, std::vector<Point_d>& vertices, const Delaunay_vertex& v1, const Delaunay_vertex v2, FT delta, bool power_protection)
{
assert(vertices.size() == vertices[0].size() ||
vertices.size() == vertices[0].size() + 1); //simplex size = d | d+1
assert(v1 != v2);
if (vertices.size() == vertices[0].size() + 1)
// FINITE CASE
{
Sphere_d cs(vertices.begin(), vertices.end());
Point_d center_cs = cs.center();
FT r = sqrt(Euclidean_distance().transformed_distance(center_cs, vertices[0]));
/*
for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
if (!t.is_infinite(v_it))
{
//CGAL::Oriented_side side = Oriented_side_d()(cs, (v_it)->point());
if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
{
FT dist2 = Euclidean_distance().transformed_distance(center_cs, (v_it)->point());
if (!power_protection)
if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
return true;
if (power_protection)
if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
return true;
}
}
*/
if (!t.is_infinite(v1))
{
FT dist2 = Euclidean_distance().transformed_distance(center_cs, v1->point());
if (!power_protection)
if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
return true;
if (power_protection)
if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
return true;
}
if (!t.is_infinite(v2))
{
FT dist2 = Euclidean_distance().transformed_distance(center_cs, v2->point());
if (!power_protection)
if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
return true;
if (power_protection)
if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
return true;
}
}
else
// INFINITE CASE
{
Delaunay_triangulation::Vertex_iterator v = t.vertices_begin();
while (t.is_infinite(v) || std::find(vertices.begin(), vertices.end(), v->point()) == vertices.end())
v++;
Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v->point(), CGAL::ON_POSITIVE_SIDE);
Vector_d orth_v = facet_plane.orthogonal_vector();
/*
for (auto v_it = t.vertices_begin(); v_it != t.vertices_end(); ++v_it)
if (!t.is_infinite(v_it))
if (std::find(vertices.begin(), vertices.end(), v_it->point()) == vertices.end())
{
std::vector<FT> coords;
Point_d p = v_it->point();
auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
Point_d p_delta = Point_d(coords);
bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
if (!p_is_inside && p_delta_is_inside)
return true;
}
*/
if (!t.is_infinite(v1))
{
std::vector<FT> coords;
Point_d p = v1->point();
auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
Point_d p_delta = Point_d(coords);
bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
if (!p_is_inside && p_delta_is_inside)
return true;
}
if (!t.is_infinite(v2))
{
std::vector<FT> coords;
Point_d p = v2->point();
auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
Point_d p_delta = Point_d(coords);
bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p);
bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
if (!p_is_inside && p_delta_is_inside)
return true;
}
}
return false;
}
/** Auxillary recursive function to check if the point p violates the protection of the cell c and
* if there is a violation of an eventual new cell
*
* p is the point to insert
* t is the current triangulation
* c is the current cell (simplex)
* parent_cell is the parent cell (simplex)
* index is the index of the facet between c and parent_cell from parent_cell's point of view
* D is the dimension of the triangulation
* delta is the protection constant
* marked_cells is the vector of all visited cells containing p in their circumscribed ball
* power_protection is true iff you are working with delta-power protection
*
* OUT: true iff inserting p hasn't produced any violation so far
*/
bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, Full_cell_handle c, Full_cell_handle parent_cell, int index, int D, FT delta, std::vector<Full_cell_handle>& marked_cells, bool power_protection)
{
Euclidean_distance ed;
std::vector<Point_d> vertices;
if (!t.is_infinite(c))
{
// if the cell is finite, we look if the protection is violated
for (auto v_it = c->vertices_begin(); v_it != c->vertices_end(); ++v_it)
vertices.push_back((*v_it)->point());
Sphere_d cs( vertices.begin(), vertices.end());
Point_d center_cs = cs.center();
FT r = sqrt(ed.transformed_distance(center_cs, vertices[0]));
FT dist2 = ed.transformed_distance(center_cs, p);
// if the new point is inside the protection ball of a non conflicting simplex
if (!power_protection)
if (dist2 >= r*r-_sfty && dist2 <= (r+delta)*(r+delta))
return true;
if (power_protection)
if (dist2 >= r*r-_sfty && dist2 <= r*r+delta*delta)
return true;
// if the new point is inside the circumscribing ball : continue violation searching on neighbours
//if (dist2 < r*r)
//if (dist2 < (5*r+delta)*(5*r+delta))
if (dist2 < r*r)
{
c->tds_data().mark_visited();
marked_cells.push_back(c);
for (int i = 0; i < D+1; ++i)
{
Full_cell_handle next_c = c->neighbor(i);
if (next_c->tds_data().is_clear() &&
is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection))
return true;
}
}
// if the new point is outside the protection sphere
else
{
// facet f is on the border of the conflict zone : check protection of simplex {p,f}
// the new simplex is guaranteed to be finite
vertices.clear(); vertices.push_back(p);
for (int i = 0; i < D+1; ++i)
if (i != index)
vertices.push_back(parent_cell->vertex(i)->point());
Delaunay_vertex vertex_to_check = t.infinite_vertex();
for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
if (!vertex_is_in_full_cell(*vh_it, parent_cell))
{
vertex_to_check = *vh_it; break;
}
if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection))
//if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
return true;
}
}
else
{
// Inside of the convex hull is + side. Outside is - side.
for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
if (!t.is_infinite(*vh_it))
vertices.push_back((*vh_it)->point());
Delaunay_triangulation::Vertex_iterator v_it = t.vertices_begin();
while (t.is_infinite(v_it) || vertex_is_in_full_cell(v_it, c))
v_it++;
Hyperplane_d facet_plane(vertices.begin(), vertices.end(), v_it->point(), CGAL::ON_POSITIVE_SIDE);
//CGAL::Oriented_side outside = Oriented_side_d()(facet_plane, v_it->point());
Vector_d orth_v = facet_plane.orthogonal_vector();
std::vector<FT> coords;
auto orth_i = orth_v.cartesian_begin(), p_i = p.cartesian_begin();
for (; orth_i != orth_v.cartesian_end(); ++orth_i, ++p_i)
coords.push_back((*p_i) - (*orth_i) * delta / sqrt(orth_v.squared_length()));
Point_d p_delta = Point_d(coords);
bool p_is_inside = !Has_on_positive_side_d()(facet_plane, p) && (Oriented_side_d()(facet_plane, p) != CGAL::ZERO);
bool p_delta_is_inside = !Has_on_positive_side_d()(facet_plane, p_delta);
if (!p_is_inside && p_delta_is_inside)
return true;
//if the cell is infinite we look at the neighbours regardless
if (p_is_inside)
{
c->tds_data().mark_visited();
marked_cells.push_back(c);
for (int i = 0; i < D+1; ++i)
{
Full_cell_handle next_c = c->neighbor(i);
if (next_c->tds_data().is_clear() &&
is_violating_protection(p, t, next_c, c, i, D, delta, marked_cells, power_protection))
return true;
}
}
else
{
// facet f is on the border of the conflict zone : check protection of simplex {p,f}
// the new simplex is finite if the parent cell is finite
vertices.clear(); vertices.push_back(p);
for (int i = 0; i < D+1; ++i)
if (i != index)
if (!t.is_infinite(parent_cell->vertex(i)))
vertices.push_back(parent_cell->vertex(i)->point());
Delaunay_vertex vertex_to_check = t.infinite_vertex();
for (auto vh_it = c->vertices_begin(); vh_it != c->vertices_end(); ++vh_it)
if (!vertex_is_in_full_cell(*vh_it, parent_cell))
{
vertex_to_check = *vh_it; break;
}
if (new_cell_is_violated(t, vertices, vertex_to_check, parent_cell->vertex(index), delta, power_protection))
//if (new_cell_is_violated(t, vertices, vertex_to_check->point(), delta))
return true;
}
}
//c->tds_data().clear_visited();
//marked_cells.pop_back();
return false;
}
/** Checks if inserting the point p in t will make conflicts
*
* p is the point to insert
* t is the current triangulation
* D is the dimension of triangulation
* delta is the protection constant
* power_protection is true iff you are working with delta-power protection
* OUT: true iff inserting p produces a violation of delta-protection.
*/
bool is_violating_protection(Point_d& p, Delaunay_triangulation& t, int D, FT delta, bool power_protection)
{
Euclidean_distance ed;
Delaunay_triangulation::Vertex_handle v;
Delaunay_triangulation::Face f(t.current_dimension());
Delaunay_triangulation::Facet ft;
Delaunay_triangulation::Full_cell_handle c;
Delaunay_triangulation::Locate_type lt;
std::vector<Full_cell_handle> marked_cells;
c = t.locate(p, lt, f, ft, v);
bool violation_existing_cells = is_violating_protection(p, t, c, c, 0, D, delta, marked_cells, power_protection);
for (Full_cell_handle fc : marked_cells)
fc->tds_data().clear();
return violation_existing_cells;
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//!!!!!!!!!!!!! THE INTERFACE FOR LANDMARK CHOICE IS BELOW !!!!!!!!!!//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// LANDMARK CHOICE PROCEDURE
///////////////////////////////////////////////////////////////////////
/** Procedure to compute a maximal protected subset from a point cloud. All OUTs should be empty at call.
*
* IN: W is the initial point cloud having type Epick_d<Dynamic_dimension_tag>::Point_d
* IN: nbP is the size of W
* OUT: landmarks is the output vector for the points
* OUT: landmarks_ind is the output vector for the indices of the selected points in W
* IN: delta is the constant of protection
* OUT: full_cells is the output vector of the simplices in the final Delaunay triangulation
* IN: torus is true iff you are working on a flat torus [-1,1]^d
*/
void landmark_choice_protected_delaunay(Point_Vector& W, int nbP, Point_Vector& landmarks, std::vector<int>& landmarks_ind, FT delta, std::vector<std::vector<int>>& full_cells, bool torus, bool power_protection)
{
unsigned D = W[0].size();
Euclidean_distance ed;
Delaunay_triangulation t(D);
CGAL::Random rand;
int landmark_count = 0;
std::list<int> index_list;
// shuffle the list of indexes (via a vector)
{
std::vector<int> temp_vector;
for (int i = 0; i < nbP; ++i)
temp_vector.push_back(i);
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::shuffle(temp_vector.begin(), temp_vector.end(), std::default_random_engine(seed));
//CGAL::spatial_sort(temp_vector.begin(), temp_vector.end());
for (std::vector<int>::iterator it = temp_vector.begin(); it != temp_vector.end(); ++it)
index_list.push_front(*it);
}
if (!torus)
for (unsigned pos1 = 0; pos1 < D+1; ++pos1)
{
std::vector<FT> point;
for (unsigned i = 0; i < pos1; ++i)
point.push_back(-1);
if (pos1 != D)
point.push_back(1);
for (unsigned i = pos1+1; i < D; ++i)
point.push_back(0);
assert(point.size() == D);
W[index_list.front()] = Point_d(point);
insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
index_list.pop_front();
}
else if (D == 2)
{
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 2; ++j)
{
W[index_list.front()] = Point_d(std::vector<FT>{i*0.5, j*1.0});
insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
index_list.pop_front();
W[index_list.front()] = Point_d(std::vector<FT>{0.25+i*0.5, 0.5+j});
insert_delaunay_landmark_with_copies(W, index_list.front(), landmarks_ind, t, landmark_count, torus);
index_list.pop_front();
}
}
else
std::cout << "No torus starter available for dim>2\n";
std::list<int>::iterator list_it = index_list.begin();
while (list_it != index_list.end())
{
if (!is_violating_protection(W[*list_it], t, D, delta, power_protection))
{
// If no conflicts then insert in every copy of T^3
insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count, torus);
index_list.erase(list_it);
list_it = index_list.begin();
/*
// PIECE OF CODE FOR DEBUGGING PURPOSES
Delaunay_vertex inserted_v = insert_delaunay_landmark_with_copies(W, *list_it, landmarks_ind, t, landmark_count);
if (triangulation_is_protected(t, delta))
{
index_list.erase(list_it);
list_it = index_list.begin();
}
else
{ //THAT'S WHERE SOMETHING'S WRONG
t.remove(inserted_v);
landmarks_ind.pop_back();
landmark_count--;
write_delaunay_mesh(t, W[*list_it], is2d);
is_violating_protection(W[*list_it], t_old, D, delta); //Called for encore
}
*/
//std::cout << "index_list_size() = " << index_list.size() << "\n";
}
else
{
list_it++;
//std::cout << "!!!!!WARNING!!!!! A POINT HAS BEEN OMITTED!!!\n";
}
//if (list_it != index_list.end())
// write_delaunay_mesh(t, W[*list_it], is2d);
}
fill_landmarks(W, landmarks, landmarks_ind, torus);
fill_full_cell_vector(t, full_cells);
/*
if (triangulation_is_protected(t, delta))
std::cout << "Triangulation is ok\n";
else
{
std::cout << "Triangulation is BAD!! T_T しくしく!\n";
}
*/
//write_delaunay_mesh(t, W[0], is2d);
//std::cout << t << std::endl;
}
#endif

View File

@ -0,0 +1,632 @@
// Copyright (c) 2014 INRIA Sophia-Antipolis (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: $
//
//
// Author(s) : Clement Jamin
#ifndef CGAL_TC_UTILITIES_H
#define CGAL_TC_UTILITIES_H
#include <CGAL/basic.h>
#include <CGAL/Dimension.h>
#include <CGAL/Combination_enumerator.h>
#include <Eigen/Core>
#include <Eigen/Eigen>
#include <set>
#include <vector>
#include <array>
#include <atomic> // CJTODO: this is C++11 => use boost.Atomic (but it's too recent)
// or tbb::atomic (works for doubles, but not officially)
namespace CGAL {
namespace Tangential_complex_ {
// Provides copy constructors to std::atomic so that
// it can be used in a vector
template <typename T>
struct Atomic_wrapper
: public std::atomic<T>
{
typedef std::atomic<T> Base;
Atomic_wrapper() {}
Atomic_wrapper(const T &t) : Base(t) {}
Atomic_wrapper(const std::atomic<T> &a) : Base(a.load()) {}
Atomic_wrapper(const Atomic_wrapper &other) : Base(other.load())
{}
Atomic_wrapper &operator=(const T &other)
{
Base::store(other);
return *this;
}
Atomic_wrapper &operator=(const std::atomic<T> &other)
{
Base::store(other.load());
return *this;
}
Atomic_wrapper &operator=(const Atomic_wrapper &other)
{
Base::store(other.load());
return *this;
}
};
/*template <typename T>
struct Atomic_wrapper
{
std::atomic<T> _a;
Atomic_wrapper()
:_a()
{}
Atomic_wrapper(const std::atomic<T> &other)
:_a(other.load())
{}
Atomic_wrapper(const Atomic_wrapper &other)
:_a(other._a.load())
{}
Atomic_wrapper(const T &other)
:_a(other)
{}
Atomic_wrapper &operator=(const std::atomic<T> &other)
{
_a.store(other._a.load());
return *this;
}
Atomic_wrapper &operator=(const Atomic_wrapper &other)
{
_a.store(other._a.load());
return *this;
}
Atomic_wrapper &operator=(const T &other)
{
_a.store(other);
return *this;
}
operator T() const
{
return _a.load();
}
operator std::atomic<T>() const
{
return _a;
}
};*/
// Modifies v in-place
template <typename K>
typename K::Vector_d& normalize_vector(typename K::Vector_d& v,
K const& k)
{
v = k.scaled_vector_d_object()(
v, typename K::FT(1)/CGAL::sqrt(k.squared_length_d_object()(v)));
return v;
}
template<typename Kernel>
struct Basis
{
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_d Point;
typedef typename Kernel::Vector_d Vector;
typedef typename std::vector<Vector>::const_iterator const_iterator;
std::size_t m_origin;
std::vector<Vector> m_vectors;
std::size_t origin() const { return m_origin; }
void set_origin(std::size_t o) { m_origin = o; }
const_iterator begin() const { return m_vectors.begin(); }
const_iterator end() const { return m_vectors.end(); }
std::size_t size() const { return m_vectors.size(); }
Vector& operator[](const std::size_t i)
{
return m_vectors[i];
}
const Vector& operator[](const std::size_t i) const
{
return m_vectors[i];
}
void push_back(const Vector& v)
{
m_vectors.push_back(v);
}
void reserve(const std::size_t s)
{
m_vectors.reserve(s);
}
Basis() { }
Basis(std::size_t origin) : m_origin(origin) { }
Basis(std::size_t origin, const std::vector<Vector>& vectors)
: m_origin(origin), m_vectors(vectors)
{ }
#ifdef CGAL_ALPHA_TC
// Thickening vectors...
struct Thickening_vector
{
Thickening_vector()
: alpha_minus(FT(0)), alpha_plus(FT(0)) {}
Thickening_vector(Vector const& v, FT am, FT ap)
: vec(v), alpha_minus(am), alpha_plus(ap) {}
Vector vec;
FT alpha_minus;
FT alpha_plus;
};
typedef std::vector<Thickening_vector> Thickening_vectors;
Thickening_vectors m_thickening_vectors;
std::size_t num_thickening_vectors() const
{
return m_thickening_vectors.size();
}
Thickening_vectors const& thickening_vectors() const
{
return m_thickening_vectors;
}
void add_thickening_vector(
Vector const& vec, FT alpha_minus = FT(0), FT alpha_plus = FT(0))
{
m_thickening_vectors.push_back(
Thickening_vector(vec, alpha_minus, alpha_plus));
}
void update_alpha_values_of_thickening_vectors(
Vector const& vec, Kernel const& k)
{
typename Kernel::Scalar_product_d k_scalar_pdct =
k.scalar_product_d_object();
for (Thickening_vectors::iterator it_v = m_thickening_vectors.begin(),
it_v_end = m_thickening_vectors.end() ;
it_v != it_v_end ; ++it_v)
{
const FT MARGIN_RATIO = 1.001; // CJTODO TEMP
FT alpha_i = k_scalar_pdct(it_v->vec, vec);
if (alpha_i * MARGIN_RATIO > it_v->alpha_plus)
{
#ifdef CGAL_TC_VERY_VERBOSE
std::cerr << "OLD alpha+ = " << it_v->alpha_plus << std::endl;
#endif
it_v->alpha_plus = alpha_i * MARGIN_RATIO;
#ifdef CGAL_TC_VERY_VERBOSE
std::cerr << "NEW alpha+ = " << it_v->alpha_plus << std::endl;
std::cerr << "NOT MODIFIED alpha- = " << it_v->alpha_minus << std::endl;
#endif
}
else if (alpha_i * MARGIN_RATIO < it_v->alpha_minus)
{
#ifdef CGAL_TC_VERY_VERBOSE
std::cerr << "OLD alpha- = " << it_v->alpha_minus << std::endl;
#endif
it_v->alpha_minus = alpha_i * MARGIN_RATIO;
#ifdef CGAL_TC_VERY_VERBOSE
std::cerr << "NEW alpha- = " << it_v->alpha_minus << std::endl;
std::cerr << "NOT MODIFIED alpha+ = " << it_v->alpha_plus << std::endl;
#endif
}
}
}
FT alpha_minus(std::size_t i) const
{
return m_thickening_vectors[i].alpha_minus;
}
FT alpha_plus(std::size_t i) const
{
return m_thickening_vectors[i].alpha_plus;
}
// Returns 0 if no thickening vectors
FT max_absolute_alpha() const
{
FT max = FT(0);
for (Thickening_vectors::const_iterator
it_v = m_thickening_vectors.begin(),
it_v_end = m_thickening_vectors.end() ;
it_v != it_v_end ;
++it_v)
{
if (it_v->alpha_plus > max)
max = it_v->alpha_plus;
if (-it_v->alpha_minus > max)
max = -it_v->alpha_minus;
}
return max;
}
int dimension() const
{
return static_cast<int>(m_vectors.size() + m_thickening_vectors.size());
}
#else
int dimension() const
{
return static_cast<int>(m_vectors.size());
}
#endif
};
// Using Gram-Schmidt
// * If the resulting vector after G-S algorithm is below "sqlen_threshold",
// the vector considered linearly dependend to the existing vectors
// and is not added to the basis
// * Returns true if the vector was added to the basis
template <typename K>
bool add_vector_to_orthonormal_basis(
Basis<K> & basis, typename K::Vector_d const& v, K const& k,
typename K::FT sqlen_threshold = typename K::FT(1e-13)
#ifdef CGAL_ALPHA_TC
, bool add_to_thickening_vectors = false
#endif
)
{
typedef Basis<K> Basis;
typedef typename K::FT FT;
typedef typename K::Vector_d Vector;
// Kernel functors
typename K::Scaled_vector_d scaled_vec = k.scaled_vector_d_object();
typename K::Scalar_product_d scalar_pdct = k.scalar_product_d_object();
typename K::Difference_of_vectors_d diff_vec = k.difference_of_vectors_d_object();
Vector u = v;
for (int j = 0 ; j < basis.size() ; ++j)
{
Vector const& ej = basis[j];
Vector u_proj = scaled_vec(ej, scalar_pdct(u, ej) / scalar_pdct(ej, ej));
u = diff_vec(u, u_proj);
}
for (int j = 0 ; j < basis.num_thickening_vectors() ; ++j)
{
Vector const& ej = basis.thickening_vectors()[j].vec;
Vector u_proj = scaled_vec(ej, scalar_pdct(u, ej) / scalar_pdct(ej, ej));
u = diff_vec(u, u_proj);
}
FT sqlen_new_v = k.squared_length_d_object()(u);
bool add_it = (sqlen_new_v > sqlen_threshold);
if (add_it)
{
Vector new_v = scaled_vec(u, FT(1)/CGAL::sqrt(sqlen_new_v));
// If new_v is small, run the Gram-Schmidt once more to
// re-orthogonalize it
if (sqlen_new_v < 0.01)
{
for (int j = 0 ; j < basis.size() ; ++j)
{
Vector const& ej = basis[j];
Vector new_v_proj = scaled_vec(
ej, scalar_pdct(new_v, ej) / scalar_pdct(ej, ej));
new_v = diff_vec(new_v, new_v_proj);
}
for (int j = 0 ; j < basis.num_thickening_vectors() ; ++j)
{
Vector const& ej = basis.thickening_vectors()[j].vec;
Vector new_v_proj = scaled_vec(
ej, scalar_pdct(new_v, ej) / scalar_pdct(ej, ej));
new_v = diff_vec(new_v, new_v_proj);
}
sqlen_new_v = k.squared_length_d_object()(new_v);
new_v = scaled_vec(new_v, FT(1)/CGAL::sqrt(sqlen_new_v));
}
#ifdef CGAL_ALPHA_TC
if (add_to_thickening_vectors)
basis.add_thickening_vector(new_v);
else
#endif
basis.push_back(new_v);
}
return add_it;
}
template<
typename Kernel, typename Tangent_space_basis,
typename OutputIteratorPoints, typename OutputIteratorTS>
bool load_points_from_file(
const std::string &filename,
OutputIteratorPoints points,
OutputIteratorTS tangent_spaces,
std::size_t only_first_n_points = std::numeric_limits<std::size_t>::max())
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::Vector_d Vector;
std::ifstream in(filename);
if (!in.is_open())
{
std::cerr << "Could not open '" << filename << "'" << std::endl;
return false;
}
bool contains_tangent_spaces =
(filename.substr(filename.size() - 3) == "pwt");
Kernel k;
Point p;
int num_ppints;
in >> num_ppints;
std::size_t i = 0;
while (i < only_first_n_points && in >> p)
{
*points++ = p;
if (contains_tangent_spaces)
{
Tangent_space_basis tsb(i);
for (int d = 0 ; d < 2 ; ++d) // CJTODO : pas toujours "2"
{
Vector v;
in >> v;
tsb.push_back(CGAL::Tangential_complex_::normalize_vector(v, k));
}
*tangent_spaces++ = tsb;
}
++i;
}
#ifdef CGAL_TC_VERBOSE
std::cerr << "'" << filename << "' loaded." << std::endl;
#endif
return true;
}
// 1st line: number of points
// Then one point per line
template <typename Kernel, typename Point_range>
std::ostream &export_point_set(
Kernel const& k,
Point_range const& points,
std::ostream & os,
const char *coord_separator = " ")
{
// Kernel functors
typename Kernel::Construct_cartesian_const_iterator_d ccci =
k.construct_cartesian_const_iterator_d_object();
os << points.size() << "\n";
typename Point_range::const_iterator it_p = points.begin();
typename Point_range::const_iterator it_p_end = points.end();
// For each point p
for ( ; it_p != it_p_end ; ++it_p)
{
for (auto it = ccci(*it_p) ; it != ccci(*it_p, 0) ; ++it) // CJTODO: C++11
os << CGAL::to_double(*it) << coord_separator;
os << "\n";
}
return os;
}
template <typename K>
Basis<K> compute_gram_schmidt_basis(Basis<K> const& input_basis, K const& k)
{
typedef Basis<K> Basis;
Basis output_basis(input_basis.origin());
// Add vector one by one
typename Basis::const_iterator inb_it = input_basis.begin();
typename Basis::const_iterator inb_it_end = input_basis.end();
for (int i = 0 ; inb_it != inb_it_end ; ++inb_it, ++i)
add_vector_to_orthonormal_basis(output_basis, *inb_it, k);
return output_basis;
}
// Functor to compute stereographic projection from S^3(sphere_radius) to R^3
template <typename K>
class Orthogonal_projection
{
public:
typedef typename K::FT FT;
typedef typename K::Point_d Point;
// center_of_projection will be sent to infinity by the projection
Orthogonal_projection(
std::array<int, 3> const& selected_coords, K const& k)
: m_selected_coords(selected_coords), m_k(k)
{}
Point operator()(Point const& p) const
{
typedef K::FT FT;
typedef K::Point_d Point;
typename K::Construct_point_d constr_pt = m_k.construct_point_d_object();
typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
std::vector<FT> projected_p;
projected_p.reserve(3);
for (int i = 0 ; i < 3 ; ++i)
projected_p.push_back(coord(p, m_selected_coords[i]));
return constr_pt(3, projected_p.begin(), projected_p.end());
}
private:
std::array<int, 3> m_selected_coords; // CJTODO C++11
K const& m_k;
};
// Functor to compute radial projection from R^4 to S^3(sphere_radius)
// The returned point coordinates are expressed with the origin
// at `center_of_sphere`, i.e. the new points are all on the sphere
// S^3{(0,0,0,0), sphere_radius}
template <typename K>
class R4_to_S3_radial_projection
{
public:
typedef typename K::FT FT;
typedef typename K::Point_d Point;
// center_of_projection will be sent to infinity by the projection
R4_to_S3_radial_projection(
FT sphere_radius, Point const& center_of_sphere, K const& k)
: m_sphere_radius(sphere_radius), m_center_of_sphere(center_of_sphere),
m_k(k) {}
Point operator()(Point const& p) const
{
CGAL_assertion(m_k.point_dimension_d_object()(p) == 4);
typedef K::FT FT;
typedef K::Point_d Point;
typedef K::Vector_d Vector;
typename K::Translated_point_d transl = m_k.translated_point_d_object();
typename K::Point_to_vector_d pt_to_vec = m_k.point_to_vector_d_object();
typename K::Vector_to_point_d vec_to_pt = m_k.vector_to_point_d_object();
typename K::Squared_length_d sqlen = m_k.squared_length_d_object();
typename K::Scaled_vector_d scaled_vec = m_k.scaled_vector_d_object();
Point transl_p = transl(p, scaled_vec(pt_to_vec(m_center_of_sphere), FT(-1)));
Vector v = pt_to_vec(transl_p);
v = scaled_vec(v, m_sphere_radius / CGAL::sqrt(sqlen(v)));
return vec_to_pt(v);
}
private:
FT m_sphere_radius;
Point m_center_of_sphere;
K const& m_k;
};
// Functor to compute stereographic projection from S^3(sphere_radius) to R^3
template <typename K>
class S3_to_R3_stereographic_projection
{
public:
typedef typename K::FT FT;
typedef typename K::Point_d Point;
// center_of_projection will be sent to infinity by the projection
S3_to_R3_stereographic_projection(
FT sphere_radius, Point const& center_of_projection, K const& k)
: m_sphere_radius(sphere_radius), m_center_of_proj(center_of_projection),
m_k(k) {}
Point operator()(Point const& p) const
{
CGAL_assertion(m_k.point_dimension_d_object()(p) == 4);
typedef K::FT FT;
typedef K::Point_d Point;
typename K::Construct_point_d constr_pt = m_k.construct_point_d_object();
typename K::Compute_coordinate_d coord = m_k.compute_coordinate_d_object();
std::vector<FT> stereo_proj;
stereo_proj.reserve(3);
FT t = (2 * m_sphere_radius + coord(m_center_of_proj, 3))
/ (m_sphere_radius - (coord(p, 3) - coord(m_center_of_proj, 3)));
for (int i = 0 ; i < 3 ; ++i)
stereo_proj.push_back(coord(m_center_of_proj, i) + t*(coord(p, i) - coord(m_center_of_proj, i)));
return constr_pt(3, stereo_proj.begin(), stereo_proj.end());
}
private:
FT m_sphere_radius;
Point m_center_of_proj;
K const& m_k;
};
// Functor to project R^4 points to R^3
template <typename K>
class R4_to_R3_using_radial_then_stereographic_projection
{
public:
typedef typename K::FT FT;
typedef typename K::Point_d Point;
// sphere_radius and center_of_projection are for the stereographic
// projection
R4_to_R3_using_radial_then_stereographic_projection(
FT sphere_radius, Point const& center_of_sphere,
Point const& center_of_projection, K const& k)
: m_R4toS3(sphere_radius, center_of_sphere, k),
m_S3toR3(sphere_radius, center_of_projection, k),
m_k(k) {}
Point operator()(Point const& p) const
{
return m_S3toR3(m_R4toS3(p));
}
private:
R4_to_S3_radial_projection<K> m_R4toS3;
S3_to_R3_stereographic_projection<K> m_S3toR3;
K const& m_k;
};
// CJTODO: use CGAL::Combination_enumerator<int> (cf. Tangential_complex.h)
// Compute all the k-combinations of elements
// Output_iterator::value_type must be std::set<std::size_t> >
template <typename Elements_container, typename Output_iterator>
void combinations(const Elements_container elements, int k,
Output_iterator combinations)
{
std::size_t n = elements.size();
std::vector<bool> booleans(n, false);
std::fill(booleans.begin() + n - k, booleans.end(), true);
do
{
std::set<std::size_t> combination;
typename Elements_container::const_iterator it_elt = elements.begin();
for (std::size_t i = 0 ; i < n ; ++i, ++it_elt)
{
if (booleans[i])
combination.insert(*it_elt);
}
*combinations++ = combination;
} while (std::next_permutation(booleans.begin(), booleans.end()));
}
} // namespace Tangential_complex_
} //namespace CGAL
#endif // CGAL_TC_UTILITIES_H

View File

@ -0,0 +1,2 @@
INRIA Sophia-Antipolis (France)

View File

@ -0,0 +1,3 @@
Tangential complex
This CGAL component provides an implementation of the tangential complex.

View File

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

View File

@ -0,0 +1 @@
Clément Jamin <clement.jamin.pro@gmail.com>

View File

@ -0,0 +1,81 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.
project( Tangential_complex_test )
cmake_minimum_required(VERSION 2.6.2)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_GREATER 2.6)
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_GREATER 2.8.3)
cmake_policy(VERSION 2.8.4)
else()
cmake_policy(VERSION 2.6)
endif()
endif()
# Creates a new CMake option, turned ON by default
option(ACTIVATE_MSVC_PRECOMPILED_HEADERS
"Activate precompiled headers in MSVC"
OFF)
# Macro to add precompiled headers for MSVC
# This function does two things:
# 1. Enable precompiled headers on each file which is listed in "SourcesVar".
# 2. Add the content of "PrecompiledSource" (e.g. "StdAfx.cpp") to "SourcesVar".
MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar)
IF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS)
GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE)
SET(Sources ${${SourcesVar}})
SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource}
PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\"")
SET_SOURCE_FILES_PROPERTIES(${Sources}
PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeader}\"")
# Add precompiled header to SourcesVar
LIST(APPEND ${SourcesVar} ${PrecompiledSource})
ENDIF(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS)
ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER)
# The compiler might need more memory because of precompiled headers
if(MSVC AND ACTIVATE_MSVC_PRECOMPILED_HEADERS AND NOT(MSVC_VERSION LESS 1310))
set(CGAL_C_FLAGS "${CGAL_C_FLAGS} /Zm1000")
set(CGAL_CXX_FLAGS "${CGAL_CXX_FLAGS} /Zm1000")
endif()
find_package(CGAL QUIET COMPONENTS Core )
if ( CGAL_FOUND )
include( ${CGAL_USE_FILE} )
find_package( TBB QUIET )
if( TBB_FOUND )
include(${TBB_USE_FILE})
list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES})
endif()
include( CGAL_CreateSingleSourceCGALProgram )
find_package(Eigen3 3.1.0)
if (EIGEN3_FOUND)
include( ${EIGEN3_USE_FILE} )
include_directories (BEFORE "../../include")
include_directories (BEFORE "include")
include_directories(../../../Anisotropic_mesh_TC/include)
set (SOURCE_FILES "test_tangential_complex.cpp")
ADD_MSVC_PRECOMPILED_HEADER("StdAfx.h" "StdAfx.cpp" SOURCE_FILES)
create_single_source_cgal_program( ${SOURCE_FILES} )
create_single_source_cgal_program( "aniso_TC.cpp" )
create_single_source_cgal_program( "test_utilities.cpp" )
else()
message(STATUS "NOTICE: Some of the executables in this directory need Eigen 3.1 (or greater) and will not be compiled.")
endif()
else()
message(STATUS "This program requires the CGAL library, and will not be compiled.")
endif()

View File

@ -0,0 +1,2 @@
// Build the precompiled headers.
#include "StdAfx.h"

View File

@ -0,0 +1,14 @@
#ifndef STDAFX_H
#define STDAFX_H
// CGAL
#include <CGAL/Tangential_complex/config.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Regular_triangulation_euclidean_traits.h>
#include <CGAL/Regular_triangulation.h>
#include <CGAL/Delaunay_triangulation.h>
#include <CGAL/Tangential_complex/utilities.h>
#include <CGAL/Tangential_complex/Point_cloud.h>
#include <CGAL/Combination_enumerator.h>
#endif //STDAFX_H

View File

@ -0,0 +1,297 @@
#include <CGAL/assertions_behaviour.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Tangential_complex.h>
#include <CGAL/Random.h>
#include "../../test/Tangential_complex/testing_utilities.h"
#include <CGAL/Metric_field.h> // Anisotropic metrics
#include <Metric_field/Euclidean_metric_field.h>
#include <Metric_field/Custom_metric_field.h>
#include <cstdlib>
#include <fstream>
#include <math.h>
const int k = 2; // intrinsic
const int d = 5; // ambiant
typedef CGAL::Epick_d< CGAL::Dimension_tag<k> > Kk;
typedef CGAL::Epick_d< CGAL::Dimension_tag<d> > Kd;
typedef Kk::FT FT;
typedef Kk::Point_d Point_k;
typedef Kd::Point_d Point_d;
typedef Kd::Weighted_point_d Weighted_point_d;
typedef Kd::Vector_d Vector_d;
typedef CGAL::Tangential_complex<Kd,
CGAL::Dimension_tag<k>,
CGAL::Parallel_tag> TC;
typedef CGAL::Tangential_complex_::Basis<Kd> Basis;
typedef CGAL::Anisotropic_mesh_TC::Metric_base<Kk> Metric;
typedef CGAL::Anisotropic_mesh_TC::Metric_field<Kk> Metric_field;
typedef typename Metric::E_Matrix E_Matrix_k;
typedef typename Metric::E_Vector E_Vector_k;
typedef Eigen::Matrix<FT, d, 1> E_Vector_d;
typedef Eigen::Matrix<FT, d, k> E_Matrix_dk;
typedef CGAL::Anisotropic_mesh_TC::Euclidean_metric_field<Kk> Euclidean_mf;
typedef CGAL::Anisotropic_mesh_TC::Custom_metric_field<Kk> Custom_mf;
void read_points(std::vector<Point_k>& points,
const Kk kerk = Kk())
{
std::ifstream in("../../../../Anisotropic_mesh_2/examples/Anisotropic_mesh_2/bambimboum.mesh");
// std::ifstream in("aniso_regular.mesh");
std::string word;
int useless, nv, dd;
FT x;
in >> word >> useless; //MeshVersionFormatted i
in >> word >> dd; //Dimension d
in >> word >> nv;
assert(dd == Kk::Dimension::value);
for(int i=0; i<nv; ++i)
{
std::vector<FT> ids;
for(int j=0; j<k; ++j)
{
in >> x;
ids.push_back(x);
}
in >> useless;
points.push_back(kerk.construct_point_d_object()(ids.begin(), ids.begin() + k));
if(points.size() == 200)
break;
}
std::cout << points.size() << " points" << std::endl;
}
// compute the corresponding point on the paraboloid (these points will be the
// points at which we compute tangent planes)
Point_d to_Q(const Point_k& p)
{
typename Kk::Compute_coordinate_d k_coord = Kk().compute_coordinate_d_object();
E_Vector_d p_on_Q;
for(int i=0; i<k; ++i)
p_on_Q(i) = k_coord(p, i);
int ind = k;
for(int i=0; i<k; ++i)
for(int j=i; j<k; ++j)
p_on_Q(ind++) = k_coord(p,i) * k_coord(p,j);
return Kd().construct_point_d_object()(d, p_on_Q.data(), p_on_Q.data() + d);
}
// compute the corresponding point on the metric manifold (these points will be
// the seeds of the global power diagram)
Weighted_point_d to_S(const Point_k& p,
const Metric& met,
const Kd kerd = Kd())
{
const E_Matrix_k m = met.get_mat();
E_Vector_k e_p, p_bar;
typename Kk::Compute_coordinate_d k_coord = Kk().compute_coordinate_d_object();
for(int i=0; i<k; ++i)
e_p(i) = k_coord(p, i);
p_bar = m * e_p;
E_Vector_d p_on_S;
for(int i=0; i<k; ++i)
p_on_S(i) = p_bar(i);
int ind = k;
for(int i=0; i<k; ++i)
{
for(int j=i; j<k; ++j)
{
if(j==i)
p_on_S(ind++) = -0.5*m(i,i);
else
p_on_S(ind++) = -m(i,j);
}
}
FT n = p_on_S.norm();
FT w = n * n - e_p.transpose() * p_bar;
return kerd.construct_weighted_point_d_object()
(kerd.construct_point_d_object()(d, p_on_S.data(),p_on_S.data()+d), w);
}
void compute_points_in_ambiant_space(std::vector<Point_k> const & points_k,
Metric_field const * const mf,
std::vector<Point_d>& points_d,
std::vector<FT>& weights,
Kd const kerd = Kd())
{
typename Kd::Point_drop_weight_d k_drop_w = kerd.point_drop_weight_d_object();
typename Kd::Point_weight_d k_point_weight = kerd.point_weight_d_object();
for(std::size_t i=0; i<points_k.size(); ++i)
{
Point_k const & p = points_k[i];
Metric met = mf->compute_metric(p);
Weighted_point_d wp = to_S(p, met, kerd);
points_d.push_back(k_drop_w(wp));
weights.push_back(k_point_weight(wp));
}
}
void compute_and_set_tangent_planes(TC& tc,
const std::vector<Point_k>& points_k,
Kd const kerd = Kd())
{
typedef TC::TS_container TS_container;
typedef TC::OS_container OS_container;
typename Kd::Compute_coordinate_d coord = kerd.compute_coordinate_d_object();
typename Kd::Construct_vector_d constr_vec = kerd.construct_vector_d_object();
TS_container tsc;
OS_container osc;
std::size_t n = tc.number_of_vertices();
CGAL_assertion(n == points_k.size());
for(std::size_t c=0; c<n; ++c)
{
// origin of the basis is the point moved the paraboloid
Point_d origin = to_Q(points_k[c]);
// compute the tsc; the vectors are given by the partial derivatives
// of the parametrization of the paraboloid
Basis ts(origin);
// filling all the vectors at the same time through a (d,k)-matrix
E_Matrix_dk ts_m = E_Matrix_dk::Zero();
// 'first' part: x y z etc. derivates
for(int i=0; i<k; ++i)
for(int j=0; j<k; ++j)
ts_m(i,j) = (i==j);
// 'second' part: x² xy xz y² yz z² etc. derivatives
int pos = k;
for(int i=0; i<k; ++i)
{
for(int j=i; j<k; ++j)
{
if(i == j)
ts_m(pos, i) = 2*coord(origin, i);
else
{
ts_m(pos, i) = coord(origin, j);
ts_m(pos, j) = coord(origin, i);
}
pos++;
}
}
for(int i=0; i<k; ++i)
{
Vector_d v = constr_vec(d, ts_m.col(i).data(), ts_m.col(i).data() + d);
ts.push_back(v);
}
tsc.push_back(CGAL::Tangential_complex_::compute_gram_schmidt_basis(ts, kerd));
#ifdef CGAL_FIXED_ALPHA_TC
// compute the osc
Basis os(origin);
// todo
osc.push_back(CGAL::Tangential_complex_::compute_gram_schmidt_basis(os, kerd));
#endif
}
tc.set_tangent_planes(tsc
#ifdef CGAL_FIXED_ALPHA_TC
, osc
#endif
);
}
// translate the connectivity of the stars back to the original points
void export_complex_in_origin_space(const TC& tc,
const TC::Simplicial_complex& complex,
const std::vector<Point_k>& points_k)
{
std::ofstream out("aniso.off");
std::stringstream output;
std::size_t num_simplices;
typename Kk::Compute_coordinate_d k_coord = Kk().compute_coordinate_d_object();
for(std::size_t i=0; i<points_k.size(); ++i)
{
const Point_k& p = points_k[i];
output << k_coord(p, 0) << " " << k_coord(p, 1) << " 0" << std::endl;
}
tc.export_simplices_to_off(complex, output, num_simplices);
out << "OFF" << std::endl;
out << points_k.size() << " " << num_simplices << " 0" << std::endl;
out << output.str();
}
void make_tc(std::vector<Point_k>& points_k,
Metric_field const * const mf)
{
Kd ker_d;
std::vector<Point_d> points_d;
std::vector<FT> weights;
compute_points_in_ambiant_space(points_k, mf, points_d, weights, ker_d);
TC tc(points_d.begin(), points_d.end(), 0./*sparsity*/, k /*intr dim*/, ker_d);
tc.set_weights(weights);
compute_and_set_tangent_planes(tc, points_k, ker_d);
tc.compute_tangential_complex();
TC::Simplicial_complex complex;
int max_dim = tc.export_TC(complex, false);
complex.display_stats();
{
std::ofstream off_stream("aniso_alpha_complex.off");
tc.export_to_off(complex, off_stream);
}
// Collapse
complex.collapse(max_dim);
{
std::ofstream off_stream("aniso_after_collapse.off");
tc.export_to_off(complex, off_stream);
}
std::size_t num_wrong_dim_simplices, num_wrong_number_of_cofaces;
bool pure_manifold = complex.is_pure_manifold(k, false, 1,
&num_wrong_dim_simplices,
&num_wrong_number_of_cofaces);
complex.display_stats();
export_complex_in_origin_space(tc, complex, points_k);
return;
}
int main()
{
CGAL::default_random = CGAL::Random();
std::vector<Point_k> points_k;
//Custom_mf* mf = new Custom_mf();
Euclidean_mf* mf = new Euclidean_mf();
read_points(points_k);
make_tc(points_k, mf);
return 0;
}

View File

@ -0,0 +1,163 @@
//#undef CGAL_LINKED_WITH_TBB // CJTODO TEMP
// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB
// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/)
#ifdef _DEBUG
# define TBB_USE_THREADING_TOOL
#endif
#include <CGAL/assertions_behaviour.h>
#include <CGAL/Epick_d.h>
#include <CGAL/Tangential_complex.h>
#include <CGAL/Random.h>
#include <CGAL/Mesh_3/Profiling_tools.h>
#include "testing_utilities.h"
#include <fstream>
#include <math.h>
#ifdef CGAL_LINKED_WITH_TBB
# include <tbb/task_scheduler_init.h>
#endif
//=============== Constants =================
const double INPUT_SPARSITY = 0.05;
#ifdef _DEBUG
const int NUM_POINTS = 50;
#else
const int NUM_POINTS = 30000;
#endif
//===========================================
int main()
{
#if defined(CHECK_MEMORY_LEAKS_ON_MSVC) && defined(_MSC_VER)
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
CGAL::set_error_behaviour(CGAL::ABORT);
#ifdef CGAL_LINKED_WITH_TBB
# ifdef _DEBUG
tbb::task_scheduler_init init(1);
# else
tbb::task_scheduler_init init(10);
# endif
#endif
const int INTRINSIC_DIMENSION = 3;
const int AMBIENT_DIMENSION = 9;
typedef CGAL::Epick_d<CGAL::Dimension_tag<AMBIENT_DIMENSION> > Kernel;
typedef Kernel::FT FT;
typedef Kernel::Point_d Point;
typedef CGAL::Tangential_complex<
Kernel, CGAL::Dimension_tag<INTRINSIC_DIMENSION>,
CGAL::Parallel_tag> TC;
int i = 0;
bool stop = false;
//for ( ; !stop ; ++i)
{
Kernel k;
Wall_clock_timer t;
CGAL::default_random = CGAL::Random(i);
std::cerr << "Random seed = " << i << std::endl;
#ifdef CGAL_TC_PROFILING
Wall_clock_timer t_gen;
#endif
/*std::vector<Point> points =
//generate_points_on_circle_2<Kernel>(NUM_POINTS, 3.);
//generate_points_on_moment_curve<Kernel>(NUM_POINTS, AMBIENT_DIMENSION, 0., 1.);
//generate_points_on_plane<Kernel>(NUM_POINTS);
//generate_points_on_sphere_3<Kernel>(NUM_POINTS, 3.0);
//generate_points_on_sphere_d<Kernel>(NUM_POINTS, AMBIENT_DIMENSION, 3.0);
//generate_points_on_klein_bottle_3D<Kernel>(NUM_POINTS, 4., 3.);
generate_points_on_klein_bottle_4D<Kernel>(NUM_POINTS, 4., 3.);
//generate_points_on_klein_bottle_variant_5D<Kernel>(NUM_POINTS, 4., 3.);*/
// LOAD FROM A FILE
std::vector<Point> points;
load_points_from_file<Point>(
"data/SO3_10000.txt", std::back_inserter(points));
#ifdef CGAL_TC_PROFILING
std::cerr << "Point set generated in " << t_gen.elapsed()
<< " seconds." << std::endl;
#endif
std::size_t num_points_before = points.size();
points = sparsify_point_set(
k, points, FT(INPUT_SPARSITY)*FT(INPUT_SPARSITY));
std::cerr << "Number of points before/after sparsification: "
<< num_points_before << " / " << points.size() << std::endl;
TC tc(points.begin(), points.end(), INPUT_SPARSITY, INTRINSIC_DIMENSION, k);
double init_time = t.elapsed(); t.reset();
tc.compute_tangential_complex();
double computation_time = t.elapsed(); t.reset();
if (ambient_dim <= 4)
tc.check_if_all_simplices_are_in_the_ambient_delaunay();
double export_before_time = -1.;
if (INTRINSIC_DIMENSION <= 3)
{
t.reset();
std::stringstream output_filename;
output_filename << "output/test_tc_" << INTRINSIC_DIMENSION
<< "_in_R" << AMBIENT_DIMENSION << "_BEFORE_FIX.off";
std::ofstream off_stream(output_filename.str().c_str());
tc.export_to_off(off_stream, true);
export_before_time = t.elapsed(); t.reset();
}
t.reset();
unsigned int num_fix_steps;
std::size_t initial_num_inconsistent_local_tr;
std::size_t best_num_inconsistent_local_tr;
std::size_t final_num_inconsistent_local_tr;
CGAL::Fix_inconsistencies_status fix_ret =
tc.fix_inconsistencies_using_perturbation(
num_fix_steps, initial_num_inconsistent_local_tr,
best_num_inconsistent_local_tr, final_num_inconsistent_local_tr, 1000.);
double fix_time = t.elapsed(); t.reset();
double export_after_time = -1.;
if (INTRINSIC_DIMENSION <= 3)
{
t.reset();
std::stringstream output_filename;
output_filename << "output/test_tc_" << INTRINSIC_DIMENSION
<< "_in_R" << AMBIENT_DIMENSION << "_AFTER_FIX.off";
std::ofstream off_stream(output_filename.str().c_str());
tc.export_to_off(off_stream, true);
export_after_time = t.elapsed(); t.reset();
}
/*else
tc.number_of_inconsistent_simplices();*/
std::cerr << std::endl
<< "================================================" << std::endl
<< "Number of vertices: " << tc.number_of_vertices() << std::endl
<< "Computation times (seconds): " << std::endl
<< " * Tangential complex: " << init_time + computation_time
<< std::endl
<< " - Init + kd-tree = " << init_time << std::endl
<< " - TC computation = " << computation_time << std::endl
<< " * Export to OFF (before fix): " << export_before_time << std::endl
<< " * Fix inconsistencies: " << fix_time
<< " (" << num_fix_steps << " steps) ==> "
<< (fix_ret == CGAL::TC_FIXED ? "FIXED" : "NOT fixed") << std::endl
<< " * Export to OFF (after fix): " << export_after_time << std::endl
<< "================================================" << std::endl
<< std::endl;
}
return 0;
}

View File

@ -0,0 +1,57 @@
// Without TBB_USE_THREADING_TOOL Intel Inspector XE will report false positives in Intel TBB
// (http://software.intel.com/en-us/articles/compiler-settings-for-threading-error-analysis-in-intel-inspector-xe/)
#ifdef _DEBUG
# define TBB_USE_THREADING_TOOL
#endif
#include <CGAL/Epick_d.h>
#include <CGAL/Tangential_complex/utilities.h>
#include <vector>
using namespace CGAL::Tangential_complex_;
void test_does_voronoi_face_and_alpha_tangent_subspace_intersect()
{
typedef CGAL::Epick_d<CGAL::Dimension_tag<2> > K;
typedef K::Point_d Pt;
typedef K::Vector_d Vec;
std::vector<std::size_t> P;
std::vector<std::size_t> Q;
std::vector<Vec> osb;
K k;
std::vector<Pt> points;
points.push_back(Pt(0.02, -0.03));
points.push_back(Pt(0.005, 2.3));
points.push_back(Pt(4.5, 1.12));
points.push_back(Pt(-3.5, 1.02));
P.push_back(0);
P.push_back(1);
Q.push_back(2);
Q.push_back(3);
osb.push_back(Vec(0.01, 0.995));
assert(does_voronoi_face_and_fixed_alpha_tangent_subspace_intersect(
points, 0, P, Q, osb, 0.0, k) == false);
assert(does_voronoi_face_and_fixed_alpha_tangent_subspace_intersect(
points, 0, P, Q, osb, 0.5, k) == false);
assert(does_voronoi_face_and_fixed_alpha_tangent_subspace_intersect(
points, 0, P, Q, osb, 1.0, k) == false);
assert(does_voronoi_face_and_fixed_alpha_tangent_subspace_intersect(
points, 0, P, Q, osb, 1.5, k) == true);
}
int main()
{
test_does_voronoi_face_and_alpha_tangent_subspace_intersect();
return 0;
}

View File

@ -0,0 +1,846 @@
// Copyright (c) 2014 INRIA Sophia-Antipolis (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$
//
//
// Author(s) : Clement Jamin
//
//******************************************************************************
// File Description :
//
//******************************************************************************
#ifndef CGAL_TC_TEST_TEST_UTILITIES_H
#define CGAL_TC_TEST_TEST_UTILITIES_H
#include <CGAL/Random.h>
#include <CGAL/point_generators_2.h>
#include <CGAL/point_generators_3.h>
#include <CGAL/point_generators_d.h>
#include <CGAL/function_objects.h>
#include <CGAL/Tangential_complex/Point_cloud.h>
#include <CGAL/Tangential_complex/utilities.h>
#include <CGAL/IO/Triangulation_off_ostream.h>
#include <CGAL/iterator.h>
#include <fstream>
#include <iterator>
// Actually, this is very slow because the "m_points_ds->insert"
// cleans the tree, which is thus built at each query_ANN call
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
template <typename Kernel, typename Point_container>
class Point_sparsifier
{
public:
typedef typename Kernel::FT FT;
typedef typename Point_container::value_type Point;
typedef typename CGAL::Tangential_complex_::Point_cloud_data_structure<
Kernel, Point_container> Points_ds;
typedef typename Points_ds::KNS_range KNS_range;
// We can't instantiate m_points_ds right now since it requires that
// points is not empty (which be the case here)
Point_sparsifier(Point_container &points,
FT sparsity = FT(0.05*0.05))
: m_points(points), m_sparsity(sparsity), m_points_ds(NULL)
{}
bool try_to_insert_point(const Point &p)
{
if (m_points_ds == NULL)
{
m_points.push_back(p);
m_points_ds = new Points_ds(m_points);
m_points_ds->insert(0);
return true;
}
else
{
KNS_range kns_range = m_points_ds->query_ANN(p, 1, false);
if (kns_range.begin()->second >= m_sparsity)
{
m_points.push_back(p);
m_points_ds->insert(m_points.size() - 1);
return true;
}
}
return false;
}
private:
Point_container & m_points;
Points_ds * m_points_ds;
FT m_sparsity;
};
#endif
// construct_point: dim 2
template <typename Kernel>
typename Kernel::Point_d construct_point(
const Kernel &k,
typename Kernel::FT x1, typename Kernel::FT x2)
{
typename Kernel::FT tab[2];
tab[0] = x1; tab[1] = x2;
return k.construct_point_d_object()(2, &tab[0], &tab[2]);
}
// construct_point: dim 3
template <typename Kernel>
typename Kernel::Point_d construct_point(
const Kernel &k,
typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3)
{
typename Kernel::FT tab[3];
tab[0] = x1; tab[1] = x2; tab[2] = x3;
return k.construct_point_d_object()(3, &tab[0], &tab[3]);
}
// construct_point: dim 4
template <typename Kernel>
typename Kernel::Point_d construct_point(
const Kernel &k,
typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
typename Kernel::FT x4)
{
typename Kernel::FT tab[4];
tab[0] = x1; tab[1] = x2; tab[2] = x3; tab[3] = x4;
return k.construct_point_d_object()(4, &tab[0], &tab[4]);
}
// construct_point: dim 5
template <typename Kernel>
typename Kernel::Point_d construct_point(
const Kernel &k,
typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
typename Kernel::FT x4, typename Kernel::FT x5)
{
typename Kernel::FT tab[5];
tab[0] = x1; tab[1] = x2; tab[2] = x3; tab[3] = x4; tab[4] = x5;
return k.construct_point_d_object()(5, &tab[0], &tab[5]);
}
// construct_point: dim 6
template <typename Kernel>
typename Kernel::Point_d construct_point(
const Kernel &k,
typename Kernel::FT x1, typename Kernel::FT x2, typename Kernel::FT x3,
typename Kernel::FT x4, typename Kernel::FT x5, typename Kernel::FT x6)
{
typename Kernel::FT tab[6];
tab[0] = x1; tab[1] = x2; tab[2] = x3; tab[3] = x4; tab[4] = x5; tab[5] = x6;
return k.construct_point_d_object()(6, &tab[0], &tab[6]);
}
template <typename Kernel, typename Point_container>
std::vector<typename Point_container::value_type>
sparsify_point_set(
const Kernel &k, Point_container const& input_pts,
typename Kernel::FT min_squared_dist)
{
typedef typename CGAL::Tangential_complex_::Point_cloud_data_structure<
Kernel, Point_container> Points_ds;
typedef typename Points_ds::INS_iterator INS_iterator;
typedef typename Points_ds::INS_range INS_range;
typename Kernel::Squared_distance_d sqdist = k.squared_distance_d_object();
#ifdef CGAL_TC_PROFILING
Wall_clock_timer t;
#endif
// Create the output container
std::vector<typename Point_container::value_type> output;
Points_ds points_ds(input_pts);
std::vector<bool> dropped_points(input_pts.size(), false);
// Parse the input points, and add them if they are not too close to
// the other points
std::size_t pt_idx = 0;
for (typename Point_container::const_iterator it_pt = input_pts.begin() ;
it_pt != input_pts.end();
++it_pt, ++pt_idx)
{
if (dropped_points[pt_idx])
continue;
output.push_back(*it_pt);
INS_range ins_range = points_ds.query_incremental_ANN(*it_pt);
// If another point Q is closer that min_squared_dist, mark Q to be dropped
for (INS_iterator nn_it = ins_range.begin() ;
nn_it != ins_range.end() ;
++nn_it)
{
std::size_t neighbor_point_idx = nn_it->first;
// If the neighbor is too close, we drop the neighbor
if (nn_it->second < min_squared_dist)
{
// N.B.: If neighbor_point_idx < pt_idx,
// dropped_points[neighbor_point_idx] is already true but adding a
// test doesn't make things faster, so why bother?
dropped_points[neighbor_point_idx] = true;
}
else
break;
}
}
#ifdef CGAL_TC_PROFILING
std::cerr << "Point set sparsified in " << t.elapsed()
<< " seconds." << std::endl;
#endif
return output;
}
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_plane(
std::size_t num_points, int intrinsic_dim, int ambient_dim)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
std::vector<FT> pt(ambient_dim, FT(0));
for (int j = 0 ; j < intrinsic_dim ; ++j)
pt[j] = rng.get_double(-5., 5.);
/*for (int j = intrinsic_dim ; j < ambient_dim ; ++j)
pt[j] = rng.get_double(-0.01, 0.01);*/
Point p = k.construct_point_d_object()(ambient_dim, pt.begin(), pt.end());
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_moment_curve(
std::size_t num_points, int dim,
typename Kernel::FT min_x , typename Kernel::FT max_x)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
FT x = rng.get_double(min_x, max_x);
std::vector<FT> coords;
coords.reserve(dim);
for (int p = 1 ; p <= dim ; ++p)
coords.push_back(std::pow(CGAL::to_double(x), p));
Point p = k.construct_point_d_object()(
dim, coords.begin(), coords.end());
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
// R = big radius, r = small radius
template <typename Kernel/*, typename TC_basis*/>
std::vector<typename Kernel::Point_d> generate_points_on_torus_3D(
std::size_t num_points, double R, double r, bool uniform = false
/*, std::vector<TC_basis> *p_tangent_planes = NULL*/)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::Vector_d Vector;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
//typename Kernel::Construct_vector_d cstr_vec = k.construct_vector_d_object();
// if uniform
std::size_t num_lines = (std::size_t)sqrt(num_points);
std::size_t num_cols = num_points/num_lines + 1;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
FT u, v;
if (uniform)
{
std::size_t k1 = i / num_lines;
std::size_t k2 = i % num_lines;
u = 6.2832 * k1 / num_lines;
v = 6.2832 * k2 / num_lines;
}
else
{
u = rng.get_double(0, 6.2832);
v = rng.get_double(0, 6.2832);
}
double tmp = cos(u/2)*sin(v) - sin(u/2)*sin(2.*v);
Point p = construct_point(k,
(R + r * std::cos(u)) * std::cos(v),
(R + r * std::cos(u)) * std::sin(v),
r * std::sin(u));
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
/*if (p_tangent_planes)
{
TC_basis tp(p);
tp.push_back(cstr_vec(
-r * std::cos(v) * std::sin(u),
-r * std::sin(v) * std::sin(u),
r * std::cos(u)));
tp.push_back(cstr_vec(
-(R + r * std::cos(u)) * std::sin(v),
(R + r * std::cos(u)) * std::cos(v),
0));
p_tangent_planes->push_back(
CGAL::Tangential_complex_::compute_gram_schmidt_basis(sp, k));
}*/
}
return points;
}
template <typename Kernel, typename OutputIterator>
static void generate_uniform_points_on_torus_d(
const Kernel &k, int dim, std::size_t num_slices,
OutputIterator out,
double radius_noise_percentage = 0.,
std::vector<typename Kernel::FT> current_point = std::vector<typename Kernel::FT>())
{
static CGAL::Random rng;
if (current_point.size() == 2*dim)
{
*out++ = k.construct_point_d_object()(
static_cast<int>(current_point.size()),
current_point.begin(), current_point.end());
}
else
{
for (std::size_t slice_idx = 0 ; slice_idx < num_slices ; ++slice_idx)
{
double radius_noise_ratio = 1.;
if (radius_noise_percentage > 0.)
{
radius_noise_ratio = rng.get_double(
(100. - radius_noise_percentage)/100.,
(100. + radius_noise_percentage)/100.);
}
std::vector<typename Kernel::FT> cp2 = current_point;
FT alpha = 6.2832 * slice_idx / num_slices;
cp2.push_back(radius_noise_ratio*std::cos(alpha));
cp2.push_back(radius_noise_ratio*std::sin(alpha));
generate_uniform_points_on_torus_d(
k, dim, num_slices, out, radius_noise_percentage, cp2);
}
}
}
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_torus_d(
std::size_t num_points, int dim, bool uniform = false,
double radius_noise_percentage = 0.)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
static CGAL::Random rng;
std::vector<Point> points;
points.reserve(num_points);
if (uniform)
{
std::size_t num_slices = (std::size_t)std::pow(num_points, 1./dim);
generate_uniform_points_on_torus_d(
k, dim, num_slices, std::back_inserter(points), radius_noise_percentage);
}
else
{
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
double radius_noise_ratio = 1.;
if (radius_noise_percentage > 0.)
{
radius_noise_ratio = rng.get_double(
(100. - radius_noise_percentage)/100.,
(100. + radius_noise_percentage)/100.);
}
std::vector<typename Kernel::FT> pt;
pt.reserve(dim*2);
for (int curdim = 0 ; curdim < dim ; ++curdim)
{
FT alpha = rng.get_double(0, 6.2832);
pt.push_back(radius_noise_ratio*std::cos(alpha));
pt.push_back(radius_noise_ratio*std::sin(alpha));
}
Point p = k.construct_point_d_object()(pt.begin(), pt.end());
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
}
return points;
}
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_sphere_d(
std::size_t num_points, int dim, double radius,
double radius_noise_percentage = 0.)
{
typedef typename Kernel::Point_d Point;
Kernel k;
CGAL::Random rng;
CGAL::Random_points_on_sphere_d<Point> generator(dim, radius);
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
Point p = *generator++;
if (radius_noise_percentage > 0.)
{
double radius_noise_ratio = rng.get_double(
(100. - radius_noise_percentage)/100.,
(100. + radius_noise_percentage)/100.);
typename Kernel::Point_to_vector_d k_pt_to_vec =
k.point_to_vector_d_object();
typename Kernel::Vector_to_point_d k_vec_to_pt =
k.vector_to_point_d_object();
typename Kernel::Scaled_vector_d k_scaled_vec =
k.scaled_vector_d_object();
p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio));
}
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_two_spheres_d(
std::size_t num_points, int dim, double radius,
double distance_between_centers, double radius_noise_percentage = 0.)
{
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_d Point;
typedef typename Kernel::Vector_d Vector;
Kernel k;
CGAL::Random rng;
CGAL::Random_points_on_sphere_d<Point> generator(dim, radius);
std::vector<Point> points;
points.reserve(num_points);
std::vector<FT> t(dim, FT(0));
t[0] = distance_between_centers;
Vector c1_to_c2(t.begin(), t.end());
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
Point p = *generator++;
if (radius_noise_percentage > 0.)
{
double radius_noise_ratio = rng.get_double(
(100. - radius_noise_percentage)/100.,
(100. + radius_noise_percentage)/100.);
typename Kernel::Point_to_vector_d k_pt_to_vec =
k.point_to_vector_d_object();
typename Kernel::Vector_to_point_d k_vec_to_pt =
k.vector_to_point_d_object();
typename Kernel::Scaled_vector_d k_scaled_vec =
k.scaled_vector_d_object();
p = k_vec_to_pt(k_scaled_vec(k_pt_to_vec(p), radius_noise_ratio));
}
typename Kernel::Translated_point_d k_transl =
k.translated_point_d_object();
Point p2 = k_transl(p, c1_to_c2);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
if (sparsifier.try_to_insert_point(p2))
++i;
#else
points.push_back(p);
points.push_back(p2);
i += 2;
#endif
}
return points;
}
// Product of a 3-sphere and a circle => d = 3 / D = 5
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_3sphere_and_circle(
std::size_t num_points, double sphere_radius)
{
typedef typename Kernel::FT FT;
typedef typename Kernel::Point_d Point;
typedef typename Kernel::Vector_d Vector;
Kernel k;
CGAL::Random rng;
CGAL::Random_points_on_sphere_d<Point> generator(3, sphere_radius);
std::vector<Point> points;
points.reserve(num_points);
typename Kernel::Translated_point_d k_transl =
k.translated_point_d_object();
typename Kernel::Compute_coordinate_d k_coord =
k.compute_coordinate_d_object();
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
Point p_sphere = *generator++; // First 3 coords
FT alpha = rng.get_double(0, 6.2832);
std::vector<FT> pt(5);
pt[0] = k_coord(p_sphere, 0);
pt[1] = k_coord(p_sphere, 1);
pt[2] = k_coord(p_sphere, 2);
pt[3] = std::cos(alpha);
pt[4] = std::sin(alpha);
Point p(pt.begin(), pt.end());
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
if (sparsifier.try_to_insert_point(p2))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
// a = big radius, b = small radius
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_klein_bottle_3D(
std::size_t num_points, double a, double b, bool uniform = false)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
// if uniform
std::size_t num_lines = (std::size_t)sqrt(num_points);
std::size_t num_cols = num_points/num_lines + 1;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
FT u, v;
if (uniform)
{
std::size_t k1 = i / num_lines;
std::size_t k2 = i % num_lines;
u = 6.2832 * k1 / num_lines;
v = 6.2832 * k2 / num_lines;
}
else
{
u = rng.get_double(0, 6.2832);
v = rng.get_double(0, 6.2832);
}
double tmp = cos(u/2)*sin(v) - sin(u/2)*sin(2.*v);
Point p = construct_point(k,
(a + b*tmp)*cos(u),
(a + b*tmp)*sin(u),
b*(sin(u/2)*sin(v) + cos(u/2)*sin(2.*v)));
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
// a = big radius, b = small radius
template <typename Kernel>
std::vector<typename Kernel::Point_d> generate_points_on_klein_bottle_4D(
std::size_t num_points, double a, double b, double noise = 0., bool uniform = false)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
// if uniform
std::size_t num_lines = (std::size_t)sqrt(num_points);
std::size_t num_cols = num_points/num_lines + 1;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
FT u, v;
if (uniform)
{
std::size_t k1 = i / num_lines;
std::size_t k2 = i % num_lines;
u = 6.2832 * k1 / num_lines;
v = 6.2832 * k2 / num_lines;
}
else
{
u = rng.get_double(0, 6.2832);
v = rng.get_double(0, 6.2832);
}
Point p = construct_point(k,
(a + b*cos(v))*cos(u) + (noise == 0. ? 0. : rng.get_double(0, noise)),
(a + b*cos(v))*sin(u) + (noise == 0. ? 0. : rng.get_double(0, noise)),
b*sin(v)*cos(u/2) + (noise == 0. ? 0. : rng.get_double(0, noise)),
b*sin(v)*sin(u/2) + (noise == 0. ? 0. : rng.get_double(0, noise)));
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
// a = big radius, b = small radius
template <typename Kernel>
std::vector<typename Kernel::Point_d>
generate_points_on_klein_bottle_variant_5D(
std::size_t num_points, double a, double b, bool uniform = false)
{
typedef typename Kernel::Point_d Point;
typedef typename Kernel::FT FT;
Kernel k;
CGAL::Random rng;
// if uniform
std::size_t num_lines = (std::size_t)sqrt(num_points);
std::size_t num_cols = num_points/num_lines + 1;
std::vector<Point> points;
points.reserve(num_points);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
Point_sparsifier<Kernel, std::vector<Point> > sparsifier(points);
#endif
for (std::size_t i = 0 ; i < num_points ; )
{
FT u, v;
if (uniform)
{
std::size_t k1 = i / num_lines;
std::size_t k2 = i % num_lines;
u = 6.2832 * k1 / num_lines;
v = 6.2832 * k2 / num_lines;
}
else
{
u = rng.get_double(0, 6.2832);
v = rng.get_double(0, 6.2832);
}
FT x1 = (a + b*cos(v))*cos(u);
FT x2 = (a + b*cos(v))*sin(u);
FT x3 = b*sin(v)*cos(u/2);
FT x4 = b*sin(v)*sin(u/2);
FT x5 = x1 + x2 + x3 + x4;
Point p = construct_point(k, x1, x2, x3, x4, x5);
#ifdef CGAL_TC_USE_SLOW_BUT_ACCURATE_SPARSIFIER
if (sparsifier.try_to_insert_point(p))
++i;
#else
points.push_back(p);
++i;
#endif
}
return points;
}
template <typename Kernel>
void benchmark_spatial_search(
const std::vector<typename Kernel::Point_d> &points, const Kernel &k,
std::ostream & csv_file)
{
std::cout <<
"****************************************\n"
"***** Benchmarking spatial search ******\n"
"****************************************\n\n";
const std::size_t NUM_QUERIES = 100000;
const std::size_t NUM_NEIGHBORS = 50;
typedef Kernel::FT FT;
typedef Kernel::Point_d Point;
typedef std::vector<Point> Points;
CGAL::Random random_generator;
Wall_clock_timer t;
//****************************** CGAL ***************************************
{
std::cout << "\n=== CGAL ===\n";
typedef CGAL::Tangential_complex_::Point_cloud_data_structure<Kernel, Points>
Points_ds;
typedef Points_ds::KNS_range KNS_range;
typedef Points_ds::KNS_iterator KNS_iterator;
typedef Points_ds::INS_range INS_range;
typedef Points_ds::INS_iterator INS_iterator;
t.reset();
Points_ds points_ds(points);
double init_time = t.elapsed();
std::cout << "Init: " << init_time << std::endl;
t.reset();
for (std::size_t i = 0 ; i < NUM_QUERIES ; ++i)
{
std::size_t pt_idx = random_generator.get_int(0, points.size() - 1);
KNS_range kns_range = points_ds.query_ANN(
points[pt_idx], NUM_NEIGHBORS, true);
}
double queries_time = t.elapsed();
std::cout << NUM_QUERIES << " queries among "
<< points.size() << " points: " << queries_time << std::endl;
csv_file << queries_time << ";";
}
//**************************** nanoflann ************************************
{
std::cout << "\n=== nanoflann ===\n";
typedef CGAL::Tangential_complex_::
Point_cloud_data_structure__nanoflann<Kernel, Points>
Points_ds;
t.reset();
Points_ds points_ds(points, k);
double init_time = t.elapsed();
std::cout << "Init: " << init_time << std::endl;
t.reset();
for (std::size_t i = 0 ; i < NUM_QUERIES ; ++i)
{
std::size_t pt_idx = random_generator.get_int(0, points.size() - 1);
std::size_t neighbors_indices[NUM_NEIGHBORS];
FT neighbors_sq_distances[NUM_NEIGHBORS];
points_ds.query_ANN(
points[pt_idx], NUM_NEIGHBORS, neighbors_indices, neighbors_sq_distances);
}
double queries_time = t.elapsed();
std::cout << NUM_QUERIES << " queries among "
<< points.size() << " points: " << queries_time << std::endl;
csv_file << queries_time << ";";
}
//******************************* ANN ***************************************
{
std::cout << "\n=== ANN ===\n";
typedef CGAL::Tangential_complex_::
Point_cloud_data_structure__ANN<Kernel, Points>
Points_ds;
t.reset();
Points_ds points_ds(points, k);
double init_time = t.elapsed();
std::cout << "Init: " << init_time << std::endl;
t.reset();
for (std::size_t i = 0 ; i < NUM_QUERIES ; ++i)
{
std::size_t pt_idx = random_generator.get_int(0, points.size() - 1);
int neighbors_indices[NUM_NEIGHBORS];
double neighbors_sq_distances[NUM_NEIGHBORS];
points_ds.query_ANN(
points[pt_idx], NUM_NEIGHBORS, neighbors_indices, neighbors_sq_distances);
}
double queries_time = t.elapsed();
std::cout << NUM_QUERIES << " queries among "
<< points.size() << " points: " << queries_time << std::endl;
csv_file << queries_time << "\n";
}
}
#endif // CGAL_MESH_3_TEST_TEST_UTILITIES_H

View File

@ -881,8 +881,8 @@ Delaunay_triangulation<DCTraits, TDS>
int dim = current_dimension();
if (dim == maximal_dimension())
{
for (Finite_full_cell_const_iterator cit = finite_full_cells_begin() ;
cit != finite_full_cells_end() ; ++cit )
for (Finite_full_cell_const_iterator cit = this->finite_full_cells_begin() ;
cit != this->finite_full_cells_end() ; ++cit )
{
Full_cell_const_handle ch = cit.base();
for(int i = 0; i < dim+1 ; ++i )

View File

@ -173,6 +173,32 @@ operator>>(std::istream &is, typename Wrap::Weighted_point_d<K> & wp)
return is;
}
// TODO: test if the stream is binary or text?
template<typename K>
std::istream &
operator>>(std::istream &is, typename Wrap::Vector_d<K> & v)
{
typedef typename Wrap::Vector_d<K> V;
typedef typename K::FT FT;
std::vector<FT> coords;
std::string line;
for (;;)
{
if (!std::getline(is, line))
return is;
if (line != "")
break;
}
std::stringstream line_sstr(line);
FT temp;
while (line_sstr >> temp)
coords.push_back(temp);
v = V(coords.begin(), coords.end());
return is;
}
template < class GT, class TDS >
std::ostream &
export_triangulation_to_off(std::ostream & os,

View File

@ -611,7 +611,8 @@ public:
return incident_faces(v, dim, out, cmp, true);
}
template< typename OutputIterator, typename Comparator = std::less<Vertex_const_handle> >
OutputIterator incident_faces(Vertex_const_handle, const int, OutputIterator, Comparator = Comparator(), bool = false) const;
OutputIterator incident_faces(Vertex_const_handle, const int, OutputIterator,
Comparator = Comparator(), bool = false) const;
#else
template< typename OutputIterator, typename Comparator >
OutputIterator incident_upper_faces(Vertex_const_handle v, const int dim, OutputIterator out, Comparator cmp = Comparator())
@ -664,6 +665,9 @@ Triangulation_data_structure<Dim, Vb, Fcb>
{
// CGAL_expensive_precondition(is_vertex(v));
CGAL_precondition(Vertex_handle() != v);
CGAL_precondition(v->full_cell()->has_vertex(v));
if (!v->full_cell()->has_vertex(v)) // CJTODO TEMP
std::cout << "ERROR: incident_full_cells !v->full_cell()->has_vertex(v). Is the point cloud sparse enough?";
Face f(v->full_cell());
f.set_index(0, v->full_cell()->index(v));
return incident_full_cells(f, out);
@ -713,7 +717,9 @@ Triangulation_data_structure<Dim, Vb, Fcb>
}
}
}
clear_visited_marks(start);
clear_visited_marks(start); // CJTODO: couldn't we use what is in "out"
// to make ot faster? (would require to
// replace the output iterator by a container)
return ft;
}

View File

@ -355,7 +355,7 @@ public:
#endif //CGAL_TRIANGULATION_3_DONT_INSERT_RANGE_OF_POINTS_WITH_INFO
{
#ifdef CGAL_TRIANGULATION_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
size_type n = number_of_vertices();
@ -691,7 +691,7 @@ public:
size_type n = number_of_vertices();
#ifdef CGAL_TRIANGULATION_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
// Parallel

View File

@ -289,7 +289,7 @@ namespace CGAL {
#endif
#ifdef CGAL_TRIANGULATION_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
size_type n = number_of_vertices();
@ -695,7 +695,7 @@ namespace CGAL {
size_type n = number_of_vertices();
#ifdef CGAL_TRIANGULATION_3_PROFILING
WallClockTimer t;
Wall_clock_timer t;
#endif
// Parallel