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

947 lines
27 KiB
C
Raw Normal View History

// Copyright (c) 1997-2001 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) : Sven Schoenherr <sven@inf.ethz.ch>
#ifndef CGAL_POLYTOPE_DISTANCE_D_H
#define CGAL_POLYTOPE_DISTANCE_D_H
#include <CGAL/license/Polytope_distance_d.h>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4244) // conversion warning in Boost iterator_adaptor
#endif
// includes
// --------
#include <CGAL/Optimisation/basic.h>
#include <CGAL/function_objects.h>
#include <boost/functional.hpp>
#include <CGAL/QP_options.h>
#include <CGAL/QP_solver/QP_solver.h>
#include <CGAL/QP_models.h>
#include <CGAL/QP_solver/functors.h>
#include <CGAL/QP_solver/QP_full_filtered_pricing.h>
#include <CGAL/QP_solver/QP_full_exact_pricing.h>
namespace CGAL {
// To determine the polytope distance, we set up the following QP:
//
// We let v-w be nonnegative vectors such that
// v-w = p-q, where p and q are the points that realize the
// optimal distance. That way, we obtain a nonnegative QP
//
//
//min (v-w)^T(w-v)
// v-w - \sum x_i p_i + \sum y_j q_j = 0
// \sum x_i = 1
// \sum y_j = 1
// v, w, x, y >= 0
namespace PD_detail {
// The functors necessary to realize access to A
//
// A has the form
// I -I -P Q
// 0 0 1 0
// 0 0 0 1
// where I and -I are blocks of size d*d, and the 0's and 1's are
// rows vectors of 0's and 1's
//
// we have one functor for a fixed column, and one functor for the
// whole matrix
// functor for a fixed column of A
template <class NT, class Iterator>
class A_column : public CGAL::cpp98::unary_function <int, NT>
{
public:
typedef NT result_type;
A_column()
{}
A_column (int j, int d, bool in_p, Iterator it)
: j_ (j), d_ (d), in_p_ (in_p), it_ (it), nt_0_ (0), nt_1_ (1)
{}
result_type operator() (int i) const
{
if (j_ < d_) {
// column for v
return (i == j_ ? nt_1_ : nt_0_);
}
if (j_ < 2*d_) {
// column for w
return (i == j_-d_ ? -nt_1_ : nt_0_);
}
// point column
if (in_p_) {
// column for P
if (i < d_) return -(*(it_ + i));
if (i == d_) return *(it_ + d_); // homogenizing coordinate
return nt_0_;
} else {
// column for Q
if (i < d_) return (*(it_ + i));
if (i == d_+1) return *(it_ + d_); // homogenizing coordinate
return nt_0_;
}
// never get here
}
private:
int j_; // column number
int d_; // dimension
bool in_p_; // point in P ?
Iterator it_; // the iterator through the column's point
NT nt_0_;
NT nt_1_;
};
// functor for matrix A
template <class NT, class Access_coordinate_begin_d,
class Point_iterator >
class A_matrix : public CGAL::cpp98::unary_function
<int, boost::transform_iterator <A_column
<NT, typename Access_coordinate_begin_d::Coordinate_iterator>,
boost::counting_iterator<int> > >
{
typedef PD_detail::A_column
<NT, typename Access_coordinate_begin_d::Coordinate_iterator> A_column;
public:
typedef boost::transform_iterator
<A_column, boost::counting_iterator<int> > result_type;
A_matrix ()
{}
A_matrix (int d,
Access_coordinate_begin_d da_coord,
Point_iterator P,
int r,
Point_iterator Q)
: d_ (d), da_coord_ (da_coord), P_ (P), r_ (r), Q_ (Q)
{}
result_type operator () (int j) const
{
if (j < 2*d_) {
// column of v or w
return result_type
(0, A_column (j, d_, false /*dummy*/,
da_coord_ (*P_) /*dummy*/));
}
if (j < 2*d_+r_) {
// column of P
return result_type
(0, A_column (j , d_, true, da_coord_ (*(P_+(j-2*d_)))));
}
// column of Q
return result_type
(0, A_column (j, d_, false, da_coord_ (*(Q_+(j-2*d_-r_)))));
}
private:
int d_; // dimension
Access_coordinate_begin_d da_coord_; // data accessor
Point_iterator P_; // point set P
int r_; // size of point set P
Point_iterator Q_; // point set Q
};
// The functor necessary to realize access to b
// b has the form
// 0
// 0
// 1 (row d)
// 1 (row d+1)
template <class NT>
class B_vector : public CGAL::cpp98::unary_function<int, NT>
{
public:
typedef NT result_type;
B_vector()
{}
B_vector (int d)
: d_ (d), nt_0_ (0), nt_1_ (1)
{}
result_type operator() (int i) const
{
return ( (i == d_ || i == d_+1) ? nt_1_ : nt_0_);
}
private:
int d_;
NT nt_0_;
NT nt_1_;
};
// The functors necessary to realize access to D
//
// D has the form
// I -I 0
// -I I 0
// 0 0 0
// where all I and -I are blocks of size d*d
//
// we have one functor for a fixed row, and one functor for the
// whole matrix
// functor for a fixed row of D; note that we have to return 2D in
// order to please the QP_solver
template <class NT>
class D_row : public CGAL::cpp98::unary_function <int, NT>
{
public:
typedef NT result_type;
D_row ()
{}
D_row (int i, int d)
: i_ (i), d_ (d), nt_0_ (0), nt_2_ (2)
{}
result_type operator () (int j) const
{
if (j < d_) {
// I ( 1 iff i = j)
// -I (-1 iff i = j + d)
// 0
if (i_ == j) return nt_2_;
if (i_ == j + d_) return -nt_2_;
return nt_0_;
}
if (j < 2*d_) {
// -I (-1 iff i = j - d)
// I ( 1 iff i = j)
// 0
if (i_ == j - d_) return -nt_2_;
if (i_ == j) return nt_2_;
return nt_0_;
}
// 0
// 0
// 0
return nt_0_;
}
private:
int i_; // row number
int d_; // dimension
NT nt_0_;
NT nt_2_;
};
// functor for matrix D
template <class NT>
class D_matrix : public CGAL::cpp98::unary_function
<int, boost::transform_iterator<D_row<NT>,
boost::counting_iterator<int> > >
{
public:
typedef boost::transform_iterator<D_row<NT>,
boost::counting_iterator<int> > result_type;
D_matrix ()
{}
D_matrix (int d)
: d_ (d)
{}
result_type operator()(int i) const
{
return result_type (0, D_row<NT>(i, d_));
}
private:
int d_; // dimension
};
}
// Class interfaces
// ================
template < class Traits_ >
class Polytope_distance_d {
public:
// self
typedef Traits_ Traits;
typedef Polytope_distance_d<Traits>
Self;
// types from the traits class
typedef typename Traits::Point_d Point;
typedef typename Traits::Rep_tag Rep_tag;
typedef typename Traits::RT RT;
typedef typename Traits::FT FT;
typedef typename Traits::Access_dimension_d
Access_dimension_d;
typedef typename Traits::Access_coordinates_begin_d
Access_coordinates_begin_d;
typedef typename Traits::Construct_point_d
Construct_point_d;
typedef typename Traits::ET ET;
typedef typename Traits::NT NT;
private:
// private types
typedef std::vector<Point> Point_vector;
typedef std::vector<ET> ET_vector;
typedef QP_access_by_index
<typename std::vector<Point>::const_iterator, int> Point_by_index;
typedef std::vector<NT> NT_vector;
typedef std::vector<NT_vector> NT_matrix;
typedef std::vector<int> Index_vector;
public:
// public types
typedef typename Point_vector::const_iterator
Point_iterator;
typedef typename Index_vector::const_iterator IVCI;
typedef CGAL::Join_input_iterator_1< IVCI, Point_by_index >
Support_point_iterator;
typedef typename Index_vector::const_iterator
Support_point_index_iterator;
typedef typename ET_vector::const_iterator
Coordinate_iterator;
private:
// QP solver iterator types
typedef PD_detail::A_matrix <NT, Access_coordinates_begin_d,
Point_iterator> A_matrix;
typedef boost::transform_iterator<
A_matrix, boost::counting_iterator<int> > A_iterator;
typedef PD_detail::B_vector <NT> B_vector;
typedef boost::transform_iterator<
B_vector, boost::counting_iterator<int> > B_iterator;
typedef CGAL::Const_oneset_iterator<CGAL::Comparison_result> R_iterator;
typedef CGAL::Const_oneset_iterator<NT> C_iterator;
typedef PD_detail::D_matrix <NT> D_matrix;
typedef boost::transform_iterator <
D_matrix, boost::counting_iterator<int> > D_iterator;
// Program type
typedef CGAL::Nonnegative_quadratic_program_from_iterators
<A_iterator, B_iterator, R_iterator, D_iterator, C_iterator> QP;
// Tags
typedef QP_solver_impl::QP_tags <Tag_false, Tag_true> QP_tags;
// Solver types
typedef CGAL::QP_solver <QP, ET, QP_tags > Solver;
typedef typename Solver::Pricing_strategy Pricing_strategy;
public:
// creation
Polytope_distance_d( const Traits& traits = Traits())
: nt_0(0), nt_1(1),
tco( traits), da_coord (tco.access_coordinates_begin_d_object()),
d( -1), solver(0)
{}
template < class InputIterator1, class InputIterator2 >
Polytope_distance_d( InputIterator1 p_first,
InputIterator1 p_last,
InputIterator2 q_first,
InputIterator2 q_last,
const Traits& traits = Traits())
: nt_0(0), nt_1(1),
tco( traits), da_coord (tco.access_coordinates_begin_d_object()),
solver(0)
{
set( p_first, p_last, q_first, q_last);
}
~Polytope_distance_d() {
if (solver)
delete solver;
}
// access to point sets
int ambient_dimension( ) const { return d; }
int number_of_points( ) const { return static_cast<int>(p_points.size()+q_points.size());}
int number_of_points_p( ) const { return static_cast<int>(p_points.size()); }
int number_of_points_q( ) const { return static_cast<int>(q_points.size()); }
Point_iterator points_p_begin( ) const { return p_points.begin(); }
Point_iterator points_p_end ( ) const { return p_points.end (); }
Point_iterator points_q_begin( ) const { return q_points.begin(); }
Point_iterator points_q_end ( ) const { return q_points.end (); }
// access to support points
int
number_of_support_points( ) const
{ return is_finite() ?
static_cast<int>(p_support_indices.size()+q_support_indices.size()) : 0; }
int number_of_support_points_p() const { return static_cast<int>(p_support_indices.size());}
int number_of_support_points_q() const { return static_cast<int>(q_support_indices.size());}
Support_point_iterator
support_points_p_begin() const
{ return Support_point_iterator(
p_support_indices.begin(),
Point_by_index( p_points.begin())); }
Support_point_iterator
support_points_p_end() const
{ return Support_point_iterator(
is_finite() ? p_support_indices.end()
: p_support_indices.begin(),
Point_by_index( p_points.begin())); }
Support_point_iterator
support_points_q_begin() const
{ return Support_point_iterator(
q_support_indices.begin(),
Point_by_index( q_points.begin())); }
Support_point_iterator
support_points_q_end() const
{ return Support_point_iterator(
is_finite() ? q_support_indices.end()
: q_support_indices.begin(),
Point_by_index( q_points.begin())); }
Support_point_index_iterator
support_points_p_indices_begin() const
{ return p_support_indices.begin(); }
Support_point_index_iterator
support_points_p_indices_end() const
{ return p_support_indices.end(); }
Support_point_index_iterator
support_points_q_indices_begin() const
{ return q_support_indices.begin(); }
Support_point_index_iterator
support_points_q_indices_end() const
{ return q_support_indices.end(); }
// access to realizing points (rational representation)
Coordinate_iterator
realizing_point_p_coordinates_begin( ) const { return p_coords.begin(); }
Coordinate_iterator
realizing_point_p_coordinates_end ( ) const { return p_coords.end (); }
Coordinate_iterator
realizing_point_q_coordinates_begin( ) const { return q_coords.begin(); }
Coordinate_iterator
realizing_point_q_coordinates_end ( ) const { return q_coords.end (); }
// access to squared distance (rational representation)
ET squared_distance_numerator ( ) const
{ return solver->solution_numerator(); }
ET squared_distance_denominator( ) const
{ return solver->solution_denominator(); }
// access to realizing points and squared distance
// NOTE: an implicit conversion from ET to RT must be available!
Point
realizing_point_p( ) const
{ CGAL_optimisation_precondition( is_finite());
return tco.construct_point_d_object()
( ambient_dimension(),
realizing_point_p_coordinates_begin(),
realizing_point_p_coordinates_end ()); }
Point
realizing_point_q( ) const
{ CGAL_optimisation_precondition( is_finite());
return tco.construct_point_d_object()
( ambient_dimension(),
realizing_point_q_coordinates_begin(),
realizing_point_q_coordinates_end ()); }
FT
squared_distance( ) const
{
return FT( squared_distance_numerator ()) /
FT( squared_distance_denominator()); }
bool is_finite( ) const
{ return ( number_of_points_p() > 0) && ( number_of_points_q() > 0); }
bool is_zero( ) const
{ return CGAL_NTS is_zero( squared_distance_numerator()); }
bool is_degenerate( ) const { return ( ! is_finite()); }
// modifiers
template < class InputIterator1, class InputIterator2 >
void
set( InputIterator1 p_first, InputIterator1 p_last,
InputIterator2 q_first, InputIterator2 q_last)
{
p_points.clear();
q_points.clear();
std::copy( p_first, p_last, std::back_inserter( p_points));
std::copy( q_first, q_last, std::back_inserter( q_points));
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( p_points.begin(), p_points.end())
&& check_dimension( q_points.begin(), q_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
template < class InputIterator >
void
set_p( InputIterator p_first, InputIterator p_last)
{
p_points.clear();
std::copy( p_first, p_last, std::back_inserter( p_points));
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( p_points.begin(), p_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
template < class InputIterator >
void
set_q( InputIterator q_first, InputIterator q_last)
{
q_points.clear();
std::copy( q_first, q_last, std::back_inserter( q_points));
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( q_points.begin(), q_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
void
insert_p( const Point& p)
{
CGAL_optimisation_precondition
( ( ! is_finite()) ||
( tco.access_dimension_d_object()( p) == d));
p_points.push_back( p);
set_dimension(); // it might no longer be -1
compute_distance();
}
void
insert_q( const Point& q)
{
CGAL_optimisation_precondition
( ( ! is_finite()) ||
( tco.access_dimension_d_object()( q) == d));
q_points.push_back( q);
set_dimension(); // it might no longer be -1
compute_distance();
}
template < class InputIterator1, class InputIterator2 >
void
insert( InputIterator1 p_first, InputIterator1 p_last,
InputIterator2 q_first, InputIterator2 q_last)
{
CGAL_optimisation_precondition_code(int old_r = static_cast<int>(p_points.size()));
CGAL_optimisation_precondition_code(int old_s = static_cast<int>(q_points.size()));
p_points.insert( p_points.end(), p_first, p_last);
q_points.insert( q_points.end(), q_first, q_last);
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( p_points.begin()+old_r, p_points.end())
&& check_dimension( q_points.begin()+old_s, q_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
template < class InputIterator >
void
insert_p( InputIterator p_first, InputIterator p_last)
{
CGAL_optimisation_precondition_code(int old_r = static_cast<int>(p_points.size()));
p_points.insert( p_points.end(), p_first, p_last);
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( p_points.begin()+old_r, p_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
template < class InputIterator >
void
insert_q( InputIterator q_first, InputIterator q_last)
{
CGAL_optimisation_precondition_code( int old_s = static_cast<int>(q_points.size()));
q_points.insert( q_points.end(), q_first, q_last);
set_dimension();
CGAL_optimisation_precondition_msg
(check_dimension( q_points.begin()+old_s, q_points.end()),
"Not all points have the same dimension.");
compute_distance();
}
void
clear( )
{
p_points.clear();
q_points.clear();
compute_distance();
}
// validity check
bool is_valid( bool verbose = false, int level = 0) const;
// traits class access
const Traits& traits( ) const { return tco; }
private:
NT nt_0;
NT nt_1;
Traits tco; // traits class object
Access_coordinates_begin_d da_coord; // data accessor object
Point_vector p_points; // points of P
Point_vector q_points; // points of Q
int d; // dimension of input points
ET_vector p_coords; // realizing point of P
ET_vector q_coords; // realizing point of Q
Solver *solver; // quadratic programming solver
Index_vector p_support_indices;
Index_vector q_support_indices;
private:
// set dimension of input points
void
set_dimension( )
{
d = ( p_points.size() > 0 ?
tco.access_dimension_d_object()( p_points[ 0]) :
q_points.size() > 0 ?
tco.access_dimension_d_object()( q_points[ 0]) :
-1);
}
// check dimension of input points
template < class InputIterator >
bool
check_dimension( InputIterator first, InputIterator last)
{ return ( std::find_if
( first, last,
CGAL::compose1_1
( boost::bind2nd(std::not_equal_to<int>(), d),
tco.access_dimension_d_object()))
== last); }
// compute (squared) distance
void
compute_distance( )
{
// clear support points
p_support_indices.clear();
q_support_indices.clear();
if ( ( p_points.size() == 0) || ( q_points.size() == 0)) return;
// construct program
int n = 2 * d + static_cast<int>(p_points.size() + q_points.size());
int m = d + 2;
CGAL_optimisation_precondition (p_points.size() > 0);
QP qp (n, m,
A_iterator
(boost::counting_iterator<int>(0),
A_matrix (d, da_coord, p_points.begin(), static_cast<int>(p_points.size()),
q_points.begin())),
B_iterator (boost::counting_iterator<int>(0), B_vector (d)),
R_iterator (CGAL::EQUAL),
D_iterator (boost::counting_iterator<int>(0), D_matrix (d)),
C_iterator (nt_0));
delete solver;
Quadratic_program_options options;
options.set_pricing_strategy(pricing_strategy(NT()));
solver = new Solver(qp, options);
CGAL_optimisation_assertion(solver->status() == QP_OPTIMAL);
// compute support and realizing points
ET et_0 = 0;
int r = static_cast<int>(p_points.size());
p_coords.resize( ambient_dimension()+1);
q_coords.resize( ambient_dimension()+1);
std::fill( p_coords.begin(), p_coords.end(), et_0);
std::fill( q_coords.begin(), q_coords.end(), et_0);
for (int i = 0; i < solver->number_of_basic_original_variables(); ++i) {
ET value = solver->basic_original_variables_numerator_begin()[ i];
int index = solver->basic_original_variable_indices_begin()[ i];
if (index < 2*d) continue; // v or w variable
if (index < 2*d + r) {
// a point of p
for ( int j = 0; j < d; ++j) {
p_coords[ j]
+= value * ET(da_coord (p_points[ index-2*d ])[ j]);
}
p_support_indices.push_back( index-2*d);
} else {
// a point of q
for ( int j = 0; j < d; ++j) {
q_coords[ j]
+= value * ET(da_coord (q_points[ index-2*d-r])[ j]);
}
q_support_indices.push_back( index-2*d-r);
}
}
p_coords[ d] = q_coords[ d] = solver->variables_common_denominator();
}
template < class NT >
Quadratic_program_pricing_strategy pricing_strategy( NT) {
return QP_PARTIAL_FILTERED_DANTZIG;
}
Quadratic_program_pricing_strategy pricing_strategy( ET) {
return QP_PARTIAL_DANTZIG;
}
};
// Function declarations
// =====================
// output operator
template < class Traits_ >
std::ostream&
operator << ( std::ostream& os,
const Polytope_distance_d<Traits_>& poly_dist);
// ============================================================================
// Class implementation
// ====================
// validity check
template < class Traits_ >
bool
Polytope_distance_d<Traits_>::
is_valid( bool verbose, int level) const
{
using namespace std;
CGAL::Verbose_ostream verr( verbose);
verr << "CGAL::Polytope_distance_d<Traits>::" << endl;
verr << "is_valid( true, " << level << "):" << endl;
verr << " |P+Q| = " << number_of_points_p()
<< '+' << number_of_points_q()
<< ", |S| = " << number_of_support_points_p()
<< '+' << number_of_support_points_q() << endl;
if ( is_finite()) {
// compute normal vector
ET_vector normal( d), diff( d);
ET et_0 = 0, den = p_coords[d];
CGAL_optimisation_assertion (den > et_0);
CGAL_optimisation_assertion (den == q_coords[d]);
int i, j;
for ( j = 0; j < d; ++j) normal[ j] = p_coords[ j] - q_coords[ j];
// check correctness of computed squared distance
verr << " checking squared_distance..." << flush;
ET sqr_dist_num (0);
for ( j = 0; j < d; ++j)
sqr_dist_num += normal[ j] * normal[ j];
ET sqr_dist_den =
p_coords[ d] * p_coords[ d];
if (sqr_dist_num * squared_distance_denominator() !=
sqr_dist_den * squared_distance_numerator())
return CGAL::_optimisation_is_valid_fail
( verr, "realizing points don't have correct squared distance");
// check P
// -------
verr << " checking P..." << flush;
// check point set
for ( i = 0; i < number_of_points_p(); ++i) {
for ( j = 0; j < d; ++j) {
// compute (a positive multiple of) p^* - p_i
diff[ j] =
ET(da_coord(p_points[ i])[d]) * p_coords[ j] -
den * ET(da_coord( p_points[ i])[ j]);
}
if ( std::inner_product( diff.begin(), diff.end(),
normal.begin(), et_0) > et_0)
return CGAL::_optimisation_is_valid_fail
( verr, "polytope P is not separated by its hyperplane");
}
verr << "passed." << endl;
// check Q
// -------
verr << " checking Q..." << flush;
// check point set
for ( i = 0; i < number_of_points_q(); ++i) {
for ( j = 0; j < d; ++j) {
// compute (a positive multiple of) q^* - q_i
diff[ j] =
ET(da_coord(q_points[ i])[d]) * q_coords[ j] -
den * ET(da_coord( q_points[ i])[ j]);
}
if ( std::inner_product( diff.begin(), diff.end(),
normal.begin(), et_0) < et_0)
return CGAL::_optimisation_is_valid_fail
( verr, "polytope Q is not separated by its hyperplane");
}
verr << "passed." << endl;
}
verr << " object is valid!" << endl;
return( true);
}
// output operator
template < class Traits_ >
std::ostream&
operator << ( std::ostream& os,
const Polytope_distance_d<Traits_>& poly_dist)
{
using namespace std;
typedef typename Polytope_distance_d<Traits_>::Point Point;
typedef ostream_iterator<Point> Os_it;
typedef typename Traits_::ET ET;
typedef ostream_iterator<ET> Et_it;
switch ( CGAL::get_mode( os)) {
case CGAL::IO::PRETTY:
os << "CGAL::Polytope_distance_d( |P+Q| = "
<< poly_dist.number_of_points_p() << '+'
<< poly_dist.number_of_points_q() << ", |S| = "
<< poly_dist.number_of_support_points_p() << '+'
<< poly_dist.number_of_support_points_q() << endl;
os << " P = {" << endl;
os << " ";
copy( poly_dist.points_p_begin(), poly_dist.points_p_end(),
Os_it( os, ",\n "));
os << "}" << endl;
os << " Q = {" << endl;
os << " ";
copy( poly_dist.points_q_begin(), poly_dist.points_q_end(),
Os_it( os, ",\n "));
os << "}" << endl;
os << " S_P = {" << endl;
os << " ";
copy( poly_dist.support_points_p_begin(),
poly_dist.support_points_p_end(),
Os_it( os, ",\n "));
os << "}" << endl;
os << " S_Q = {" << endl;
os << " ";
copy( poly_dist.support_points_q_begin(),
poly_dist.support_points_q_end(),
Os_it( os, ",\n "));
os << "}" << endl;
os << " p = ( ";
copy( poly_dist.realizing_point_p_coordinates_begin(),
poly_dist.realizing_point_p_coordinates_end(),
Et_it( os, " "));
os << ")" << endl;
os << " q = ( ";
copy( poly_dist.realizing_point_q_coordinates_begin(),
poly_dist.realizing_point_q_coordinates_end(),
Et_it( os, " "));
os << ")" << endl;
os << " squared distance = "
<< poly_dist.squared_distance_numerator() << " / "
<< poly_dist.squared_distance_denominator() << endl;
break;
case CGAL::IO::ASCII:
os << poly_dist.number_of_points_p() << endl;
copy( poly_dist.points_p_begin(),
poly_dist.points_p_end(),
Os_it( os, "\n"));
os << poly_dist.number_of_points_q() << endl;
copy( poly_dist.points_q_begin(),
poly_dist.points_q_end(),
Os_it( os, "\n"));
break;
case CGAL::IO::BINARY:
os << poly_dist.number_of_points_p() << endl;
copy( poly_dist.points_p_begin(),
poly_dist.points_p_end(),
Os_it( os));
os << poly_dist.number_of_points_q() << endl;
copy( poly_dist.points_q_begin(),
poly_dist.points_q_end(),
Os_it( os));
break;
default:
CGAL_optimisation_assertion_msg( false,
"CGAL::get_mode( os) invalid!");
break; }
return( os);
}
} //namespace CGAL
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif // CGAL_POLYTOPE_DISTANCE_D_H
// ===== EOF ==================================================================