Update tests; bug fix; method with borders seems ok now.

This commit is contained in:
Guillaume Damiand 2019-11-26 11:35:18 +01:00
parent a5240b4477
commit fa7e93b03b
5 changed files with 126 additions and 127 deletions

View File

@ -13,12 +13,12 @@ int main()
ps.add_facet("a b -a c"); // First facet, giving directly its sequence of edges ps.add_facet("a b -a c"); // First facet, giving directly its sequence of edges
ps.add_facet("d -c e -b"); // Second facet ps.add_facet("d -c e -b"); // Second facet
ps.begin_facet(); // Third facet ps.init_facet(); // Third facet
ps.add_edges_to_facet("f"); // Here, each edge is added one at a time ps.add_edges_to_facet("f"); // Here, each edge is added one at a time
ps.add_edges_to_facet("-d"); ps.add_edges_to_facet("-d");
ps.add_edges_to_facet("-f"); ps.add_edges_to_facet("-f");
ps.add_edges_to_facet("-e"); ps.add_edges_to_facet("-e");
ps.end_facet(); ps.finish_facet();
ps.perforate_facet("f"); ps.perforate_facet("f");

View File

@ -37,13 +37,16 @@
#include <initializer_list> #include <initializer_list>
// A Path_on_surface contains two vectors of equal length n // A Path_on_surface contains two vectors of equal length n
// The first one is a vector of darts called m_path and the second one a vector of booleans called m_flip // The first one is a vector of darts called m_path and the second one a vector
// If n = 0, the path represented by those vectors is the empty path // of booleans called m_flip.
// If n = 0, the path represented by those vectors is the empty path.
// Else, it is the path represented by the n-1 first elements of both vectors, // Else, it is the path represented by the n-1 first elements of both vectors,
// at the one we add the m_path[n-1] dart if m_flip[n-1] is false and the opposite of this dart if m_flip[n-1] is true // at the one we add the m_path[n-1] dart if m_flip[n-1] is false and the
// i.e. if m_flip[i] is true means that the i-th dart m_path[i] has to be flipped // opposite of this dart if m_flip[n-1] is true i.e. if m_flip[i] is true means
// We use flips because sometimes opposite darts doesn't exist on surfaces with boundaries // that the i-th dart m_path[i] has to be flipped.
// But if m_flip[i] is true doesn't necesary mean that m_path[i] is 2-free // We use flips because sometimes opposite darts doesn't exist on surfaces with
// boundaries. But if m_flip[i] is true doesn't necesary mean that
// m_path[i] is 2-free
namespace CGAL { namespace CGAL {
namespace Surface_mesh_topology { namespace Surface_mesh_topology {
@ -722,13 +725,19 @@ public:
/// If this face does not exist (if it is a boundary) then replace the edge /// If this face does not exist (if it is a boundary) then replace the edge
/// by the face on the other side. Problem of complexity when used many times /// by the face on the other side. Problem of complexity when used many times
/// (like in update_path_randomly). /// (like in update_path_randomly).
void push_around_face(std::size_t i, bool update_isclosed=true) bool push_around_face(std::size_t i, bool update_isclosed=true)
{ {
CGAL_assertion(i<length()); CGAL_assertion(i<length());
// It is not possible to push around a perforated face since it changes
// the homotopy of the path.
if (get_map().is_perforated(get_ith_dart(i))) { return false; }
Self p2(get_mesh()); Self p2(get_mesh());
// 1) We add in p2 the part of the path which is pushed.
if (get_ith_flip(i)) if (get_ith_flip(i))
{// in this case the face of the ith dart doesn't exist {
Dart_const_handle dh=get_map().template beta<1>(get_ith_dart(i)); Dart_const_handle dh=get_map().template beta<1>(get_ith_dart(i));
do do
{ {
@ -748,16 +757,20 @@ public:
while(dh!=get_ith_dart(i)); while(dh!=get_ith_dart(i));
} }
// 2) We copy the end of the path.
p2.m_path.reserve(p2.length()+length()-i); p2.m_path.reserve(p2.length()+length()-i);
for (std::size_t j=i+1; j<length(); ++j) for (std::size_t j=i+1; j<length(); ++j)
{ p2.push_back(get_ith_dart(j), get_ith_flip(j), false); } { p2.push_back(get_ith_dart(j), get_ith_flip(j), false); }
// 3) We cut this path to keep the first i darts.
cut(i, false); cut(i, false);
m_path.reserve(length()+p2.length()); m_path.reserve(length()+p2.length());
for (std::size_t j=0; j<p2.length(); ++j) for (std::size_t j=0; j<p2.length(); ++j)
{ push_back(p2[j], p2.get_ith_flip(j), false); } { push_back(p2[j], p2.get_ith_flip(j), false); }
if (update_isclosed) { update_is_closed(); } if (update_isclosed) { update_is_closed(); }
return true;
//CGAL_assertion(is_valid()); //CGAL_assertion(is_valid());
} }
@ -768,8 +781,8 @@ public:
{ {
if (is_empty()) return; if (is_empty()) return;
for (unsigned int i=0; i<nb; ++i) for (unsigned int i=0; i<nb; )
{ push_around_face(random.get_int(0, length()), false); } { if (push_around_face(random.get_int(0, length()), false)) { ++i; } }
if (update_isclosed) { update_is_closed(); } if (update_isclosed) { update_is_closed(); }
} }

View File

@ -28,11 +28,14 @@
#include <cstddef> #include <cstddef>
#include <string> #include <string>
#include <initializer_list> #include <initializer_list>
#include <algorithm>
#include <random>
#include <CGAL/assertions.h> #include <CGAL/assertions.h>
#include <CGAL/memory.h> #include <CGAL/memory.h>
#include <CGAL/Polygonal_schema_min_items.h> #include <CGAL/Polygonal_schema_min_items.h>
#include <CGAL/Combinatorial_map.h> #include <CGAL/Combinatorial_map.h>
#include <CGAL/Generalized_map.h> #include <CGAL/Generalized_map.h>
#include <CGAL/Random.h>
namespace CGAL { namespace CGAL {
namespace Surface_mesh_topology { namespace Surface_mesh_topology {
@ -223,7 +226,7 @@ namespace Surface_mesh_topology {
} }
/// Start a new facet. /// Start a new facet.
void begin_facet() void init_facet()
{ {
if (facet_started) if (facet_started)
{ {
@ -291,9 +294,9 @@ namespace Surface_mesh_topology {
<<" but the previous facet is not yet ended."<<std::endl; <<" but the previous facet is not yet ended."<<std::endl;
return; return;
} }
begin_facet(); init_facet();
add_edges_to_facet(s); add_edges_to_facet(s);
end_facet(); finish_facet();
} }
/// add edges to the current facet, /// add edges to the current facet,
@ -321,13 +324,13 @@ namespace Surface_mesh_topology {
<<" but the previous facet is not yet ended."<<std::endl; <<" but the previous facet is not yet ended."<<std::endl;
return; return;
} }
begin_facet(); init_facet();
add_edges_to_facet(l); add_edges_to_facet(l);
end_facet(); finish_facet();
} }
/// End of the facet. Return the first dart of this facet. /// End of the facet. Return the first dart of this facet.
Dart_handle end_facet() Dart_handle finish_facet()
{ {
if (!facet_started) if (!facet_started)
{ {
@ -429,39 +432,6 @@ namespace Surface_mesh_topology {
std::size_t get_perforated_mark() const std::size_t get_perforated_mark() const
{ return mark_perforated; } { return mark_perforated; }
using Base::is_free;
/// same thing but using a label instead of a dart
template<unsigned int i>
bool is_free(const std::string& s) const
{
auto ite=edge_label_to_dart.find(s);
if (ite==edge_label_to_dart.end())
{// maybe there is no need to put an error message
std::cerr<<"Polygonal_schema ERROR: "
<<"you ask if label "<<s<<" represents a dart border"
<<" but this label does not exist yet."<<std::endl;
return false;
}
return Self::template is_free<i>(ite->second);
}
/// Non templated versions
bool is_free(const std::string& s, unsigned int i) const
{
auto ite=edge_label_to_dart.find(s);
if (ite==edge_label_to_dart.end())
{// maybe there is no need to put an error message
std::cerr<<"Polygonal_schema ERROR: "
<<"you ask if label "<<s<<" represents a dart border"
<<" but this label does not exist yet."<<std::endl;
return false;
}
return is_free(ite->second, i);
}
void display_perforated_darts() const void display_perforated_darts() const
{ {
std::cout<<"labels is_free<2> is_perforated"<<std::endl; std::cout<<"labels is_free<2> is_perforated"<<std::endl;
@ -474,8 +444,8 @@ namespace Surface_mesh_topology {
} }
protected: protected:
// For each edge label, its corresponding dart. Stores both association a -a, to allow // For each edge label, its corresponding dart. Stores both association
// users to start to add either a or -a. // a -a, to allow users to start to add either a or -a.
std::unordered_map<std::string, Dart_handle> edge_label_to_dart; std::unordered_map<std::string, Dart_handle> edge_label_to_dart;
std::size_t mark_perforated; // mark for perforated facets. std::size_t mark_perforated; // mark for perforated facets.
@ -485,6 +455,7 @@ namespace Surface_mesh_topology {
bool facet_started; bool facet_started;
}; };
/// Polygonal schema with combinatorial map.
template <class Items_=Polygonal_schema_min_items, template <class Items_=Polygonal_schema_min_items,
class Alloc_=CGAL_ALLOCATOR(int), class Alloc_=CGAL_ALLOCATOR(int),
class Storage_= Combinatorial_map_storage_1<2, Items_, Alloc_> > class Storage_= Combinatorial_map_storage_1<2, Items_, Alloc_> >
@ -545,6 +516,7 @@ namespace Surface_mesh_topology {
{} {}
}; };
/// Polygonal schema with generalized map.
template <class Items_=Polygonal_schema_min_items, template <class Items_=Polygonal_schema_min_items,
class Alloc_=CGAL_ALLOCATOR(int), class Alloc_=CGAL_ALLOCATOR(int),
class Storage_= Generalized_map_storage_1<2, Items_, Alloc_> > class Storage_= Generalized_map_storage_1<2, Items_, Alloc_> >
@ -605,6 +577,53 @@ namespace Surface_mesh_topology {
{} {}
}; };
/// Generate a random polygonal schema ps.
/// @param nb_labels the number of labels used to generate ps.
/// @param seed the seed used for random
/// @param max_dart_per_face maximal number of darts per face
/// @param closed if true generates a closed polygonal schema.
/// @param percentage_of_perforated percentage of perforated faces. If 0
/// no perforated faces.
template<typename PS>
void generate_random_polygonal_schema(PS& ps, std::size_t nb_labels,
unsigned int seed
=static_cast<unsigned int>(std::time(nullptr)),
std::size_t max_dart_per_face=30,
bool closed=true,
std::size_t percentage_of_perforated=20)
{
CGAL::Random random(seed);
std::vector<std::string> all_labels(nb_labels*2);
for (std::size_t i=0; i<nb_labels; ++i)
{
all_labels[2*i]=std::to_string(static_cast<int>(i)+1);
all_labels[(2*i)+1]=std::to_string(-(static_cast<int>(i)+1));
}
std::shuffle(all_labels.begin(), all_labels.end(),
std::default_random_engine(seed));
std::size_t endlabel=all_labels.size();
if (!closed)
{ endlabel-=(all_labels.size()/10); } // We remove 10% of labels.
for (std::size_t i=0; i<endlabel; )
{
ps.init_facet();
for (std::size_t j=0,
nb=static_cast<std::size_t>
(random.get_int(1, static_cast<int>(max_dart_per_face)));
i<endlabel && j<nb; ++i, ++j)
{ ps.add_edges_to_facet(all_labels[i]); }
typename PS::Dart_handle dh=ps.finish_facet();
if (rand()%101<percentage_of_perforated)
{ ps.perforate_facet(dh); }
}
ps.keep_biggest_connected_component(); // We keep only the biggest cc.
}
} //namespace Surface_mesh_topology } //namespace Surface_mesh_topology
} //namespace CGAL } //namespace CGAL

View File

@ -697,7 +697,8 @@ protected:
if (get_original_map().is_perforated(it)) if (get_original_map().is_perforated(it))
{ get_reduced_map().mark(d1, m_mark_perforated); } { get_reduced_map().mark(d1, m_mark_perforated); }
} }
else if (it<get_original_map().template beta<2>(it)) else if (Original_dart_const_handle(it)<
get_original_map().template beta<2>(it))
{ {
d1=get_reduced_map().create_dart(); d1=get_reduced_map().create_dart();
d2=get_reduced_map().create_dart(); d2=get_reduced_map().create_dart();

View File

@ -2,8 +2,6 @@
#include <CGAL/Path_on_surface.h> #include <CGAL/Path_on_surface.h>
#include <CGAL/Curves_on_surface_topology.h> #include <CGAL/Curves_on_surface_topology.h>
#include <iostream> #include <iostream>
#include <vector>
#include <algorithm>
#include <ctime> #include <ctime>
#include <cstdlib> #include <cstdlib>
@ -14,55 +12,21 @@ using namespace CGAL::Surface_mesh_topology;
static unsigned int starting_seed; static unsigned int starting_seed;
///////////////////////////////////////////////////////////////////////////////
int myrandom (int i) { return std::rand()%i;}
//-----------------------------------------------------------------------------
void generate_random_map(PS& ps, std::size_t nb_labels,
std::size_t max_dart_per_face=30,
bool closed=true,
std::size_t percentage_of_perforated=20) // 0 => no perforated faces
{
std::vector<std::string> all_labels(nb_labels*2);
for (std::size_t i=0; i<nb_labels; ++i)
{
all_labels[2*i]=std::to_string(static_cast<int>(i)+1);
all_labels[(2*i)+1]=std::to_string(-(static_cast<int>(i)+1));
}
std::random_shuffle(all_labels.begin(), all_labels.end(), myrandom);
std::size_t endlabel=all_labels.size();
if (!closed)
{ endlabel-=(all_labels.size()/10); } // We remove 10% of labels.
for (std::size_t i=0; i<endlabel; )
{
ps.begin_facet();
for (std::size_t j=0,
nb=1+(static_cast<std::size_t>(rand())%max_dart_per_face);
i<endlabel && j<nb; ++i, ++j)
{
ps.add_edges_to_facet(all_labels[i]);
}
Dart_handle dh=ps.end_facet();
if (rand()%101<percentage_of_perforated)
{ ps.perforate_facet(dh); }
}
ps.keep_biggest_connected_component();
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
bool test_two_random_paths(const PS& ps, bool test_two_random_paths(const PS& ps,
const Curves_on_surface_topology<PS>& cst, const Curves_on_surface_topology<PS>& cst,
unsigned int nbtests, unsigned int nbtests,
unsigned int lmin=5, unsigned int& seed,
unsigned int lmax=20) int lmin=5,
int lmax=20)
{ {
CGAL_assertion(lmin>0 && lmin<lmax); CGAL_assertion(lmin>0 && lmin<lmax);
CGAL::Random random(starting_seed+nbtests); CGAL::Random random(seed++);
Path_on_surface<PS> p1(ps), p2(ps); Path_on_surface<PS> p1(ps), p2(ps);
internal::generate_random_closed_path(p1, random.get_int(lmin, lmax), random); internal::generate_random_closed_path(p1,
static_cast<std::size_t>
(random.get_int(lmin, lmax)),
random);
p2=p1; p2=p1;
p2.update_path_randomly(100, random); p2.update_path_randomly(100, random);
@ -72,8 +36,8 @@ bool test_two_random_paths(const PS& ps,
if (!cst.are_freely_homotopic(p1, p2)) if (!cst.are_freely_homotopic(p1, p2))
{ {
res=false; res=false;
std::cout<<"ERROR for path number "<<nbtests<<" (seed="<<random.get_seed() std::cout<<std::endl<<"ERROR for path number "<<nbtests<<" (seed="
<<")"<<std::endl; res=false; <<random.get_seed()<<")"<<std::endl;
} }
return res; return res;
@ -82,21 +46,21 @@ bool test_two_random_paths(const PS& ps,
bool run_n_random_paths_tests(const PS& ps, bool run_n_random_paths_tests(const PS& ps,
unsigned int n, unsigned int n,
const Curves_on_surface_topology<PS>& cst, const Curves_on_surface_topology<PS>& cst,
unsigned int lmin=5, unsigned int& seed,
unsigned int lmax=20) int lmin=5,
int lmax=20)
{ {
static std::size_t nbtest=0; static std::size_t nbtest=0;
std::cout<<"Test "<<nbtest++<<std::flush; std::cout<<"***** Test "<<nbtest++<<" "<<std::flush;
ps.display_characteristics(std::cout)<<" ";
bool res=true; bool res=true;
for (unsigned int i=0; i<n; ++i) for (unsigned int i=0; i<n; ++i)
{ {
std::cout<<"."<<std::flush; std::cout<<"."<<std::flush;
if (!test_two_random_paths(ps, cst, i, lmin, lmax)) if (!test_two_random_paths(ps, cst, i, seed, lmin, lmax))
{ res=false; } { res=false; }
} }
if (res) { std::cout<<"OK."; } std::cout<<(res?" OK.":" FAILED.")<<std::endl;
else { std::cout<<"FAILED."; }
std::cout<<std::endl;
return res; return res;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -105,7 +69,8 @@ bool run_n_random_paths_tests(const PS& ps,
std::cout<<"usage: "<<argv[0]<<" [-seed S]"<<std::endl std::cout<<"usage: "<<argv[0]<<" [-seed S]"<<std::endl
<<" Run different homotopy on 2-maps built using polygonal schema." <<" Run different homotopy on 2-maps built using polygonal schema."
<<std::endl <<std::endl
<<" -seed S: uses S as seed of random generator. Otherwise use a different seed at each run (based on time)."<<std::endl <<" -seed S: uses S as seed of random generator. Otherwise use a"
<<" different seed at each run (based on time)."<<std::endl
<<std::endl; <<std::endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -141,27 +106,28 @@ void process_command_line(int argc, char** argv,
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
process_command_line(argc, argv, starting_seed); process_command_line(argc, argv, starting_seed);
std::cout<<"Start tests="<<starting_seed<<"."<<std::endl;
std::cout<<"Start tests (seed="<<starting_seed<<")"<<std::endl; bool closed=true;
srand(starting_seed); std::size_t percent=0;
CGAL::Random r(starting_seed);
PS ps1, ps2, ps3, ps4;
generate_random_map(ps1, 5000, 30, true, 0); // Closed, no perforated faces
generate_random_map(ps2, 5000, 30, true, 15); // Closed, 15% of perforated faces
generate_random_map(ps3, 5000, 30, false, 0); // Open, no perforated faces
generate_random_map(ps4, 5000, 30, false, 15); // Open, 15% of perforated faces
Curves_on_surface_topology<PS> cst1(ps1);
Curves_on_surface_topology<PS> cst2(ps2);
Curves_on_surface_topology<PS> cst3(ps3);
Curves_on_surface_topology<PS> cst4(ps4);
bool res=true; bool res=true;
//res&=run_n_random_paths_tests(ps1, 20, cst1); for (int i=0; i<3; ++i)
//res&=run_n_random_paths_tests(ps2, 20, cst2); {
//res&=run_n_random_paths_tests(ps3, 20, cst3); for (int j=0; j<5; ++j)
res&=run_n_random_paths_tests(ps4, 20, cst4); { // 5 tests for the same "type" of polygonal schema
// (open/closed; with or without perforated)
PS ps;
Curves_on_surface_topology<PS> cst(ps);
generate_random_polygonal_schema(ps, 5000, starting_seed++, 30, closed, percent); // Closed, no perforated faces
res&=run_n_random_paths_tests(ps, 20, cst, starting_seed);
}
switch(i)
{
case 0: closed=true; percent=15; break;
case 1: closed=false; percent=0; break;
case 2: closed=false; percent=15; break;
}
}
if (res) if (res)
{ std::cout<<"test_homotopy_with_polygonal_schema ALL TESTS OK."<<std::endl; } { std::cout<<"test_homotopy_with_polygonal_schema ALL TESTS OK."<<std::endl; }