Operator== linear for path with rle.

This commit is contained in:
Guillaume Damiand 2018-12-03 09:58:57 +01:00
parent fbc1da4278
commit 05bb25687c
2 changed files with 47 additions and 445 deletions

View File

@ -146,6 +146,24 @@ public:
return *this;
}
Self& operator+=(const Self& other)
{
// Be careful to the special case when *this==other
// this is the reason of the iend.
for (List_iterator lit=other.begin(), litend=std::prev(other.end());
lit!=litend; ++lit)
{ m_path.push_back(*lit); }
m_path.push_back(other.back()); // Last element
update_is_closed();
return *this;
}
Self operator+(const Self& other) const
{
Self res=*this;
res+=other;
return res;
}
/// @Return true if this path is equal to other path, identifying dart begin
/// of this path with dart 'itother' in other path.
bool are_same_paths_from(Self& other, List_iterator itother)
@ -164,8 +182,9 @@ public:
}
/// @return true if this path is equal to other path. For closed paths, test
/// all possible starting darts.
bool operator==(Self& other)
/// all possible starting darts. Old quadratic version, new version
/// (operator==) use linear version based on Knuth, Morris, Pratt
bool are_paths_equals(const Self& other)
{
if (is_closed()!=other.is_closed() ||
length()!=other.length() ||
@ -184,6 +203,28 @@ public:
return false;
}
/// @return true if this path is equal to other path. For closed paths, test
/// all possible starting darts.
bool operator==(Self& other)
{
if (is_closed()!=other.is_closed() ||
length()!=other.length() ||
size_of_list()!=other.size_of_list())
return false;
if (!is_closed())
{ return are_same_paths_from(other, other.m_path.begin()); }
Self p2(*this); p2+=p2;
// Now we search if other is a sub-motif of p2 <=> *this==other
return boost::algorithm::knuth_morris_pratt_search(p2.m_path.begin(),
p2.m_path.end(),
other.m_path.begin(),
other.m_path.end()).first
!=p2.m_path.end();
}
bool operator!=(Self& other)
{ return !(operator==(other)); }
@ -332,7 +373,7 @@ public:
m_path.push_back(dh);
if (update_isclosed) { update_is_closed(); }
}
*/
// Update m_is_closed to true iff the path is closed (i.e. the second
// extremity of the last dart of the path is the same vertex than the one
// of the first dart of the path).
@ -347,7 +388,7 @@ public:
else
{ m_is_closed=CGAL::belong_to_same_cell<Map,0>(m_map, m_path[0], pend); }
}
} */
}
/// @return true iff there is a dart after it
bool next_dart_exist(const List_iterator& it) const

View File

