dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/extremal_polygon_2.h

755 lines
22 KiB
C
Raw Normal View History

// Copyright (c) 1998-2003 ETH Zurich (Switzerland).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
// You can redistribute it and/or modify it under the terms of the GNU
// General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL$
// $Id$
// SPDX-License-Identifier: GPL-3.0+
//
//
// Author(s) : Michael Hoffmann <hoffmann@inf.ethz.ch>
#ifndef CGAL_EXTREMAL_POLYGON_2_H
#define CGAL_EXTREMAL_POLYGON_2_H 1
#include <CGAL/license/Inscribed_areas.h>
#include <CGAL/Optimisation/assertions.h>
#include <CGAL/monotone_matrix_search.h>
#include <CGAL/Dynamic_matrix.h>
#include <CGAL/Transform_iterator.h>
#include <CGAL/Polygon_2_algorithms.h>
#include <vector>
#include <functional>
#include <algorithm>
#include <CGAL/Extremal_polygon_traits_2.h>
#include <boost/bind.hpp>
#include <boost/bind/make_adaptable.hpp>
namespace CGAL {
//!!! This will eventually be integrated into function_objects.h
template < class Array, class Index, class Element >
struct Index_operator
: public CGAL::cpp98::binary_function< Array, Index, Element >
{
Element&
operator()( Array& a, const Index& i) const
{ return a[i]; }
const Element&
operator()( const Array& a, const Index& i) const
{ return a[i]; }
};
template < class RandomAccessIC_object_,
class RandomAccessIC_value_,
class Operation_ >
// This class describes the kind of matrices used for the
// computation of extremal polygons.
//
// RandomAccessIC_object is a random access iterator or circulator
// with value type Object
// RandomAccessIC_value is a random access iterator or circulator
// with value type Value
// Operation is an adatable binary function:
// Object x Object -> Value
//
// objects can be constructed using the helper function
// extremal_polygon_matrix.
//
class Extremal_polygon_matrix {
public:
typedef RandomAccessIC_object_ RandomAccessIC_object;
typedef RandomAccessIC_value_ RandomAccessIC_value;
typedef Operation_ Operation;
typedef typename
std::iterator_traits< RandomAccessIC_object >::value_type
Object;
typedef typename
std::iterator_traits< RandomAccessIC_value >::value_type
Value;
Extremal_polygon_matrix(
RandomAccessIC_object begin_row,
RandomAccessIC_object end_row,
RandomAccessIC_object begin_col,
RandomAccessIC_object end_col,
RandomAccessIC_value begin_value,
RandomAccessIC_value CGAL_optimisation_precondition_code(end_value),
const Operation& o)
// initialization with two ranges [begin_row, end_row) and
// [begin_col, end_col) of Objects, a range [begin_value, end_value)
// of Values and an Operation o.
//
// an entry (r, c) of this matrix is then defined as:
// begin_value[c] + op( begin_row[r], begin_col[c]).
//
: op( o),
begin_row_( begin_row),
begin_col_( begin_col),
begin_value_( begin_value),
n_rows( static_cast<int>(iterator_distance( begin_row, end_row))),
n_cols( static_cast<int>(iterator_distance( begin_col, end_col)))
{
CGAL_optimisation_precondition(
iterator_distance( begin_value, end_value) == n_cols);
CGAL_optimisation_assertion( n_rows > 0 && n_cols > 0);
}
int
number_of_rows() const
{ return n_rows; }
int
number_of_columns() const
{ return n_cols; }
Value
operator()( int r, int c) const
{
CGAL_optimisation_precondition( r >= 0 && r < n_rows);
CGAL_optimisation_precondition( c >= 0 && c < n_cols);
return begin_value_[c] + op( begin_row_[r], begin_col_[c]);
}
private:
Operation op;
RandomAccessIC_object begin_row_;
RandomAccessIC_object begin_col_;
RandomAccessIC_value begin_value_;
int n_rows;
int n_cols;
};
template < class RandomAccessIC_object,
class RandomAccessIC_value,
class Operation >
inline
Extremal_polygon_matrix< RandomAccessIC_object,
RandomAccessIC_value,
Operation >
extremal_polygon_matrix(
RandomAccessIC_object begin_row,
RandomAccessIC_object end_row,
RandomAccessIC_object begin_col,
RandomAccessIC_object end_col,
RandomAccessIC_value begin_value,
RandomAccessIC_value end_value,
const Operation& o)
{
return Extremal_polygon_matrix< RandomAccessIC_object,
RandomAccessIC_value,
Operation >
( begin_row, end_row,
begin_col, end_col,
begin_value, end_value,
o);
}
template < class RandomAccessIC, class Outputiterator, class Traits >
Outputiterator
CGAL_maximum_inscribed_rooted_k_gon_2(
RandomAccessIC points_begin,
RandomAccessIC points_end,
int k,
typename Traits::FT& max_area,
Outputiterator o,
const Traits& t)
//
// preconditions:
// --------------
// * Traits fulfills the requirements for an extremal polygon
// traits class
// * the range [points_begin, points_end) of size n > 0
// describes the vertices of a convex polygon $P$
// enumerated clock- or counterclockwise
// n > k,
// * k >= t.min_k()
// * value_type of RandomAccessIC is Traits::Point_2
// * OutputIterator accepts Traits::Point_2 as value_type
//
// functionality:
// --------------
// computes maximum (as specified by t) inscribed k-gon $P_k$
// of the polygon $P$,
// that is rooted at points_begin[0],
// sets max_area to its associated value (as specified by t)
// writes the indices (relative to points_begin)
// of $P_k$'s vertices to o and
// returns the past-the-end iterator of that sequence.
{
// check preconditions:
CGAL_optimisation_precondition( k >= t.min_k());
int number_of_points(
static_cast<int>(iterator_distance( points_begin,
points_end)));
CGAL_optimisation_precondition( number_of_points > k);
typedef std::vector< int > Index_cont;
if ( k == t.min_k())
// compute min_k gon:
return t.compute_min_k_gon(
points_begin, points_end, max_area, o);
// current i-gon (i = 2/3...k)
Index_cont gon( k + 1);
// compute initial min_k-gon:
int i( t.min_k());
t.compute_min_k_gon(
points_begin, points_end, max_area, gon.rbegin() + k + 1 - i);
for (;;) {
CGAL_optimisation_assertion( gon[0] == 0);
gon[i] = number_of_points - 1;
if ( ++i >= k)
break;
CGAL_maximum_inscribed_rooted_k_gon_2(
points_begin,
points_end,
0,
gon.begin(),
gon.begin() + i - 1,
gon.begin() + 1,
gon.begin() + i,
max_area,
gon.rbegin() + k + 1 - i,
t);
} // for (;;)
return CGAL_maximum_inscribed_rooted_k_gon_2(
points_begin,
points_end,
0,
gon.begin(),
gon.begin() + k - 1,
gon.begin() + 1,
gon.begin() + k,
max_area,
o,
t);
} // CGAL_maximum_inscribed_rooted_k_gon_2( ... )
template < class RandomAccessIC_point,
class RandomAccessIC_int,
class OutputIterator,
class Traits >
OutputIterator
CGAL_maximum_inscribed_rooted_k_gon_2(
RandomAccessIC_point points_begin,
RandomAccessIC_point points_end,
int root,
RandomAccessIC_int left_c_begin,
RandomAccessIC_int CGAL_optimisation_precondition_code(left_c_end),
RandomAccessIC_int right_c_begin,
RandomAccessIC_int right_c_end,
typename Traits::FT& max_area,
OutputIterator o,
const Traits& t)
//
// preconditions:
// --------------
// * Traits fulfills the requirements for an extremal polygon
// traits class
// * the range [points_begin, points_end) of size n > 0
// describes the vertices of a convex polygon $P$
// enumerated clock- or counterclockwise
// * value_type of RandomAccessIC_point is Traits::Point
// * value_type of RandomAccessIC_int is int
// * OutputIterator accepts int as value type
// * length := right_c_end - right_c_begin == left_c_end - left_c_begin
// >= t.min_k() - 1 (the root is already fixed)
// * [left_c_begin, left_c_end) resp. [right_c_begin, right_c_end)
// describe two subpolygons of $P$ by giving the indices of its
// vertices relative to points_begin and for any 0 <= i < length:
// left_c_begin[i] <= right_c_begin[i]
// * for any 0 <= i < length: o + i must not be contained in
// the range [right_c_begin, right_c_begin + length - i - 2].
// (NOT checked!)
//
// functionality:
// --------------
// computes maximum (as specified by t) inscribed k-gon $P_k$
// of the polygon $P$,
// that is rooted at points_begin[left_c_begin[0]]
// such that for any 0 <= i < length:
// left_c_begin[i] <= vertex i of $P_k$ <= right_c_begin[i],
// sets max_area to its associated value (as specified by t),
// writes the indices (relative to points_begin)
// of $P_k$'s vertices to o and
// returns the past-the-end iterator of that sequence.
{
using std::max_element;
// counter :)
int i;
// compute size of ranges:
int number_of_points = static_cast<int>(iterator_distance( points_begin,
points_end));
int size_of_gon = static_cast<int>(iterator_distance( right_c_begin,
right_c_end));
// check preconditions:
CGAL_optimisation_precondition( number_of_points > t.min_k());
CGAL_optimisation_precondition( size_of_gon >= t.min_k() - 1);
CGAL_optimisation_precondition(
iterator_distance( left_c_begin, left_c_end) ==
iterator_distance( right_c_begin, right_c_end));
CGAL_optimisation_precondition( left_c_begin[0] >= 0);
CGAL_optimisation_precondition( right_c_begin[0] >= 0);
CGAL_optimisation_precondition(
left_c_begin[size_of_gon-1] < number_of_points);
CGAL_optimisation_precondition(
right_c_begin[size_of_gon-1] < number_of_points);
CGAL_optimisation_expensive_precondition_code(
for ( i = 0; i < size_of_gon; ++i) {
CGAL_optimisation_expensive_precondition( left_c_begin[i] >= 0);
CGAL_optimisation_expensive_precondition( right_c_begin[i] >= 0);
CGAL_optimisation_expensive_precondition(
left_c_begin[i] < number_of_points);
CGAL_optimisation_expensive_precondition(
right_c_begin[i] < number_of_points);
CGAL_optimisation_expensive_precondition(
left_c_begin[i] <= right_c_begin[i]);
})
typedef typename Traits::FT FT;
typedef std::vector< FT > FT_cont;
typedef std::vector< int > Index_cont;
typedef typename Traits::Operation Operation;
//!!! static ???
// area container:
FT_cont area( number_of_points);
// last vertex container:
Index_cont last_vertex( number_of_points);
// matrix operation:
Operation op( t.operation( points_begin[root]));
// initialize area and last vertex containers:
for ( i = left_c_begin[0]; i <= right_c_begin[0]; ++i) {
area[i] = t.init( points_begin[i], points_begin[root]);
last_vertex[i] = root;
}
for ( i = 1; i < size_of_gon; ++i) {
monotone_matrix_search(
dynamic_matrix(
extremal_polygon_matrix(
points_begin + left_c_begin[i],
points_begin + right_c_begin[i] + 1,
points_begin + left_c_begin[i-1],
points_begin + right_c_begin[i-1] + 1,
area.begin() + left_c_begin[i-1],
area.begin() + right_c_begin[i-1] + 1,
op)),
last_vertex.begin() + left_c_begin[i]);
// compute new area values and adjust last_vertex values
// (they are relative to left_c_begin[i-1] now)
int j;
for ( j = right_c_begin[i]; j >= left_c_begin[i]; --j) {
last_vertex[j] += left_c_begin[i-1];
area[j] = area[last_vertex[j]] +
op( points_begin[j], points_begin[last_vertex[j]]);
}
} // for ( i = 1; i < size_of_gon; ++i)
// find maximum in last range:
int maxi =
static_cast<int>(iterator_distance(
area.begin(),
max_element( area.begin() + left_c_begin[size_of_gon - 1],
area.begin() + right_c_begin[size_of_gon - 1] + 1)));
// set max_area:
max_area = area[maxi];
// construct gon:
*o++ = maxi;
maxi = last_vertex[maxi];
for ( i = size_of_gon - 1; i > 0; --i) {
// We must not place the "*o++ = maxi" here,
// since o might be the same as left_c_begin + i ...
if ( maxi != right_c_begin[i-1]) {
*o++ = maxi;
maxi = last_vertex[maxi];
}
else {
*o++ = maxi;
maxi = right_c_begin[i-2];
}
} // for ( i = size_of_gon - 1; i > 0; --i)
*o++ = root;
return o;
} // CGAL_maximum_inscribed_rooted_k_gon_2( p, k, result)
template < class RandomAccessIC,
class OutputIterator,
class Traits >
inline
OutputIterator
extremal_polygon_2(
RandomAccessIC points_begin,
RandomAccessIC points_end,
int k,
OutputIterator o,
const Traits& t)
//
// preconditions:
// --------------
// * Traits fulfills the requirements for an extremal polygon
// traits class
// * the range [points_begin, points_end) of size n > 0
// describes the vertices of a convex polygon $P$
// enumerated clock- or counterclockwise
// * k >= t.min_k()
// * value_type of RandomAccessIC is Traits::Point_2
// * OutputIterator accepts Traits::Point_2 as value_type
//
// functionality:
// --------------
// computes maximum (as specified by t) inscribed k-gon $P_k$
// of the polygon $P$,
// writes the indices (relative to points_begin)
// of $P_k$'s vertices to o and
// returns the past-the-end iterator of that sequence.
{
// check preconditions:
CGAL_optimisation_precondition_code(
int number_of_points(
static_cast<int>(iterator_distance( points_begin,
points_end)));)
CGAL_optimisation_precondition( number_of_points >= t.min_k());
CGAL_optimisation_expensive_precondition(
is_convex_2( points_begin, points_end, t));
typedef typename Traits::Point_2 Point_2;
return CGAL_maximum_inscribed_k_gon_2(
points_begin,
points_end,
k,
CGAL::transform_iterator(
o,
boost::make_adaptable<Point_2, int>(boost::bind(Index_operator< RandomAccessIC, int, Point_2 >(),
points_begin, _1))),
t);
}
// backwards compatibility
template < class RandomAccessIC,
class OutputIterator,
class Traits >
inline
OutputIterator
extremal_polygon(
RandomAccessIC points_begin,
RandomAccessIC points_end,
int k,
OutputIterator o,
const Traits& t)
{ return extremal_polygon_2(points_begin, points_end, k, o, t); }
template < class RandomAccessIC,
class OutputIterator,
class Traits >
OutputIterator
CGAL_maximum_inscribed_k_gon_2(
RandomAccessIC points_begin,
RandomAccessIC points_end,
int k,
OutputIterator o,
const Traits& t)
//
// preconditions:
// --------------
// * Traits fulfills the requirements for an extremal polygon
// traits class
// * the range [points_begin, points_end) of size n > 0
// describes the vertices of a convex polygon $P$
// enumerated clock- or counterclockwise
// * k >= t.min_k()
// * value_type of RandomAccessIC is Traits::Point_2
// * OutputIterator accepts Traits::Point_2 as value_type
//
// functionality:
// --------------
// computes maximum (as specified by t) inscribed k-gon $P_k$
// of the polygon $P$,
// writes the indices (relative to points_begin)
// of $P_k$'s vertices to o and
// returns the past-the-end iterator of that sequence.
{
// check preconditions:
CGAL_optimisation_precondition( k >= t.min_k());
int number_of_points(
static_cast<int>(iterator_distance( points_begin,
points_end)));
CGAL_optimisation_precondition( number_of_points > 0);
using std::copy;
typedef typename Traits::FT FT;
typedef std::vector< int > Index_cont;
if ( number_of_points <= k) {
for ( int j( k - 1); j >= 0; --j)
*o++ = (std::min)( j, number_of_points - 1);
return o;
}
// compute k-gon rooted at points_begin[0]
Index_cont P_0( k + 1);
FT area_0;
CGAL_maximum_inscribed_rooted_k_gon_2(
points_begin,
points_end,
k,
area_0,
P_0.rbegin() + 1,
t);
P_0[k] = number_of_points - 1;
CGAL_optimisation_assertion( P_0[0] == 0);
// compute k-gon rooted at points_begin[P_0[1]]
Index_cont P_1( k);
FT area_1;
CGAL_maximum_inscribed_rooted_k_gon_2(
points_begin,
points_end,
P_0[1],
P_0.begin() + 1,
P_0.begin() + k,
P_0.begin() + 2,
P_0.begin() + k + 1,
area_1,
P_1.rbegin(),
t);
CGAL_optimisation_assertion( P_1[0] == P_0[1]);
// start recursive computation:
FT area_r( 0);
Index_cont P_r( k);
if ( P_0[1] - P_0[0] > 1) {
CGAL_maximum_inscribed_k_gon_2(
points_begin,
points_end,
P_0[0] + 1,
P_0[1] - 1,
P_0.begin() + 1,
P_0.begin() + k,
P_0.begin() + 2,
P_0.begin() + k + 1,
k,
area_r,
P_r.rbegin(),
t);
}
if ( area_r > area_0)
if ( area_r > area_1)
// recursive is maximum
copy( P_r.begin(), P_r.end(), o);
else
// P_1 is maximum
copy( P_1.begin(), P_1.end(), o);
else if ( area_0 > area_1)
// P_0 is maximum
copy( P_0.begin(), P_0.begin() + k, o);
else
// P_1 is maximum
copy( P_1.begin(), P_1.end(), o);
return o;
} // CGAL_maximum_inscribed_k_gon_2( ... )
template < class RandomAccessIC_point,
class RandomAccessIC_int,
class OutputIterator,
class Traits >
OutputIterator
CGAL_maximum_inscribed_k_gon_2(
RandomAccessIC_point points_begin,
RandomAccessIC_point points_end,
int left_index,
int right_index,
RandomAccessIC_int left_c_begin,
RandomAccessIC_int left_c_end,
RandomAccessIC_int right_c_begin,
RandomAccessIC_int right_c_end,
int k,
typename Traits::FT& max_area,
OutputIterator o,
const Traits& t)
//
// preconditions:
// --------------
// * Traits fulfills the requirements for an extremal polygon
// traits class
// * the range [points_begin, points_end) of size n > 0
// describes the vertices of a convex polygon $P$
// enumerated clock- or counterclockwise
// * value_type of RandomAccessIC_point is Traits::Point
// * value_type of RandomAccessIC_int is int
// * OutputIterator accepts int as value type
// * 0 <= left_index <= right_index < |points_end - points_begin|
// * |left_c_end - left_c_begin| == |right_c_end - right_c_begin| == k - 1
// * [left_c_begin, left_c_end) resp. [right_c_begin, right_c_end)
// describe two subpolygons $P_l$ resp $P_r$ of $P$ by giving
// the indices of its vertices relative to points_begin and
// for any 0 <= i < k - 1:
// left_c_begin[i] <= right_c_begin[i]
// * k >= t.min_k()
//
// functionality:
// --------------
// computes maximum (as specified by t) inscribed k-gon $P_k$
// of the polygon $P$,
// * that is rooted at one of the vertices [points_begin[left_index],
// points_begin[right_index]] and
// * interleaves with both $P_l$ and $P_r$,
// sets max_area to its associated value (as specified by t),
// writes the indices (relative to points_begin)
// of $P_k$'s vertices to o and
// returns the past-the-end iterator of that sequence.
{
// typedefs
typedef typename Traits::FT FT;
typedef std::vector< int > Index_cont;
using std::copy;
// check preconditions:
CGAL_optimisation_precondition( k >= t.min_k());
CGAL_optimisation_precondition( left_index <= right_index);
CGAL_optimisation_precondition( left_index >= 0);
CGAL_optimisation_precondition( right_index >= 0);
CGAL_optimisation_precondition_code(
int number_of_points(
static_cast<int>(iterator_distance( points_begin,
points_end)));)
CGAL_optimisation_precondition( left_index < number_of_points);
CGAL_optimisation_precondition( right_index < number_of_points);
CGAL_optimisation_precondition(
iterator_distance( left_c_begin, left_c_end) == k - 1);
CGAL_optimisation_precondition(
iterator_distance( right_c_begin, right_c_end) == k - 1);
CGAL_optimisation_expensive_precondition_code(
for ( int i( 0); i < k - 1; ++i) {
CGAL_optimisation_expensive_precondition( left_c_begin[i] >= 0);
CGAL_optimisation_expensive_precondition( right_c_begin[i] >= 0);
CGAL_optimisation_expensive_precondition(
left_c_begin[i] < number_of_points);
CGAL_optimisation_expensive_precondition(
right_c_begin[i] < number_of_points);
CGAL_optimisation_expensive_precondition(
left_c_begin[i] <= right_c_begin[i]);
})
int middle_index( (left_index + right_index) >> 1);
Index_cont P_m( k);
FT area_middle;
CGAL_maximum_inscribed_rooted_k_gon_2(
points_begin,
points_end,
middle_index,
left_c_begin,
left_c_end,
right_c_begin,
right_c_end,
area_middle,
P_m.rbegin(),
t);
CGAL_optimisation_assertion( P_m[0] == middle_index);
// left recursive branch:
FT area_left( 0);
Index_cont P_l( k);
if ( left_index < middle_index) {
CGAL_maximum_inscribed_k_gon_2(
points_begin,
points_end,
left_index,
middle_index - 1,
left_c_begin,
left_c_end,
P_m.begin() + 1,
P_m.end(),
k,
area_left,
P_l.rbegin(),
t);
} // if ( left_index < middle_index)
// right recursive branch:
FT area_right( 0);
Index_cont P_r( k);
if ( right_index > middle_index) {
CGAL_maximum_inscribed_k_gon_2(
points_begin,
points_end,
middle_index + 1,
right_index,
P_m.begin() + 1,
P_m.end(),
right_c_begin,
right_c_end,
k,
area_right,
P_r.rbegin(),
t);
} // if ( right_index > middle_index)
if ( area_left > area_right)
if ( area_left > area_middle) {
// left is maximum
max_area = area_left;
copy( P_l.begin(), P_l.end(), o);
}
else {
// middle is maximum
max_area = area_middle;
copy( P_m.begin(), P_m.end(), o);
}
else if ( area_right > area_middle) {
// right is maximum
max_area = area_right;
copy( P_r.begin(), P_r.end(), o);
}
else {
// middle is maximum
max_area = area_middle;
copy( P_m.begin(), P_m.end(), o);
}
return o;
} // CGAL_maximum_inscribed_k_gon_2( ... )
} //namespace CGAL
#endif // ! (CGAL_EXTREMAL_POLYGON_2_H)