mirror of https://github.com/CGAL/cgal
860 lines
32 KiB
C++
860 lines
32 KiB
C++
// Copyright (c) 2000 Max-Planck-Institute Saarbruecken (Germany).
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of CGAL (www.cgal.org); you may redistribute it under
|
|
// the terms of the Q Public License version 1.0.
|
|
// See the file LICENSE.QPL distributed with CGAL.
|
|
//
|
|
// 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) : Susan Hert <hert@mpi-sb.mpg.de>
|
|
|
|
#ifndef CGAL_GREENE_APPROX_H
|
|
#define CGAL_GREENE_APPROX_H
|
|
|
|
#include<vector>
|
|
#include<algorithm>
|
|
#include<iterator>
|
|
#include<CGAL/Circulator_pair.h>
|
|
#include<CGAL/partition_y_monotone_2.h>
|
|
#include<CGAL/Turn_reverser.h>
|
|
#include<CGAL/IO/Tee_for_output_iterator.h>
|
|
#include<CGAL/partition_assertions.h>
|
|
#include<CGAL/partition_is_valid_2.h>
|
|
#include<CGAL/Partition_traits_2.h>
|
|
#include<CGAL/is_y_monotone_2.h>
|
|
#include<CGAL/is_degenerate_polygon_2.h>
|
|
|
|
// These things should be constant:
|
|
// front is where you add things to a chain
|
|
// top chain shares its back with front (top) of stack
|
|
// bottom chain shares its back with the back (bottom) of the stack
|
|
// bottom of the stack has lower y value than top.
|
|
// ==> chain direction is cw, make ccw polygon from front to back
|
|
// and chain direction is ccw, make ccw polygon from back to front
|
|
|
|
namespace CGAL {
|
|
|
|
template <class BidirectionalCirculator>
|
|
bool is_adjacent_to(BidirectionalCirculator new_point_ref,
|
|
BidirectionalCirculator old_point_ref)
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "is_adjacent_to: new_point " << *new_point_ref
|
|
<< " old_point " << *old_point_ref << std::endl;
|
|
#endif
|
|
// find the old point in original list of points
|
|
if (*new_point_ref == *(++old_point_ref)) return true; // check ccw
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "is_adjacent_to: next point is " << *old_point_ref
|
|
<< std::endl;
|
|
#endif
|
|
old_point_ref--;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "is_adjacent_to: old_point is " << *old_point_ref
|
|
<< std::endl;
|
|
#endif
|
|
if (*new_point_ref == *(--old_point_ref)) return true; // check cw
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "is_adjacent_to: previous points is " << *old_point_ref
|
|
<< std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
|
|
// erases vertices in the range [first, last) (counterclockwise)
|
|
template<class BidirectionalCirculator, class Polygon>
|
|
void erase_vertices(BidirectionalCirculator first,
|
|
BidirectionalCirculator last,
|
|
Polygon& polygon,
|
|
bool& update_required)
|
|
{
|
|
typedef typename Polygon::iterator Vertex_iterator;
|
|
Vertex_iterator it = polygon.begin();
|
|
Vertex_iterator temp_it;
|
|
update_required = false;
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "before erasing polygon is ";
|
|
for (Vertex_iterator v = polygon.begin(); v != polygon.end(); v++)
|
|
{
|
|
std::cout << " " << *v;
|
|
}
|
|
std::cout << std::endl;
|
|
std::cout << "erasing from " << *first << " to " << *last << std::endl;
|
|
#endif
|
|
it = first.current_iterator();
|
|
|
|
CGAL_partition_assertion (it != polygon.end());
|
|
|
|
while ( (it != polygon.end()) && (*it != *last) )
|
|
{
|
|
while ( (it != polygon.end()) && (*it != *last) )
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "erase_vertices: erasing " << *it << std::endl;
|
|
#endif
|
|
temp_it = it;
|
|
// when the beginning vertex of the polygon is deleted, all the
|
|
// circulators for that polygon become invalid and must be updated.
|
|
if (it == polygon.begin())
|
|
update_required = true;
|
|
it++;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
if (it != polygon.end())
|
|
std::cout << "erase_vertices: next vertex is " << *it << std::endl;
|
|
#endif
|
|
polygon.erase(temp_it);
|
|
}
|
|
if (it == polygon.end())
|
|
it = polygon.begin();
|
|
}
|
|
// Yes, both loops here are necessary in case the range of vertices
|
|
// includes the last and first points.
|
|
}
|
|
|
|
|
|
template <class Polygon, class BidirectionalCirculator,
|
|
class OutputIterator, class Traits>
|
|
void visible(Polygon& polygon,
|
|
const BidirectionalCirculator& new_point_ref,
|
|
Circ_pair< BidirectionalCirculator >& stack,
|
|
Circ_pair< BidirectionalCirculator >& bottom_chain,
|
|
Circ_pair< BidirectionalCirculator >& top_chain,
|
|
OutputIterator& result,
|
|
const Traits& traits)
|
|
{
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: stack.back " << *stack.back()
|
|
<< " stack.before_back " << *stack.before_back() <<
|
|
" new_point_ref " << *new_point_ref << std::endl;
|
|
#endif
|
|
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
|
|
if (((bottom_chain.direction() == CLOCKWISE) &&
|
|
right_turn(*stack.back(), *stack.before_back(), *new_point_ref)) ||
|
|
((bottom_chain.direction() == COUNTERCLOCKWISE) &&
|
|
left_turn(*stack.back(), *stack.before_back(), *new_point_ref)))
|
|
{
|
|
typedef typename Traits::Polygon_2 new_Polygon_2;
|
|
new_Polygon_2 new_polygon;
|
|
|
|
bool done = false;
|
|
bool big_angle_at_stack = false;
|
|
bool is_visible = false;
|
|
bool update_required;
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: bottom_chain.front " << *bottom_chain.front()
|
|
<< std::endl;
|
|
#endif
|
|
do
|
|
{
|
|
new_Polygon_2 new_polygon;
|
|
stack.pop_back();
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: stack.back " << *stack.back() << std::endl;
|
|
#endif
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
{
|
|
std::copy(bottom_chain.front(), stack.before_back(),
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.before_front(), stack.back(), polygon,
|
|
update_required);
|
|
}
|
|
else
|
|
{
|
|
std::copy(stack.back(), bottom_chain.after_front(),
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.back(), bottom_chain.front(), polygon,
|
|
update_required);
|
|
}
|
|
if (!is_degenerate_polygon_2(new_polygon.vertices_begin(),
|
|
new_polygon.vertices_end(), traits))
|
|
{
|
|
*result = new_polygon;
|
|
result++;
|
|
}
|
|
bottom_chain.push_back(stack.back());
|
|
if (stack.back() == stack.front()) // form new stack with previous
|
|
{ // point and old stack top
|
|
// (still on stack)
|
|
done = true;
|
|
typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object();
|
|
if (less_yx(*(stack.front()),*bottom_chain.front()))
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: reversing stack and swapping chains "
|
|
<< std::endl;
|
|
#endif
|
|
stack.push_front(bottom_chain.front());
|
|
// reverse stack direction
|
|
stack.change_dir();
|
|
bottom_chain = top_chain; // swap chains
|
|
top_chain.initialize(stack.front());
|
|
top_chain.change_dir();
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: stack is now " << *stack.back()
|
|
<< " " << *stack.front()
|
|
<< " dir " << int(stack.direction())
|
|
<< std::endl;
|
|
std::cout << "visible: bottom_chain is now "
|
|
<< *bottom_chain.back() << " "
|
|
<< *bottom_chain.front()
|
|
<< " dir " << int(bottom_chain.direction())
|
|
<< std::endl;
|
|
std::cout << "visible: top_chain is now "
|
|
<< *top_chain.back() << " " << *top_chain.front()
|
|
<< " dir " << int(top_chain.direction())
|
|
<< std::endl;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
stack.push_back(bottom_chain.front());
|
|
bottom_chain.push_back(bottom_chain.front());
|
|
}
|
|
}
|
|
else // stack size must be >= 2 here
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "visible: stack.before_back "
|
|
<< *stack.before_back() << std::endl;
|
|
#endif
|
|
// angle at stack > 180
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
big_angle_at_stack = right_turn(*bottom_chain.front(),
|
|
*stack.back(),
|
|
*stack.before_back());
|
|
else
|
|
big_angle_at_stack = left_turn(*bottom_chain.front(),
|
|
*stack.back(),
|
|
*stack.before_back());
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
is_visible = !right_turn(*stack.back(), *stack.before_back(),
|
|
*new_point_ref);
|
|
else
|
|
is_visible = !left_turn(*stack.back(), *stack.before_back(),
|
|
*new_point_ref);
|
|
// point can see stack bottom
|
|
}
|
|
} while (!done && !big_angle_at_stack && !is_visible);
|
|
if (big_angle_at_stack) // previous point is placed on bottom of stack
|
|
{
|
|
stack.push_back(bottom_chain.front());
|
|
bottom_chain.push_back(bottom_chain.front());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class Polygon, class BidirectionalCirculator,
|
|
class OutputIterator, class Traits>
|
|
void stack_extend(Polygon& polygon,
|
|
BidirectionalCirculator& point_ref,
|
|
Circ_pair< BidirectionalCirculator >& stack,
|
|
Circ_pair< BidirectionalCirculator >& top_chain,
|
|
OutputIterator& result, const Traits& traits)
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "stack_extend" << std::endl;
|
|
std::cout << "stack_extend: stack.before_front() " << *stack.before_front()
|
|
<< " stack.front " << *stack.front() << " point_ref " << *point_ref
|
|
<< std::endl;
|
|
#endif
|
|
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
if (((stack.direction() == COUNTERCLOCKWISE) &&
|
|
right_turn(*stack.before_front(), *stack.front(), *point_ref)) ||
|
|
((stack.direction() == CLOCKWISE) &&
|
|
left_turn(*stack.before_front(), *stack.front(), *point_ref)))
|
|
{
|
|
// new stack top becomes new first (and only) element of top chain
|
|
stack.push_front(point_ref);
|
|
top_chain.initialize(point_ref);
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "stack_extend: top_chain.front "
|
|
<< *top_chain.front() << std::endl;
|
|
#endif
|
|
}
|
|
else
|
|
change_top_chain(polygon, point_ref, stack, top_chain, result, traits);
|
|
}
|
|
|
|
template <class Polygon, class BidirectionalCirculator,
|
|
class OutputIterator, class Traits>
|
|
void change_top_chain(Polygon& polygon,
|
|
BidirectionalCirculator new_point_ref,
|
|
Circ_pair< BidirectionalCirculator >& stack,
|
|
Circ_pair< BidirectionalCirculator >& top_chain,
|
|
OutputIterator& result, const Traits& traits)
|
|
{
|
|
BidirectionalCirculator next_point_ref = new_point_ref;
|
|
if (top_chain.direction() == COUNTERCLOCKWISE)
|
|
next_point_ref++;
|
|
else
|
|
next_point_ref--;
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_top_chain: top_chain.front " << *top_chain.front()
|
|
<< " new_point_ref " << *new_point_ref
|
|
<< " next_point_ref " << *next_point_ref << std::endl;
|
|
#endif
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
if (((top_chain.direction() == COUNTERCLOCKWISE) &&
|
|
!right_turn(*top_chain.front(), *new_point_ref, *next_point_ref)) ||
|
|
((top_chain.direction() == CLOCKWISE) &&
|
|
!left_turn(*top_chain.front(), *new_point_ref, *next_point_ref)))
|
|
{
|
|
top_chain.push_front(new_point_ref);
|
|
}
|
|
else
|
|
{
|
|
typedef typename Traits::Polygon_2 new_Polygon_2;
|
|
|
|
BidirectionalCirculator old_top_ref;
|
|
bool done = false;
|
|
bool big_angle_at_stack = false;
|
|
bool small_angle_at_point = false;
|
|
bool update_required;
|
|
|
|
// pop off element already on top chain
|
|
old_top_ref = stack.front();
|
|
stack.pop_front();
|
|
|
|
do
|
|
{
|
|
new_Polygon_2 new_polygon;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_top_chain: stack.front "
|
|
<< *stack.front() << std::endl;
|
|
#endif
|
|
if (top_chain.direction() == COUNTERCLOCKWISE)
|
|
{
|
|
std::copy(stack.front(), next_point_ref,
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(old_top_ref, new_point_ref, polygon,
|
|
update_required);
|
|
}
|
|
else
|
|
{
|
|
std::copy(new_point_ref, stack.before_front(),
|
|
std::back_inserter(new_polygon));
|
|
typedef typename Polygon::iterator iterator;
|
|
erase_vertices(top_chain.front(), stack.front(), polygon,
|
|
update_required);
|
|
top_chain.push_front(stack.front());
|
|
}
|
|
if (!is_degenerate_polygon_2(new_polygon.vertices_begin(),
|
|
new_polygon.vertices_end(), traits))
|
|
{
|
|
*result = new_polygon;
|
|
result++;
|
|
}
|
|
if (stack.front() == stack.back()) // the "stack empty" case
|
|
{
|
|
done = true;
|
|
stack.push_front(new_point_ref);
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_top_chain: stack is empty. New stack top is "
|
|
<< *stack.front() << std::endl;
|
|
std::cout << "stack.back is " << *stack.back() << std::endl;
|
|
std::cout << "stack.before_back is " << *stack.before_back()
|
|
<< std::endl;
|
|
#endif
|
|
top_chain.initialize(new_point_ref);
|
|
// top chain should share top of stack
|
|
}
|
|
else // stack size must be >= 2 here
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_top_chain: stack.front "
|
|
<< *stack.front() << std::endl;
|
|
#endif
|
|
if (top_chain.direction() == COUNTERCLOCKWISE)
|
|
big_angle_at_stack = !left_turn(*stack.before_front(),
|
|
*stack.front(), *new_point_ref);
|
|
else
|
|
big_angle_at_stack = !right_turn(*stack.before_front(),
|
|
*stack.front(), *new_point_ref);
|
|
if (top_chain.direction() == COUNTERCLOCKWISE)
|
|
small_angle_at_point = left_turn(*stack.front(), *new_point_ref,
|
|
*next_point_ref);
|
|
else
|
|
small_angle_at_point = right_turn(*stack.front(),
|
|
*new_point_ref,
|
|
*next_point_ref);
|
|
if (!big_angle_at_stack && !small_angle_at_point)
|
|
{
|
|
old_top_ref = stack.front();
|
|
stack.pop_front();
|
|
}
|
|
}
|
|
} while (!done && !big_angle_at_stack && !small_angle_at_point);
|
|
if (big_angle_at_stack) // promote point to stack
|
|
{
|
|
stack.push_front(new_point_ref);
|
|
top_chain.initialize(new_point_ref);
|
|
// top chain shares top of stack
|
|
}
|
|
else if (small_angle_at_point)
|
|
{
|
|
top_chain.push_back(stack.front());
|
|
top_chain.push_front(new_point_ref);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Polygon, class BidirectionalCirculator, class OutputIterator,
|
|
class Traits>
|
|
void change_bottom_chain(Polygon& polygon,
|
|
BidirectionalCirculator new_point_ref,
|
|
Circ_pair< BidirectionalCirculator >& stack,
|
|
Circ_pair< BidirectionalCirculator >& bottom_chain,
|
|
Circ_pair< BidirectionalCirculator >& top_chain,
|
|
OutputIterator& result, const Traits& traits)
|
|
{
|
|
BidirectionalCirculator next_point_ref = new_point_ref;
|
|
if (bottom_chain.direction() == COUNTERCLOCKWISE)
|
|
next_point_ref++;
|
|
else
|
|
next_point_ref--;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_bottom_chain: bottom_chain.front "
|
|
<< *bottom_chain.front() << " new_point_ref " << *new_point_ref
|
|
<< " next_point_ref " << *next_point_ref << std::endl;
|
|
#endif
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Left_turn_2 Left_turn_2;
|
|
Left_turn_2 left_turn = traits.left_turn_2_object();
|
|
Turn_reverser<Point_2, Left_turn_2> right_turn(left_turn);
|
|
if (((bottom_chain.direction() == CLOCKWISE) &&
|
|
!left_turn(*bottom_chain.front(), *new_point_ref,
|
|
*next_point_ref)) ||
|
|
((bottom_chain.direction() == COUNTERCLOCKWISE) &&
|
|
!right_turn(*bottom_chain.front(), *new_point_ref, *next_point_ref)))
|
|
{
|
|
bottom_chain.push_front(new_point_ref);
|
|
}
|
|
else
|
|
{
|
|
typedef typename Traits::Polygon_2 new_Polygon_2;
|
|
|
|
bool done = false;
|
|
bool small_angle_at_point = false;
|
|
bool update_required;
|
|
|
|
do
|
|
{
|
|
new_Polygon_2 new_polygon;
|
|
stack.pop_back(); // remove old bottom of stack
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_bottom_chain: stack.front " << *stack.front()
|
|
<< " stack.back " << *stack.back() << std::endl;
|
|
#endif
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
{
|
|
std::copy(new_point_ref, stack.before_back(),
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.front(), stack.back(), polygon,
|
|
update_required);
|
|
}
|
|
else
|
|
{
|
|
std::copy(stack.back(), next_point_ref,
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.back(), new_point_ref, polygon,
|
|
update_required);
|
|
}
|
|
if (!is_degenerate_polygon_2(new_polygon.vertices_begin(),
|
|
new_polygon.vertices_end(), traits))
|
|
{
|
|
*result = new_polygon;
|
|
result++;
|
|
}
|
|
bottom_chain.initialize(stack.back());
|
|
if (stack.back() == stack.front()) // form new stack with new point
|
|
{ // and old stack top (still on stack)
|
|
done = true;
|
|
typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object();
|
|
if (less_yx(*(stack.front()),*new_point_ref))
|
|
{
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_bottom_chain: reversing stack and "
|
|
<< "swapping chains" << std::endl;
|
|
#endif
|
|
stack.push_front(new_point_ref); // reverse stack direction
|
|
stack.change_dir();
|
|
bottom_chain = top_chain; // swap the chains
|
|
top_chain.initialize(stack.front());
|
|
top_chain.change_dir();
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "change_bottom_chain: stack is now "
|
|
<< *stack.back() << " " << *stack.front()
|
|
<< " dir " << int(stack.direction()) << std::endl;
|
|
std::cout << "change_bottom_chain: bottom_chain is now "
|
|
<< *bottom_chain.back() << " " << *bottom_chain.front()
|
|
<< " dir " << int(bottom_chain.direction()) << std::endl;
|
|
std::cout << "change_bottom_chain: top_chain is now "
|
|
<< *top_chain.back() << " " << *top_chain.front()
|
|
<< " dir " << int(top_chain.direction()) << std::endl;
|
|
#endif
|
|
}
|
|
else
|
|
stack.push_back(new_point_ref);
|
|
}
|
|
else // stack size must be >= 2 here
|
|
{
|
|
// angle at new point is < 180
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
small_angle_at_point = right_turn(*stack.back(), *new_point_ref,
|
|
*next_point_ref);
|
|
else
|
|
small_angle_at_point = left_turn(*stack.back(), *new_point_ref,
|
|
*next_point_ref);
|
|
}
|
|
} while (!done && !small_angle_at_point);
|
|
|
|
if (small_angle_at_point)
|
|
{
|
|
bottom_chain.push_back(stack.back());
|
|
bottom_chain.push_front(new_point_ref);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class Polygon, class BidirectionalCirculator,
|
|
class OutputIterator, class Traits>
|
|
void make_polygons_from_stack(Polygon& polygon,
|
|
const BidirectionalCirculator& high_point_ref,
|
|
Circ_pair< BidirectionalCirculator >& stack,
|
|
Circ_pair< BidirectionalCirculator >& bottom_chain,
|
|
OutputIterator& result, const Traits& traits)
|
|
{
|
|
bool update_required;
|
|
// make polygons by connecting the high point to every point on the stack
|
|
// except the first and the last.
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "make_polygons_from_stack: high_point_ref " << *high_point_ref
|
|
<< " stack.back " << *stack.back()
|
|
<< " stack.before_back " << *stack.before_back() << std::endl;
|
|
#endif
|
|
typedef typename Traits::Polygon_2 new_Polygon_2;
|
|
new_Polygon_2 new_polygon;
|
|
BidirectionalCirculator next_point_ref = high_point_ref;
|
|
if (bottom_chain.direction() == COUNTERCLOCKWISE)
|
|
next_point_ref++;
|
|
|
|
stack.pop_back();
|
|
while (stack.front() != stack.back())
|
|
{
|
|
new_Polygon_2 new_polygon;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "make_polygons_from_stack: stack.back " << *stack.back()
|
|
<< std::endl;
|
|
#endif
|
|
if (bottom_chain.direction() == CLOCKWISE)
|
|
{
|
|
std::copy(high_point_ref, stack.before_back(),
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.front(), stack.back(), polygon,
|
|
update_required);
|
|
bottom_chain.initialize(stack.back());
|
|
}
|
|
else
|
|
{
|
|
std::copy(stack.back(), next_point_ref,
|
|
std::back_inserter(new_polygon));
|
|
erase_vertices(bottom_chain.back(), high_point_ref, polygon,
|
|
update_required);
|
|
bottom_chain.push_back(stack.back());
|
|
}
|
|
if (!is_degenerate_polygon_2(new_polygon.vertices_begin(),
|
|
new_polygon.vertices_end(), traits))
|
|
{
|
|
*result = new_polygon;
|
|
result++;
|
|
}
|
|
stack.pop_back();
|
|
}
|
|
// add remaining points from the top chain if there is more than one
|
|
std::copy(polygon.begin(), polygon.end(), std::back_inserter(new_polygon));
|
|
if (!is_degenerate_polygon_2(new_polygon.vertices_begin(),
|
|
new_polygon.vertices_end(), traits))
|
|
{
|
|
*result = new_polygon;
|
|
result++;
|
|
}
|
|
}
|
|
|
|
template<class BidirectionalCirculator, class Traits>
|
|
void find_smallest_yx(BidirectionalCirculator& first, const Traits& traits)
|
|
{
|
|
BidirectionalCirculator current = first;
|
|
current++;
|
|
// find out which direction to go
|
|
typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object();
|
|
if (less_yx(*current, *first)) // go foward
|
|
{
|
|
do
|
|
{
|
|
first++;
|
|
current++;
|
|
} while (less_yx(*current, *first));
|
|
}
|
|
else
|
|
{
|
|
current = first;
|
|
current--;
|
|
if (less_yx(*current, *first)) // go backward
|
|
{
|
|
do
|
|
{
|
|
first--;
|
|
current--;
|
|
} while (less_yx(*current, *first));
|
|
}
|
|
} // otherwise both previous and next are larger, so no need to move
|
|
}
|
|
|
|
template <class BidirectionalCirculator, class Traits>
|
|
bool second_point_is_next(BidirectionalCirculator first, const Traits& traits)
|
|
{
|
|
BidirectionalCirculator next = first;
|
|
next++;
|
|
BidirectionalCirculator previous = first;
|
|
previous--;
|
|
typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object();
|
|
return less_yx(*next, *previous);
|
|
}
|
|
|
|
template <class BidirectionalCirculator, class Traits>
|
|
BidirectionalCirculator next_vertex(BidirectionalCirculator& ccw_current,
|
|
BidirectionalCirculator& cw_current,
|
|
const Traits& traits)
|
|
{
|
|
BidirectionalCirculator ccw_next = ccw_current;
|
|
ccw_next++;
|
|
BidirectionalCirculator cw_next = cw_current;
|
|
cw_next--;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "next_vertex: ccw_next " << *ccw_next << " cw_next " << *cw_next
|
|
<< std::endl;
|
|
#endif
|
|
|
|
if (ccw_next == cw_next)
|
|
{
|
|
cw_current = cw_next;
|
|
ccw_current = ccw_next;
|
|
return cw_next;
|
|
}
|
|
else
|
|
{
|
|
typename Traits::Less_yx_2 less_yx = traits.less_yx_2_object();
|
|
if (less_yx(*ccw_next,*cw_next))
|
|
{
|
|
ccw_current = ccw_next;
|
|
return ccw_next;
|
|
}
|
|
else
|
|
{
|
|
cw_current = cw_next;
|
|
return cw_next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template <class ForwardIterator, class OutputIterator, class Traits>
|
|
void ga_convex_decomposition(ForwardIterator first, ForwardIterator beyond,
|
|
OutputIterator& result, const Traits& traits)
|
|
{
|
|
if (first == beyond) return;
|
|
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef std::list<Point_2> Vertex_list;
|
|
typedef Circulator_from_container<Vertex_list> Vertex_circulator;
|
|
|
|
Vertex_list polygon(first, beyond);
|
|
|
|
CGAL_partition_precondition(
|
|
orientation_2(polygon.begin(), polygon.end(), traits) == COUNTERCLOCKWISE);
|
|
CGAL_partition_precondition(
|
|
is_y_monotone_2(polygon.begin(), polygon.end(), traits));
|
|
|
|
Vertex_circulator point_ref(&polygon);
|
|
Vertex_circulator circ = point_ref;
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "before find_smallest_yx " << std::endl;
|
|
do
|
|
{
|
|
std::cout << *circ << std::endl;
|
|
} while (++circ != point_ref);
|
|
#endif
|
|
|
|
find_smallest_yx(point_ref, traits);
|
|
|
|
circ = point_ref;
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "after find_smallest_yx " << std::endl;
|
|
do
|
|
{
|
|
std::cout << *circ << std::endl;
|
|
} while (++circ != point_ref);
|
|
#endif
|
|
|
|
Vertex_circulator ccw_chain_ref = point_ref;
|
|
Vertex_circulator cw_chain_ref = point_ref;
|
|
|
|
Circ_pair< Vertex_circulator > stack(point_ref, COUNTERCLOCKWISE);
|
|
Circ_pair< Vertex_circulator > bottom_chain(point_ref, CLOCKWISE);
|
|
Circ_pair< Vertex_circulator > top_chain(point_ref, COUNTERCLOCKWISE);
|
|
|
|
// discover which is the direction to the next point
|
|
if (second_point_is_next(point_ref, traits))
|
|
{
|
|
ccw_chain_ref++;
|
|
stack.push_front(ccw_chain_ref);
|
|
stack.set_direction(COUNTERCLOCKWISE);
|
|
top_chain.initialize(ccw_chain_ref);
|
|
top_chain.set_direction(COUNTERCLOCKWISE);
|
|
bottom_chain.set_direction(CLOCKWISE);
|
|
}
|
|
else
|
|
{
|
|
cw_chain_ref--;
|
|
stack.push_front(cw_chain_ref);
|
|
stack.set_direction(CLOCKWISE);
|
|
top_chain.initialize(cw_chain_ref);
|
|
top_chain.set_direction(CLOCKWISE);
|
|
bottom_chain.set_direction(COUNTERCLOCKWISE);
|
|
}
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "after inserting first two points: ccw_chain_ref "
|
|
<< *ccw_chain_ref << " cw_chain_ref " << *cw_chain_ref
|
|
<< std::endl;
|
|
#endif
|
|
|
|
while (ccw_chain_ref != cw_chain_ref)
|
|
{
|
|
point_ref = next_vertex(ccw_chain_ref, cw_chain_ref, traits);
|
|
|
|
#ifdef CGAL_GREENE_APPROX_DEBUG
|
|
std::cout << "after next_vertex: ccw_chain_ref " << *ccw_chain_ref
|
|
<< " cw_chain_ref " << *cw_chain_ref << std::endl;
|
|
std::cout << "current point: " << *point_ref << std::endl;
|
|
#endif
|
|
if (is_adjacent_to(point_ref, bottom_chain.front()))
|
|
visible(polygon, point_ref, stack, bottom_chain, top_chain,
|
|
result, traits);
|
|
if (ccw_chain_ref == cw_chain_ref)
|
|
{
|
|
make_polygons_from_stack(polygon, point_ref, stack,
|
|
bottom_chain, result, traits);
|
|
return;
|
|
}
|
|
if (is_adjacent_to(point_ref, stack.front()))
|
|
stack_extend(polygon, point_ref, stack, top_chain,
|
|
result, traits);
|
|
else if (is_adjacent_to(point_ref, top_chain.front()))
|
|
change_top_chain(polygon, point_ref, stack, top_chain,
|
|
result, traits);
|
|
else
|
|
change_bottom_chain(polygon, point_ref, stack, bottom_chain,
|
|
top_chain, result, traits);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// should change this so it is like the others in that it adds diagonals
|
|
// to a partition polygon and then calls partition
|
|
// have to be able to go over the vertices again in order to check the
|
|
// result, so they have to be stored somewhere else.
|
|
template <class InputIterator, class OutputIterator, class Traits>
|
|
OutputIterator partition_greene_approx_convex_2(InputIterator first,
|
|
InputIterator beyond,
|
|
OutputIterator result,
|
|
const Traits& traits)
|
|
{
|
|
if (first == beyond) return result;
|
|
|
|
typedef typename Traits::Point_2 Point_2;
|
|
typedef typename Traits::Polygon_2 Polygon_2;
|
|
|
|
#if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \
|
|
defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG)
|
|
OutputIterator res(result);
|
|
#else
|
|
|
|
Tee_for_output_iterator<OutputIterator, Polygon_2> res(result);
|
|
#endif // no postconditions
|
|
|
|
Polygon_2 polygon(first, beyond);
|
|
CGAL_partition_precondition(
|
|
orientation_2(polygon.vertices_begin(), polygon.vertices_end(),
|
|
traits) == COUNTERCLOCKWISE);
|
|
|
|
std::list<Polygon_2> MP_list;
|
|
typename std::list<Polygon_2>::iterator MP_it;
|
|
|
|
y_monotone_partition_2(polygon.vertices_begin(), polygon.vertices_end(),
|
|
std::back_inserter(MP_list), traits);
|
|
|
|
for(MP_it = MP_list.begin(); MP_it != MP_list.end(); MP_it++)
|
|
{
|
|
ga_convex_decomposition((*MP_it).vertices_begin(),
|
|
(*MP_it).vertices_end(), res, traits);
|
|
}
|
|
|
|
CGAL_partition_postcondition(
|
|
convex_partition_is_valid_2(polygon.vertices_begin(),
|
|
polygon.vertices_end(),
|
|
res.output_so_far_begin(),
|
|
res.output_so_far_end(), traits));
|
|
|
|
#if defined(CGAL_PARTITION_NO_POSTCONDITIONS) || \
|
|
defined(CGAL_NO_POSTCONDITIONS) || defined(NDEBUG)
|
|
return res;
|
|
#else
|
|
return res.to_output_iterator();
|
|
#endif // no postconditions
|
|
}
|
|
|
|
template <class InputIterator, class OutputIterator>
|
|
inline
|
|
OutputIterator partition_greene_approx_convex_2(InputIterator first,
|
|
InputIterator beyond,
|
|
OutputIterator result)
|
|
{
|
|
typedef typename std::iterator_traits<InputIterator>::value_type Point_2;
|
|
typedef typename Kernel_traits<Point_2>::Kernel K;
|
|
return partition_greene_approx_convex_2(first, beyond, result,
|
|
Partition_traits_2<K>());
|
|
}
|
|
|
|
}
|
|
|
|
#endif // CGAL_GREENE_APPROX_H
|