@ -906,458 +906,19 @@ namespace CGAL {
return res;
}
std::size_t find_end_of_braket(const Path_on_surface<Map>& path,
std::size_t begin, bool positive) const
{
assert((positive && next_positive_turn(path, begin)==1) ||
(!positive && next_negative_turn(path, begin)==1));
std::size_t end=path.next_index(begin);
if (!path.is_closed() && end>=path.length()-1)
{ return begin; } // begin is the before last dart
while ((positive && next_positive_turn(path, end)==2) ||
(!positive && next_negative_turn(path, end)==2))
{ end=path.next_index(end); }
if ((positive && next_positive_turn(path, end)==1) ||
(!positive && next_negative_turn(path, end)==1)) // We are on the end of a bracket
{ end=path.next_index(end); }
else
{ end=begin; }
return end;
}
void transform_positive_bracket(Path_on_surface<Map>& path,
std::size_t begin, std::size_t end,
Path_on_surface<Map>& new_path) const
{
// There is a special case for (1 2^r). In this case, we need to ignore
// the two darts begin and end
Dart_const_handle d1=(path.next_index(begin)!=end?
m_map.template beta<0>(path.get_ith_dart(begin)):
m_map.template beta<1,2,0>(path.get_ith_dart(end)));
Dart_const_handle d2=(path.next_index(begin)!=end?
m_map.template beta<2,0,2>(path.get_ith_dart(end)):
m_map.template beta<0,0,2>(path.get_ith_dart(begin)));
new_path.push_back(m_map.template beta<2>(d1));
CGAL::extend_straight_negative_until(new_path, d2);
}
void transform_negative_bracket(Path_on_surface<Map>& path,
std::size_t begin, std::size_t end,
Path_on_surface<Map>& new_path) const
{
// There is a special case for (-1 -2^r). In this case, we need to ignore
// the two darts begin and end
Dart_const_handle d1=(path.next_index(begin)!=end?
m_map.template beta<2,1>(path.get_ith_dart(begin)):
m_map.template beta<2,0,2,1>(path.get_ith_dart(end)));
Dart_const_handle d2=(path.next_index(begin)!=end?
m_map.template beta<1>(path.get_ith_dart(end)):
m_map.template beta<2,1,1>(path.get_ith_dart(begin)));
new_path.push_back(d1);
CGAL::extend_straight_positive_until(new_path, d2);
}
void transform_bracket(Path_on_surface<Map>& path,
std::size_t begin, std::size_t end,
Path_on_surface<Map>& new_path,
bool positive) const
{
if (positive)
{ transform_positive_bracket(path, begin, end, new_path); }
else
{ transform_negative_bracket(path, begin, end, new_path); }
}
bool bracket_flattening_one_step(Path_on_surface<Map>& path) const
{
if (path.is_empty()) return false;
#ifndef NDEBUG
bool is_even=path.length()%2;
#endif // NDEBUG
Path_on_surface<Map> new_path(m_map);
bool positive=false;
std::size_t begin, end;
std::size_t lastturn=path.length()-(path.is_closed()?0:1);
for (begin=0; begin<lastturn; ++begin)
{
positive=(next_positive_turn(path, begin)==1);
if (positive || next_negative_turn(path, begin)==1)
{
// we test if begin is the beginning of a bracket
end=find_end_of_braket(path, begin, positive);
if (begin!=end)
{
// std::cout<<"Bracket: ["<<begin<<"; "<<end<<"] "
// <<(positive?"+":"-")<<std::endl;
if (end<begin)
{
if (!path.is_closed())
{ return false; }
path.copy_rest_of_path(end+1, begin, new_path);
}
else if (path.next_index(begin)!=end) // Special case of (1 2^r)
{ path.copy_rest_of_path(0, begin, new_path); }
transform_bracket(path, begin, end, new_path, positive);
if (begin<end && path.next_index(begin)!=end && end<path.length()-1)
{ path.copy_rest_of_path(end+1, path.length(), new_path); }
path.swap(new_path);
assert(path.length()%2==is_even); // bracket flattening is supposed to preserve length parity
return true;
}
}
}
return false;
}
*/
// Simplify the path by removing all brackets
bool bracket_flattening(Path_on_surface<Map>& path) const
{
/* // TODO TEMPO POUR TEST
Path_on_surface_with_rle<Map> prle(path);
prle.remove_brackets();
Path_on_surface<Map> p2(prle); */
bool res=false;
while(bracket_flattening_one_step(path))
{ res=true; }
// assert(p2==path); // FOR TEST
return res;
}
// Simplify the path by removing all brackets
bool bracket_flattening(Path_on_surface_with_rle<Map>& path) const
{
return path.remove_brackets(); // TODO use method with index to compute turns (and add a compilation flat allowing to use either normal version, or version with indices
}
bool remove_spurs_one_step(Path_on_surface<Map>& path) const
{
if (path.is_empty()) return false;
bool res=false;
std::size_t i;
std::size_t lastturn=path.length()-(path.is_closed()?0:1);
for (i=0; !res && i<lastturn; ++i)
{
if (path[i]==m_map.template beta<2>(path.get_next_dart(i)))
{ res=true; }
}
if (!res)
{ return false; }
#ifndef NDEBUG
bool is_even=path.length()%2;
#endif // NDEBUG
--i; // Because we did a ++ before to leave the loop
// Here there is a spur at position i in the path
Path_on_surface<Map> new_path(m_map);
// Special case, the spur is between last dart of the path and the first dart
if (path.is_closed() && i==path.length()-1)
{
path.copy_rest_of_path(1, path.length()-1, new_path); // copy path between 1 and m_path.length()-2
}
else
{ // Otherwise copy darts before the spur
if (i>0)
{ path.copy_rest_of_path(0, i, new_path); } // copy path between 0 and i-1
// and the darts after
if (i+2<path.length())
{ path.copy_rest_of_path(i+2, path.length(), new_path); } // copy path between 0 and m_path.length()-1
}
path.swap(new_path);
assert(path.length()%2==is_even); // spur rremoval is supposed to preserve length parity
return true;
}
// Simplify the path by removing all spurs
// @return true iff at least one spur was removed
bool remove_spurs(Path_on_surface<Map>& path) const
{
// TODO TEMPO POUR TEST
/* Path_on_surface_with_rle<Map> prle(path);
prle.remove_spurs();
Path_on_surface<Map> p2(prle); */
bool res=false;
while(remove_spurs_one_step(path))
{ res=true; }
// assert(p2==path); // TEMPO POUR TESTS
return res;
}
bool remove_spurs(Path_on_surface_with_rle<Map>& path) const
{
return path.remove_spurs();
}
// Simplify the path by removing all possible brackets and spurs
void simplify(Path_on_surface<Map>& path) const
{
bool modified=false;
do
{
modified=bracket_flattening_one_step(path);
if (!modified)
{ modified=remove_spurs_one_step(path); }
}
while(modified);
}
/* bool find_l_shape(const Path_on_surface<Map>& path,
std::size_t begin,
std::size_t& middle,
std::size_t& end) const
{
assert(next_negative_turn(begin)==1 || next_negative_turn(begin)==2);
end=begin+1;
if (end==path.length()-1 && !path.is_closed())
{ return false; } // begin is the before last dart
while (next_negative_turn(end)==2 && end!=begin)
{ end=path.next_index(end); }
if (begin==end)
{ // Case of a path having only 2 turns
return true;
}
if (next_negative_turn(end)==1)
{
middle=end;
end=path.next_index(end);
}
else
{ return false; }
while (next_negative_turn(end)==2 && end!=begin)
{ end=path.next_index(end); }
return true;
}
void push_l_shape(Path_on_surface<Map>& path,
std::size_t begin,
std::size_t middle,
std::size_t end,
Path_on_surface<Map>& new_path,
bool case_seven) const
{
Dart_const_handle d1;
if (!case_seven)
{ d1=m_map.template beta<2,1>(path.get_ith_dart(begin)); }
else
{ d1=m_map.template beta<2,1,2,0>(path.get_ith_dart(begin)); }
new_path.push_back(d1);
if (begin!=middle)
{
if (!case_seven)
{ CGAL::extend_uturn_positive(new_path, 1); }
d1=m_map.template beta<2,1,1>(path.get_ith_dart(middle));
CGAL::extend_straight_positive_until(new_path, d1);
if (path.next_index(middle)!=end)
{ CGAL::extend_uturn_positive(new_path, 3); }
else
{ CGAL::extend_straight_positive(new_path, 1); }
}
if (path.next_index(middle)!=end)
{
d1=m_map.template beta<2,0,2,1>(path.get_ith_dart(end));
CGAL::extend_straight_positive_until(new_path, d1);
if (!case_seven)
{ CGAL::extend_uturn_positive(new_path, 1); }
else
{ CGAL::extend_straight_positive(new_path, 1); }
}
if (begin==middle && path.next_index(middle)==end)
{ // TODO: check if we need to do also something for !case_seven ?
// if (case_seven)
{ CGAL::extend_uturn_positive(new_path, 1); }
// else { assert(false); } // We think (?) that this case is not possible
}
}
void push_l_shape_cycle_2(Path_on_surface<Map>& path) const
{
Dart_const_handle d1=
m_map.template beta<2,1,1>(path.get_ith_dart(0));
path.clear();
path.push_back(d1);
CGAL::extend_straight_positive(path, 1);
CGAL::extend_straight_positive_until(path, d1);
}
bool push_l_shape_2darts(Path_on_surface<Map>& path) const
{
Dart_const_handle d1=NULL;
if (next_negative_turn(path, 0)==1)
d1=m_map.template beta<2,1>(path.get_ith_dart(0));
else if (next_negative_turn(path, 1)==1)
d1=m_map.template beta<2,1>(path.get_ith_dart(1));
else return false;
path.clear();
path.push_back(d1);
CGAL::extend_uturn_positive(path, 1);
//path.push_back(m_map.template beta<1>(d1));
return true;
}
bool right_push_one_step(Path_on_surface<Map>& path) const
{
if (path.is_empty()) { return false; }
if (path.length()==2)
{ return push_l_shape_2darts(path); }
#ifndef NDEBUG
bool is_even=path.length()%2;
#endif // NDEBUG
std::size_t begin, middle, end;
std::size_t lastturn=path.length()-(path.is_closed()?0:1);
std::size_t next_turn;
std::size_t val_x=0; // value of turn before the beginning of a l-shape
bool prev2=false;
for (middle=0; middle<lastturn; ++middle)
{
next_turn=next_negative_turn(path, middle);
if (next_turn==2)
{
if (!prev2)
{
begin=middle; // First 2 of a serie
prev2=true;
if (begin==0 && path.is_closed())
{
begin=path.length()-1;
do
{
next_turn=next_negative_turn(path, begin);
if (next_turn==2) { --begin; }
if (begin==0) // Loop of only -2 turns
{
push_l_shape_cycle_2(path);
return true;
}
}
while(next_turn==2);
begin=path.next_index(begin); // because we stopped on a dart s.t. next_turn!=2
}
// Here begin is the first dart of the path s.t. next_turn==-2
// i.e. the previous turn != -2
}
}
else
{
if (next_turn==1)
{
// Here middle is a real middle; we already know begin (or we know
// that there is no -2 before if !prev2), we only need to compute
// end.
if (!prev2) { begin=middle; } // There is no -2 before this -1
end=path.next_index(middle);
do
{
next_turn=next_negative_turn(path, end);
if (next_turn==2) { end=path.next_index(end); }
assert(end!=middle);
}
while(next_turn==2);
if (path.is_closed() || begin>0)
{ val_x=next_negative_turn(path, path.prev_index(begin)); }
// And here now we can push the path
Path_on_surface<Map> new_path(m_map);
if (end<begin)
{
if (!path.is_closed())
{ return false; }
path.copy_rest_of_path(end+1, begin, new_path);
}
else
{ path.copy_rest_of_path(0, begin, new_path); }
// std::cout<<prev_index(begin)<<" "<<next_index(end)<<std::endl;
bool case_seven=(val_x==3 && path.prev_index(begin)==end);
push_l_shape(path, begin, middle, end, new_path, case_seven);
if (begin<end)
{ path.copy_rest_of_path(end+1, path.length(), new_path); }
path.swap(new_path);
assert(path.length()%2==is_even); // push lshape is supposed to preserve length parity (maybe preserve length ?? TODO check)
return true;
}
prev2=false;
}
}
return false;
}
*/
bool right_push(Path_on_surface<Map>& path) const
{
// TODO TEMPO POUR TEST
/* Path_on_surface_with_rle<Map> prle(path);
prle.right_push();
Path_on_surface<Map> p2(prle); */
bool res=false;
while(right_push_one_step(path))
{ res=true;
/*std::cout<<"PUSH "; display(); display_pos_and_neg_turns();
std::cout<<std::endl; */
}
// assert(p2==path); // TEMPO POUR TEST
return res;
}
bool right_push(Path_on_surface_with_rle<Map>& path) const
{
return path.right_push();
@ -1370,9 +931,9 @@ namespace CGAL {
if (!path.is_closed())
{ return; }
#ifdef COMPUTE_TIME
#ifdef COMPUTE_TIME
CGAL::Timer t; t.start();
#endif // COMPUTE_TIME
#endif // COMPUTE_TIME
#ifdef CGAL_QUADRATIC_CANONIZE
Path_on_surface<Map>& path2=path;