mirror of https://github.com/CGAL/cgal
Compiled successfully version first
This commit is contained in:
parent
a087f25cb2
commit
24e1b22b08
|
|
@ -1,9 +1,9 @@
|
||||||
/** @file dijkstra_theta.cpp
|
/** @file dijkstra_theta.cpp
|
||||||
*
|
*
|
||||||
* An example application that calculates the shortest paths on a constructed Theta graph
|
* An example application that constructs Theta graph first and then calculates
|
||||||
* by calling the Dijkstra's algorithm from BGL.
|
* the shortest paths on this graph by calling the Dijkstra's algorithm from BGL.
|
||||||
*/
|
*/
|
||||||
|
// Authors: Weisheng Si, Quincy Tse
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
#include <boost/graph/dijkstra_shortest_paths.hpp>
|
||||||
|
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
#include <CGAL/Theta_graph_2.h>
|
#include <CGAL/Construct_theta_graph_2.h>
|
||||||
|
|
||||||
using namespace boost;
|
using namespace boost;
|
||||||
|
|
||||||
|
|
@ -32,11 +32,10 @@ struct Edge_property {
|
||||||
/** record the Euclidean length of the edge */
|
/** record the Euclidean length of the edge */
|
||||||
double euclidean_length;
|
double euclidean_length;
|
||||||
};
|
};
|
||||||
// define the theta graph to use the selected kernel, to be undirected,
|
|
||||||
|
// define the Graph to use the selected kernel, to be undirected,
|
||||||
// and to use Edge_property as the edge property
|
// and to use Edge_property as the edge property
|
||||||
typedef CGAL::Theta_graph_2<Kernel, boost::undirectedS, Edge_property> T;
|
typedef adjacency_list<listS, vecS, undirectedS, Point_2, Edge_property> Graph;
|
||||||
// obtain the graph type by boost::adjacency_list
|
|
||||||
typedef T::Graph Graph;
|
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
|
|
@ -62,12 +61,13 @@ int main(int argc, char ** argv) {
|
||||||
std::istream_iterator< Point_2 > input_begin( inf );
|
std::istream_iterator< Point_2 > input_begin( inf );
|
||||||
std::istream_iterator< Point_2 > input_end;
|
std::istream_iterator< Point_2 > input_end;
|
||||||
|
|
||||||
|
// initialize the functor
|
||||||
|
// If the initial direction is omitted, the x-axis will be used
|
||||||
|
CGAL::Construct_theta_graph_2<Kernel, Graph> theta(k);
|
||||||
|
// create an adjacency_list object
|
||||||
|
Graph g;
|
||||||
// construct the theta graph on the vertex list
|
// construct the theta graph on the vertex list
|
||||||
T t(k, input_begin, input_end, Direction_2(1,0));
|
theta(input_begin, input_end, g);
|
||||||
|
|
||||||
// copy the boost::adjacency_list object of the constructed graph from t
|
|
||||||
// copy is used here because we need to modify the edge property when calling the dijkstra's algorithm.
|
|
||||||
Graph g = t.graph();
|
|
||||||
|
|
||||||
// select a source vertex for dijkstra's algorithm
|
// select a source vertex for dijkstra's algorithm
|
||||||
graph_traits<Graph>::vertex_descriptor v0;
|
graph_traits<Graph>::vertex_descriptor v0;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
/** @file exact_theta_io.cpp
|
/** @file exact_theta_io.cpp
|
||||||
*
|
*
|
||||||
* An example application that exactly constructs a Theta graph with an input vertex list,
|
* An example application that constructs a Theta graph exactly with an input vertex list,
|
||||||
* and then generates the Gnuplot files to plot the Theta graph.
|
* and then generates the Gnuplot files to plot the Theta graph.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// authors: Weisheng Si, Quincy Tse
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -14,22 +15,24 @@
|
||||||
|
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
#include <boost/graph/adjacency_list.hpp>
|
||||||
|
|
||||||
#include <CGAL/Theta_graph_2.h>
|
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||||
|
#include <CGAL/Construct_theta_graph_2.h>
|
||||||
#include <CGAL/gnuplot_output_2.h>
|
#include <CGAL/gnuplot_output_2.h>
|
||||||
|
|
||||||
// select the kernel type
|
// select the kernel type
|
||||||
typedef CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt Kernel;
|
typedef CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt Kernel;
|
||||||
typedef Kernel::Point_2 Point_2;
|
typedef Kernel::Point_2 Point_2;
|
||||||
typedef Kernel::Direction_2 Direction_2;
|
typedef Kernel::Direction_2 Direction_2;
|
||||||
// define the theta graph to use the selected kernel and to be undirected
|
typedef boost::adjacency_list<boost::setS,
|
||||||
typedef CGAL::Theta_graph_2<Kernel, boost::undirectedS> T;
|
boost::vecS,
|
||||||
// obtain the graph type by boost::adjacency_list
|
boost::undirectedS,
|
||||||
typedef T::Graph Graph;
|
Point_2
|
||||||
|
> Graph;
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<dx> <dy>]" << std::endl;
|
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<direction-x> <direction-y>]" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,13 +49,13 @@ int main(int argc, char ** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction_2 startingray;
|
Direction_2 initial_direction;
|
||||||
if (argc == 3)
|
if (argc == 3)
|
||||||
startingray = Direction_2(1, 0);
|
initial_direction = Direction_2(1, 0); // default initial_direction
|
||||||
else if (argc == 5)
|
else if (argc == 5)
|
||||||
startingray = Direction_2(atof(argv[3]), atof(argv[4]));
|
initial_direction = Direction_2(atof(argv[3]), atof(argv[4]));
|
||||||
else {
|
else {
|
||||||
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<dx> <dy>]" << std::endl;
|
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<direction-x> <direction-y>]" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,16 +63,18 @@ int main(int argc, char ** argv) {
|
||||||
std::istream_iterator<Point_2> input_begin( inf );
|
std::istream_iterator<Point_2> input_begin( inf );
|
||||||
std::istream_iterator<Point_2> input_end;
|
std::istream_iterator<Point_2> input_end;
|
||||||
|
|
||||||
// construct the theta graph on the vertex list
|
// initialize the functor
|
||||||
T t(k, input_begin, input_end, startingray);
|
CGAL::Construct_theta_graph_2<Kernel, Graph> theta(k, initial_direction);
|
||||||
|
// create an adjacency_list object
|
||||||
|
Graph g;
|
||||||
|
// construct the theta graph on the vertex list
|
||||||
|
theta(input_begin, input_end, g);
|
||||||
|
|
||||||
// obtain a reference to the boost::adjacency_list object of the constructed graph
|
|
||||||
const Graph& g = t.graph();
|
|
||||||
// obtain the number of vertices in the constructed graph
|
// obtain the number of vertices in the constructed graph
|
||||||
unsigned int n = boost::num_vertices(g);
|
unsigned int n = boost::num_vertices(g);
|
||||||
|
|
||||||
// generate gnuplot files for plotting this graph, 'e' stands for 'exact'
|
// generate gnuplot files for plotting this graph
|
||||||
std::string fileprefix = "et" + std::to_string(k) + "n" + std::to_string(n);
|
std::string fileprefix = "t" + std::to_string(k) + "n" + std::to_string(n);
|
||||||
CGAL::gnuplot_output_2(g, fileprefix);
|
CGAL::gnuplot_output_2(g, fileprefix);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
* and then generates the Gnuplot files to plot the Theta graph.
|
* and then generates the Gnuplot files to plot the Theta graph.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// authors: Weisheng Si, Quincy Tse
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -15,22 +16,24 @@
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
#include <boost/graph/adjacency_list.hpp>
|
||||||
|
|
||||||
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
#include <CGAL/Theta_graph_2.h>
|
#include <CGAL/Construct_theta_graph_2.h>
|
||||||
#include <CGAL/gnuplot_output_2.h>
|
#include <CGAL/gnuplot_output_2.h>
|
||||||
|
|
||||||
// select the kernel type
|
// select the kernel type
|
||||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||||
typedef Kernel::Point_2 Point_2;
|
typedef Kernel::Point_2 Point_2;
|
||||||
typedef Kernel::Direction_2 Direction_2;
|
typedef Kernel::Direction_2 Direction_2;
|
||||||
// define the theta graph to use the selected kernel and to be undirected
|
// it is important that the edgelist is 'setS', such that duplicate edges will be automatically removed.
|
||||||
typedef CGAL::Theta_graph_2<Kernel, boost::directedS> T;
|
typedef boost::adjacency_list<boost::setS,
|
||||||
// obtain the graph type by boost::adjacency_list
|
boost::vecS,
|
||||||
typedef T::Graph Graph;
|
boost::undirectedS,
|
||||||
|
Point_2
|
||||||
|
> Graph;
|
||||||
|
|
||||||
int main(int argc, char ** argv) {
|
int main(int argc, char ** argv) {
|
||||||
|
|
||||||
if (argc < 3) {
|
if (argc < 3) {
|
||||||
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<dx> <dy>]" << std::endl;
|
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<direction-x> <direction-y>]" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,13 +50,13 @@ int main(int argc, char ** argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Direction_2 startingray;
|
Direction_2 initial_direction;
|
||||||
if (argc == 3)
|
if (argc == 3)
|
||||||
startingray = Direction_2(1, 0);
|
initial_direction = Direction_2(1, 0); // default initial_direction
|
||||||
else if (argc == 5)
|
else if (argc == 5)
|
||||||
startingray = Direction_2(atof(argv[3]), atof(argv[4]));
|
initial_direction = Direction_2(atof(argv[3]), atof(argv[4]));
|
||||||
else {
|
else {
|
||||||
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<dx> <dy>]" << std::endl;
|
std::cout << "Usage: " << argv[0] << " <no. of cones> <input filename> [<direction-x> <direction-y>]" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,11 +64,13 @@ int main(int argc, char ** argv) {
|
||||||
std::istream_iterator<Point_2> input_begin( inf );
|
std::istream_iterator<Point_2> input_begin( inf );
|
||||||
std::istream_iterator<Point_2> input_end;
|
std::istream_iterator<Point_2> input_end;
|
||||||
|
|
||||||
// construct the theta graph on the vertex list
|
// initialize the functor
|
||||||
T t(k, input_begin, input_end, startingray);
|
CGAL::Construct_theta_graph_2<Kernel, Graph> theta(k, initial_direction);
|
||||||
|
// create an adjacency_list object
|
||||||
|
Graph g;
|
||||||
|
// construct the theta graph on the vertex list
|
||||||
|
theta(input_begin, input_end, g);
|
||||||
|
|
||||||
// obtain a reference to the boost::adjacency_list object of the constructed graph
|
|
||||||
const Graph& g = t.graph();
|
|
||||||
// obtain the number of vertices in the constructed graph
|
// obtain the number of vertices in the constructed graph
|
||||||
unsigned int n = boost::num_vertices(g);
|
unsigned int n = boost::num_vertices(g);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,183 @@
|
||||||
|
// Copyright (c) 2013-2015 The University of Western Sydney, Australia.
|
||||||
|
// 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$
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Authors: Weisheng Si, Quincy Tse
|
||||||
|
|
||||||
|
/*! \file Compute_cone_boundaries_2.h
|
||||||
|
*
|
||||||
|
* This header implements the functor for constructing theta graphs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CGAL_COMPUTE_CONE_BOUNDARIES_2_H
|
||||||
|
#define CGAL_COMPUTE_CONE_BOUNDARIES_2_H
|
||||||
|
|
||||||
|
// if leda::real is used, pls modify the following definition
|
||||||
|
#define CGAL_USE_CORE 1
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <utility>
|
||||||
|
#include <CGAL/Polynomial.h>
|
||||||
|
#include <CGAL/number_utils.h>
|
||||||
|
#include <CGAL/enum.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||||
|
#include <CGAL/Aff_transformation_2.h>
|
||||||
|
|
||||||
|
namespace CGAL {
|
||||||
|
|
||||||
|
/*! \ingroup PkgConeBasedSpanners
|
||||||
|
* \brief The functor for computing the directions of cone boundaries with a given
|
||||||
|
* cone number and a given initial direction. The results are stored in the vector
|
||||||
|
* \p rays.
|
||||||
|
*
|
||||||
|
* This computation can be either inexact by simply dividing an approximate Pi by the cone number
|
||||||
|
* (which is quick), or exact by using roots of polynomials (entailing number types such as `CORE::Expr` or `LEDA::Real`,
|
||||||
|
* which are slow). The inexact computation is done by the general functor definition,
|
||||||
|
* while the exact computation is done by a specialization of this functor.
|
||||||
|
* If the template parameter `Kernel_` is `Exact_predicates_exact_constructions_kernel_with_sqrt`,
|
||||||
|
* the specialization functor will be invoked.
|
||||||
|
*
|
||||||
|
* In the construction of Yao graph and Theta graph implemented by this package,
|
||||||
|
* all predicates and construction functions are from \cgal.
|
||||||
|
* Therefore, if the kernel `Exact_predicates_exact_constructions_kernel_with_sqrt` is used,
|
||||||
|
* the Yao or Theta graph will be constructed exactly, otherwise inexactly.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename Kernel_>
|
||||||
|
class Compute_cone_boundaries_2 {
|
||||||
|
public:
|
||||||
|
typedef Kernel_ kernel_type;
|
||||||
|
typedef typename Kernel_::FT FT;
|
||||||
|
typedef typename Kernel_::Direction_2 Direction_2;
|
||||||
|
typedef typename Kernel_::Aff_transformation_2 Transformation;
|
||||||
|
|
||||||
|
/* No member variables in this class, so a Constructor is not needed. */
|
||||||
|
//Compute_cone_boundaries_2() {};
|
||||||
|
|
||||||
|
/*! \brief The operator().
|
||||||
|
*
|
||||||
|
* The direction of the first ray can be specified by the parameter
|
||||||
|
* \p initial_direction, which allows the first ray to start at any direction. The remaining rays are calculated in
|
||||||
|
* counter-clockwise order.
|
||||||
|
*
|
||||||
|
* \param[in] cone_number The number of cones
|
||||||
|
* \param[in] initial_direction The direction of the first ray
|
||||||
|
* \param[out] rays The results, a vector of directions
|
||||||
|
*/
|
||||||
|
void operator()(const unsigned int cone_number,
|
||||||
|
Direction_2& initial_direction,
|
||||||
|
std::vector<Direction_2>& rays) {
|
||||||
|
if (cone_number<2) {
|
||||||
|
std::cout << "The number of cones should be larger than 1!" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rays.size() > 0) {
|
||||||
|
std::cout << "Initially, the vector rays must contain no elements!" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
rays.push_back(initial_direction);
|
||||||
|
|
||||||
|
const double cone_angle = 2*CGAL_PI/cone_number;
|
||||||
|
double sin_value, cos_value;
|
||||||
|
for (unsigned int i = 1; i < cone_number; i++) {
|
||||||
|
sin_value = std::sin(i*cone_angle);
|
||||||
|
cos_value = std::cos(i*cone_angle);
|
||||||
|
Direction_2 ray_i = Transformation(cos_value, -sin_value, sin_value, cos_value)(initial_direction);
|
||||||
|
rays.push_back(ray_i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class Compute_cone_boundaries_2<Exact_predicates_exact_constructions_kernel_with_sqrt> {
|
||||||
|
public:
|
||||||
|
typedef Exact_predicates_exact_constructions_kernel_with_sqrt kernel_type;
|
||||||
|
typedef typename Exact_predicates_exact_constructions_kernel_with_sqrt::FT FT;
|
||||||
|
typedef typename Exact_predicates_exact_constructions_kernel_with_sqrt::Direction_2 Direction_2;
|
||||||
|
typedef typename Exact_predicates_exact_constructions_kernel_with_sqrt::Aff_transformation_2 Transformation;
|
||||||
|
|
||||||
|
/*! \brief Constructor. */
|
||||||
|
Compute_cone_boundaries_2() {};
|
||||||
|
|
||||||
|
void operator()(const unsigned int cone_number,
|
||||||
|
Direction_2& initial_direction,
|
||||||
|
std::vector< Direction_2 >& rays) {
|
||||||
|
|
||||||
|
if (cone_number<2) {
|
||||||
|
std::cout << "The number of cones should be larger than 1!" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rays.size() > 0) {
|
||||||
|
std::cout << "Initially, the vector rays must contain no elements!" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//std::cout << "Specialization is called!" << std::endl;
|
||||||
|
|
||||||
|
// We actually use -x instead of x since CGAL::root_of() will give the k-th
|
||||||
|
// smallest root but we want the second largest one without counting.
|
||||||
|
Polynomial<FT> x(CGAL::shift(Polynomial<FT>(-1), 1));
|
||||||
|
Polynomial<FT> twox(2*x);
|
||||||
|
Polynomial<FT> a(1), b(x);
|
||||||
|
for (unsigned int i = 2; i <= cone_number; ++i) {
|
||||||
|
Polynomial<FT> c = twox*b - a;
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
}
|
||||||
|
a = b - 1;
|
||||||
|
|
||||||
|
unsigned int m, i;
|
||||||
|
if (cone_number % 2 == 0)
|
||||||
|
m = cone_number/2; // for even number of cones
|
||||||
|
else
|
||||||
|
m= cone_number/2 + 1; // for odd number of cones
|
||||||
|
|
||||||
|
FT cos_value, sin_value;
|
||||||
|
Direction_2 ray_i;
|
||||||
|
// add the first half number of rays in counter clockwise order
|
||||||
|
for (i = 1; i <= m; i++) {
|
||||||
|
cos_value = - root_of(i, a.begin(), a.end());
|
||||||
|
sin_value = sqrt(FT(1) - cos_value*cos_value);
|
||||||
|
ray_i = Transformation(cos_value, -sin_value, sin_value, cos_value)(initial_direction);
|
||||||
|
rays.push_back(ray_i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the remaining half number of rays in ccw order
|
||||||
|
if (cone_number % 2 == 0) {
|
||||||
|
for (i = 0; i < m; i++) {
|
||||||
|
rays.push_back(-rays[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < m-1; i++) {
|
||||||
|
cos_value = - root_of(m-i, a.begin(), a.end());
|
||||||
|
sin_value = - sqrt(FT(1) - cos_value*cos_value);
|
||||||
|
ray_i = Transformation(cos_value, -sin_value, sin_value, cos_value)(initial_direction);
|
||||||
|
rays.push_back(ray_i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // end of operator()
|
||||||
|
}; // end of functor specialization: Compute_cone_..._2
|
||||||
|
|
||||||
|
} // namespace CGAL
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2013-2014 The University of Western Sydney, Australia.
|
// Copyright (c) 2013-2015 The University of Western Sydney, Australia.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// This file is part of CGAL (www.cgal.org).
|
// This file is part of CGAL (www.cgal.org).
|
||||||
|
|
@ -16,157 +16,217 @@
|
||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Authors: Quincy Tse, Weisheng Si
|
// Authors: Weisheng Si, Quincy Tse
|
||||||
|
|
||||||
/** @file Theta_graph_2.h
|
/*! \file Construct_theta_graph_2.h
|
||||||
*
|
*
|
||||||
* This header implements the class Theta_graph_2, the constructor of which
|
* This header implements the functor for constructing Theta graphs.
|
||||||
* builds a Theta graph on a set of given vertices in the plane.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CGAL_THETA_GRAPH_2_H
|
#ifndef CGAL_CONSTRUCT_THETA_GRAPH_2_H
|
||||||
#define CGAL_THETA_GRAPH_2_H
|
#define CGAL_CONSTRUCT_THETA_GRAPH_2_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <set>
|
#include <utility>
|
||||||
#include <functional>
|
#include <CGAL/Polynomial.h>
|
||||||
|
#include <CGAL/number_utils.h>
|
||||||
|
#include <CGAL/enum.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||||
|
#include <CGAL/Aff_transformation_2.h>
|
||||||
|
#include <CGAL/Compute_cone_boundaries_2.h>
|
||||||
|
#include <CGAL/Cone_spanners_2/Less_by_direction_2.h>
|
||||||
|
#include <CGAL/Cone_spanners_2/Plane_Scan_Tree.h>
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
#include <boost/graph/adjacency_list.hpp>
|
||||||
|
|
||||||
#include <CGAL/Cone_spanners_2.h>
|
|
||||||
#include <CGAL/Cone_spanners_2/Plane_Scan_Tree.h>
|
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
/**
|
/*! \ingroup PkgConeBasedSpanners
|
||||||
* \ingroup PkgConeBasedSpanners
|
|
||||||
* @brief A derived class for constructing Theta graphs with a given set of 2D points.
|
|
||||||
*
|
|
||||||
* Its base class is Cone_spanners_2.
|
|
||||||
* Directed,undirected and bidirectional graphs are supported. For differences among these
|
|
||||||
* three types of graphs, please see the documentation of BGL.
|
|
||||||
*/
|
|
||||||
template <typename Kernel,
|
|
||||||
typename Directedness=boost::undirectedS,
|
|
||||||
typename EdgeProperty=boost::no_property>
|
|
||||||
class Theta_graph_2 : public Cone_spanners_2<Kernel, Directedness, EdgeProperty>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename Kernel::Direction_2 Direction_2;
|
|
||||||
typedef typename Kernel::Point_2 Point_2;
|
|
||||||
typedef typename Kernel::Line_2 Line_2;
|
|
||||||
typedef typename Kernel::Aff_transformation_2 Transformation;
|
|
||||||
|
|
||||||
typedef Cone_spanners_2<Kernel, Directedness, EdgeProperty> base_class;
|
\brief A functor for constructing theta graphs with a given set of 2D points.
|
||||||
typedef typename base_class::Graph Graph;
|
|
||||||
typedef typename base_class::vertex_smaller_2 vertex_smaller_2;
|
|
||||||
|
|
||||||
/** @brief constructs a Theta graph object.
|
\tparam Kernel_ The CGAL kernel used by this functor. If this parameter is
|
||||||
*
|
`CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt`,
|
||||||
* @param k Number of cones to divide space into
|
the graph will be constructed exactly; otherwise, inexactly using an approximate PI=3.1415...
|
||||||
* @param start An iterator pointing to the first point (vertex) in the graph.
|
|
||||||
* (default: NULL)
|
|
||||||
* @param end An iterator pointing to the place that passes the last point. (default: NULL)
|
|
||||||
* @param ray0 The direction of the first ray. This allows the first ray to be at an arbitary
|
|
||||||
* direction. (default: positive x-axis)
|
|
||||||
*/
|
|
||||||
//#ifdef GXX11
|
|
||||||
// template <typename PointInputIterator=Point_2*>
|
|
||||||
//#else
|
|
||||||
template <typename PointInputIterator>
|
|
||||||
//#endif
|
|
||||||
Theta_graph_2(const unsigned int k,
|
|
||||||
const PointInputIterator& start=NULL,
|
|
||||||
const PointInputIterator& end=NULL,
|
|
||||||
const Direction_2& ray0 = Direction_2(1,0)
|
|
||||||
)
|
|
||||||
: Cone_spanners_2<Kernel, Directedness, EdgeProperty>(k, start, end, ray0)
|
|
||||||
{
|
|
||||||
build_edges();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief copy constructor.
|
\tparam Graph_ The graph type to store the constructed Theta graph. It should be a model of
|
||||||
* @param x another Theta_graph_2 object to copy from.
|
both concepts MutableGraph and VertexAndEdgeListGraph in BGL. Of the two graph classes provided
|
||||||
*/
|
in BGL: `adjacency_list` and `adjacency_matrix`, only `adjacency_list` is such a model.
|
||||||
Theta_graph_2 (const Theta_graph_2& x)
|
So pls use `adjacency_list` to be your graph type. Note that there are seven template parameters for
|
||||||
: Cone_spanners_2<Kernel, Directedness, EdgeProperty>(x) {}
|
`boost::adjacency_list`: `OutEdgeList`, `VertexList`, `Directed`, `VertexProperties`, `EdgeProperties`,
|
||||||
|
`GraphProperties`, `EdgeList`, of which we require `VertexProperties` be `Point_2` from \cgal,
|
||||||
|
and other parameters can be chosen freely. Here `Point_2` is passed directly as bundled properties
|
||||||
|
to `adjacency_list` because this makes our implementation much more straightforward than using property maps.
|
||||||
|
For detailed information about bundled properties, pls refer to
|
||||||
|
http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/bundles.html.
|
||||||
|
*/
|
||||||
|
template <typename Kernel_, typename Graph_>
|
||||||
|
class Construct_theta_graph_2 {
|
||||||
|
|
||||||
/** @brief This function implements the algorithm for adding edges to build the Theta graph.
|
public:
|
||||||
* The algorithm implemented is described in
|
typedef Kernel_ kernel_type;
|
||||||
* Giri Narasimhan and Michiel Smid, Chapter 4: Spanners based on the Theta graph, Geometric Spanner Networks,
|
typedef Graph_ graph_type;
|
||||||
* Cambridge University Press, 2007.
|
|
||||||
* This algorithm has the complexity of O(n*log(n)), which is optimal.
|
|
||||||
*
|
|
||||||
* @return the constructed graph object.
|
|
||||||
*/
|
|
||||||
virtual Graph& build_edges() {
|
|
||||||
unsigned int i; // ray index of the cw ray
|
|
||||||
unsigned int j; // index of the ccw ray
|
|
||||||
|
|
||||||
for (i = 0; i < this->num_cones; i++) {
|
private:
|
||||||
j = (i+1) % this->num_cones;
|
typedef typename Kernel_::Direction_2 Direction_2;
|
||||||
add_edges_in_cone(this->rays[i], this->rays[j]);
|
typedef typename Kernel_::Point_2 Point_2;
|
||||||
}
|
typedef typename Kernel_::Line_2 Line_2;
|
||||||
return this->g;
|
typedef typename Kernel_::Aff_transformation_2 Transformation;
|
||||||
}
|
typedef Less_by_direction_2<Kernel_, Graph_> Less_by_direction;
|
||||||
|
|
||||||
/** @brief Construct edges in one cone bounded by two directions.
|
/* Store the number of cones. */
|
||||||
*
|
unsigned int cone_number;
|
||||||
* @param cwBound The direction that bounds the cone on the clockwise
|
|
||||||
* direction.
|
|
||||||
* @param ccwBound The direction that bounds the cone on the counter-clockwise
|
|
||||||
* direction.
|
|
||||||
*/
|
|
||||||
void add_edges_in_cone(const Direction_2& cwBound, const Direction_2& ccwBound) {
|
|
||||||
if (ccwBound == cwBound) {
|
|
||||||
// Degenerate case - k = 1
|
|
||||||
// not allowed.
|
|
||||||
throw std::out_of_range("k should be >= 2");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find angle bisector (requiring sqrt(), not exact)
|
/* Store the directions of the rays dividing the plane. The initial direction will be
|
||||||
Line_2 cwLine(ORIGIN, cwBound);
|
* stored in rays[0].
|
||||||
Line_2 ccwLine(ORIGIN, ccwBound);
|
*/
|
||||||
Direction_2 bisectorDir = bisector(cwLine, ccwLine).direction();
|
std::vector<Direction_2> rays;
|
||||||
|
|
||||||
// Rotational transformation of cw 90 degree
|
public:
|
||||||
static const Transformation cw90( 0, 1, -1, 0);
|
/*! \brief Constructor.
|
||||||
|
*
|
||||||
|
* Constructs a `Construct_theta_graph_2` object.
|
||||||
|
*
|
||||||
|
* \param k Number of cones to divide space into
|
||||||
|
* \param initial_direction A direction denoting one of the rays deviding the
|
||||||
|
* cones. This allows arbitary rotations of the rays that divide
|
||||||
|
* the plane. (default: positive x-axis)
|
||||||
|
*/
|
||||||
|
Construct_theta_graph_2 (unsigned int k,
|
||||||
|
Direction_2 initial_direction = Direction_2(1,0) )
|
||||||
|
|
||||||
// Ordering
|
{
|
||||||
Graph& g = this->g;
|
if (k<2) {
|
||||||
// here D1 is the reverse of D1 in the book, we find this is easier to implement
|
std::cout << "The number of cones should be larger than 1!" << std::endl;
|
||||||
const vertex_smaller_2 orderD1 (g, ccwBound);
|
std::exit(1);
|
||||||
const vertex_smaller_2 orderD2 (g, cwBound);
|
}
|
||||||
const vertex_smaller_2 orderMid(g, cw90(bisectorDir));
|
|
||||||
|
|
||||||
typename Graph::vertex_iterator vit, ve;
|
cone_number = k;
|
||||||
boost::tie(vit, ve) = boost::vertices(g);
|
/* Initialize a functor, specialization will happen here depending on the kernel type to
|
||||||
|
compute the cone boundaries either exactly or inexactly */
|
||||||
|
Compute_cone_boundaries_2<Kernel_> compute_cones;
|
||||||
|
// compute the rays using the functor
|
||||||
|
compute_cones(k, initial_direction, rays);
|
||||||
|
}
|
||||||
|
|
||||||
// Step 1: Sort S according to order induced by D1
|
/*! \brief Copy constructor.
|
||||||
std::vector<typename Graph::vertex_descriptor> S(vit, ve);
|
* \param x another Construct_theta_graph_2 object to copy from.
|
||||||
std::sort(S.begin (), S.end (), orderD1);
|
*/
|
||||||
|
Construct_theta_graph_2 (const Construct_theta_graph_2& x) : cone_number(x.cone_number), rays(x.rays) {}
|
||||||
|
|
||||||
// Step 2: Initialise an empty set to store vertices sorted by orderD2
|
/*! \brief Operator to construct a Theta graph.
|
||||||
typedef CGAL::ThetaDetail::Plane_Scan_Tree<typename Graph::vertex_descriptor,
|
*
|
||||||
typename Graph::vertex_descriptor,
|
* This operator implements the algorithm for adding edges to build the Theta graph.
|
||||||
vertex_smaller_2, vertex_smaller_2> PSTree;
|
* The algorithm implemented is described in:
|
||||||
PSTree pst(orderD2, orderMid);
|
* Giri Narasimhan and Michiel Smid, Chapter 4: Spanners based on the Theta graph, Geometric Spanner Networks,
|
||||||
|
* Cambridge University Press, 2007.
|
||||||
|
* This algorithm has the complexity of O(n*log(n)), which is optimal.
|
||||||
|
*
|
||||||
|
* \param start[in] An iterator pointing to the first point (vertex).
|
||||||
|
* \param end[in] An iterator pointing to the place that passes the last point.
|
||||||
|
* \param g[out] The constructed graph object.
|
||||||
|
*/
|
||||||
|
template <typename PointInputIterator>
|
||||||
|
Graph_& operator()(const PointInputIterator& start,
|
||||||
|
const PointInputIterator& end,
|
||||||
|
Graph_& g) {
|
||||||
|
|
||||||
|
// add vertices into the graph
|
||||||
|
for (PointInputIterator curr = start; curr != end; ++curr) {
|
||||||
|
g[boost::add_vertex(g)] = *curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int i; // ray index of the cw ray
|
||||||
|
unsigned int j; // index of the ccw ray
|
||||||
|
|
||||||
|
// add edges into the graph for every cone
|
||||||
|
for (i = 0; i < cone_number; i++) {
|
||||||
|
j = (i+1) % cone_number;
|
||||||
|
add_edges_in_cone(rays[i], rays[j], g);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief returns the number of cones.
|
||||||
|
*/
|
||||||
|
const unsigned int number_of_cones() const {
|
||||||
|
return cone_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief returns the vector of the directions of the rays dividing the plane.
|
||||||
|
*
|
||||||
|
* \return a vector of Direction_2
|
||||||
|
*/
|
||||||
|
const std::vector<Direction_2>& directions() const {
|
||||||
|
return rays;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/* \brief Construct edges in one cone bounded by two directions.
|
||||||
|
|
||||||
|
\param cwBound The direction of the clockwise boundary of the cone.
|
||||||
|
\param ccwBound The direction of the counter-clockwise boundary.
|
||||||
|
\param g The Theta graph to be built.
|
||||||
|
*/
|
||||||
|
void add_edges_in_cone(const Direction_2& cwBound, const Direction_2& ccwBound, Graph_& g) {
|
||||||
|
if (ccwBound == cwBound) {
|
||||||
|
// Degenerate case, not allowed.
|
||||||
|
throw std::out_of_range("The cw boundary and the ccw boundary shouldn't be same!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find angle bisector (requiring sqrt(), not exact)
|
||||||
|
Line_2 cwLine(ORIGIN, cwBound);
|
||||||
|
Line_2 ccwLine(ORIGIN, ccwBound);
|
||||||
|
Direction_2 bisector_direction = bisector(cwLine, ccwLine).direction();
|
||||||
|
|
||||||
|
// Rotational transformation of cw 90 degree
|
||||||
|
static const Transformation cw90( 0, 1, -1, 0);
|
||||||
|
|
||||||
|
// Ordering
|
||||||
|
// here D1 is the reverse of D1 in the book, we find this is easier to implement
|
||||||
|
const Less_by_direction orderD1 (g, ccwBound);
|
||||||
|
const Less_by_direction orderD2 (g, cwBound);
|
||||||
|
const Less_by_direction orderMid(g, cw90(bisector_direction));
|
||||||
|
|
||||||
|
typename Graph_::vertex_iterator vit, ve;
|
||||||
|
boost::tie(vit, ve) = boost::vertices(g);
|
||||||
|
|
||||||
|
// Step 1: Sort S according to order induced by D1
|
||||||
|
std::vector<typename Graph_::vertex_descriptor> S(vit, ve);
|
||||||
|
std::sort(S.begin (), S.end (), orderD1);
|
||||||
|
|
||||||
|
// Step 2: Initialise an empty set to store vertices sorted by orderD2
|
||||||
|
typedef CGAL::ThetaDetail::Plane_Scan_Tree<typename Graph_::vertex_descriptor,
|
||||||
|
typename Graph_::vertex_descriptor,
|
||||||
|
Less_by_direction,
|
||||||
|
Less_by_direction > PSTree;
|
||||||
|
PSTree pst(orderD2, orderMid);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION
|
#ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION
|
||||||
int i = 0;
|
int i = 0;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
// Step 3: visit S in orderD1
|
// Step 3: visit S in orderD1
|
||||||
// * insert pi into T
|
// * insert pi into T
|
||||||
// * ri = T.minAbove(pi)
|
// * ri = T.minAbove(pi)
|
||||||
for (typename std::vector<typename Graph::vertex_descriptor>::const_iterator
|
for (typename std::vector<typename Graph_::vertex_descriptor>::const_iterator
|
||||||
it = S.begin(); it != S.end(); ++it) {
|
it = S.begin(); it != S.end(); ++it) {
|
||||||
pst.add(*it, *it);
|
pst.add(*it, *it);
|
||||||
const typename Graph::vertex_descriptor *const ri = pst.minAbove(*it);
|
const typename Graph_::vertex_descriptor *const ri = pst.minAbove(*it);
|
||||||
if (NULL != ri)
|
if ( ri != NULL ) {
|
||||||
boost::add_edge(*it, *ri, g);
|
typename Graph_::edge_descriptor existing_e;
|
||||||
|
bool existing;
|
||||||
|
// check whether the edge already exists
|
||||||
|
boost::tie(existing_e, existing)=boost::edge(*it, *ri, g);
|
||||||
|
if (!existing)
|
||||||
|
boost::add_edge(*it, *ri, g);
|
||||||
|
//else
|
||||||
|
// std::cout << "Edge " << *it << ", " << *ri << " already exists!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION
|
#ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION
|
||||||
|
|
@ -180,51 +240,42 @@ namespace CGAL {
|
||||||
// ...etc...
|
// ...etc...
|
||||||
//
|
//
|
||||||
// The tree output shades the new value added, and states what action was taken.
|
// The tree output shades the new value added, and states what action was taken.
|
||||||
std::cout << "graph Plane_Scan_Tree {" << std::endl <<
|
std::cout << "graph Plane_Scan_Tree {" << std::endl <<
|
||||||
pst << std::endl << std::endl;
|
pst << std::endl << std::endl;
|
||||||
int j = 1;
|
int j = 1;
|
||||||
for (auto rit = S.rbegin(); rit <= it; ++rit) {
|
for (auto rit = S.rbegin(); rit <= it; ++rit) {
|
||||||
auto p = g[*rit];
|
auto p = g[*rit];
|
||||||
std::cout << "\t\"" << *rit << "\"[label=\"" << j++ << "\"";
|
std::cout << "\t\"" << *rit << "\"[label=\"" << j++ << "\"";
|
||||||
if (rit == it)
|
if (rit == it)
|
||||||
std::cout << ",style=filled";
|
std::cout << ",style=filled";
|
||||||
std::cout << "];" << std::endl;
|
std::cout << "];" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pst.size() > 1) {
|
if (pst.size() > 1) {
|
||||||
std::cout << "\t{rank=same;" << std::endl;
|
std::cout << "\t{rank=same;" << std::endl;
|
||||||
std::cout << "\"" << pst.begin()->first << "\"";
|
std::cout << "\"" << pst.begin()->first << "\"";
|
||||||
for (auto pit = ++(pst.begin()); pit != pst.end(); ++pit) {
|
for (auto pit = ++(pst.begin()); pit != pst.end(); ++pit) {
|
||||||
std::cout << "--\"" << pit->first << "\"";
|
std::cout << "--\"" << pit->first << "\"";
|
||||||
}
|
}
|
||||||
std::cout << "[color=white];" << std::endl;
|
std::cout << "[color=white];" << std::endl;
|
||||||
std::cout << "rankdir=LR;" << std::endl;
|
std::cout << "rankdir=LR;" << std::endl;
|
||||||
std::cout << "}" << std::endl;
|
std::cout << "}" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\tlabel=\"" << ++i << ": Added (" << g[*it].x().to_double() << "," << g[*it].y().to_double() << ").";
|
std::cout << "\tlabel=\"" << ++i << ": Added (" << g[*it].x().to_double() << "," << g[*it].y().to_double() << ").";
|
||||||
if (NULL != ri)
|
if (NULL != ri)
|
||||||
std::cout << " -- (" << g[*ri].x().to_double() << "," << g[*ri].y().to_double() << ").";
|
std::cout << " -- (" << g[*ri].x().to_double() << "," << g[*ri].y().to_double() << ").";
|
||||||
std::cout << "\";" << std::endl;
|
std::cout << "\";" << std::endl;
|
||||||
std::cout << "\ttableloc=\"b\";" << std:: endl;
|
std::cout << "\ttableloc=\"b\";" << std:: endl;
|
||||||
std::cout << "}" << std::endl << std::endl;
|
std::cout << "}" << std::endl << std::endl;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
} // end of for
|
} // end of for
|
||||||
}; // end of buildcone
|
}; // end of add edges in cone
|
||||||
|
|
||||||
}; // class theta_graph
|
}; // class Construct_theta_graph_2
|
||||||
|
|
||||||
|
|
||||||
/* serialization, to implement in future
|
|
||||||
|
|
||||||
template < typename Kernel, typename Directedness, typename EdgeProperty >
|
|
||||||
std::istream& operator>> (std::istream& is, Theta_graph_2<Kernel, Directedness, EdgeProperty>& theta_graph);
|
|
||||||
|
|
||||||
template < typename Kernel, typename Directedness, typename EdgeProperty >
|
|
||||||
std::ostream& operator<< (std::ostream& os, const Theta_graph_2<Kernel, Directedness, EdgeProperty>& theta_graph);
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // namespace CGAL
|
} // namespace CGAL
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2013-2014 The University of Western Sydney, Australia.
|
// Copyright (c) 2013-2015 The University of Western Sydney, Australia.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// This file is part of CGAL (www.cgal.org).
|
// This file is part of CGAL (www.cgal.org).
|
||||||
|
|
@ -16,185 +16,231 @@
|
||||||
// $Id$
|
// $Id$
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// Authors: Quincy Tse, Weisheng Si
|
// Authors: Weisheng Si, Quincy Tse
|
||||||
|
|
||||||
/** @file Yao_graph_2.h
|
/*! \file Construct_yao_graph_2.h
|
||||||
*
|
|
||||||
* This header implements the class Yao_graph_2, the constructor of which
|
|
||||||
* builds a Yao graph on a set of given vertices.
|
|
||||||
*
|
*
|
||||||
|
* This header implements the functor for constructing Yao graphs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CGAL_YAO_GRAPH_2_H
|
#ifndef CGAL_CONSTRUCT_YAO_GRAPH_2_H
|
||||||
#define CGAL_YAO_GRAPH_2_H
|
#define CGAL_CONSTRUCT_YAO_GRAPH_2_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <set>
|
#include <utility>
|
||||||
#include <functional>
|
#include <CGAL/Polynomial.h>
|
||||||
|
#include <CGAL/number_utils.h>
|
||||||
|
#include <CGAL/enum.h>
|
||||||
|
#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
|
||||||
|
#include <CGAL/Compute_cone_boundaries_2.h>
|
||||||
|
#include <CGAL/Cone_spanners_2/Less_by_direction_2.h>
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/graph/adjacency_list.hpp>
|
#include <boost/graph/adjacency_list.hpp>
|
||||||
|
|
||||||
#include <CGAL/Cone_spanners_2.h>
|
|
||||||
|
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
/**
|
/*! \ingroup PkgConeBasedSpanners
|
||||||
* \ingroup PkgConeBasedSpanners
|
|
||||||
* @brief A derived class for constructing Yao graphs with a given set of 2D points.
|
|
||||||
*
|
|
||||||
* Its base class is `Cone_spanners_2`.
|
|
||||||
* Directed, undirected and bidirectional graphs are supported. For differences among these
|
|
||||||
* three types of graphs, please see the documentation of BGL.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
template <typename Kernel,
|
|
||||||
typename Directedness=boost::undirectedS,
|
|
||||||
typename EdgeProperty=boost::no_property>
|
|
||||||
class Yao_graph_2 : public Cone_spanners_2<Kernel, Directedness, EdgeProperty>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename Kernel::Direction_2 Direction_2;
|
|
||||||
typedef typename Kernel::Point_2 Point_2;
|
|
||||||
typedef typename Kernel::Aff_transformation_2 Transformation;
|
|
||||||
|
|
||||||
typedef Cone_spanners_2<Kernel, Directedness, EdgeProperty> base_class;
|
\brief A functor for constructing yao graphs with a given set of 2D points.
|
||||||
typedef typename base_class::Graph Graph;
|
|
||||||
typedef typename base_class::vertex_smaller_2 vertex_smaller_2;
|
|
||||||
|
|
||||||
// a type for the set to store vertices sorted by a direction
|
\tparam Kernel_ The CGAL kernel used by this functor. If this parameter is
|
||||||
typedef std::set<typename Graph::vertex_descriptor, vertex_smaller_2> pointSet;
|
`CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt`,
|
||||||
|
the graph will be constructed exactly; otherwise, inexactly using an approximate PI=3.1415...
|
||||||
|
|
||||||
/** @brief constructs a Yao graph object.
|
\tparam Graph_ The graph type to store the constructed Yao graph. It should be a model of
|
||||||
*
|
both concepts MutableGraph and VertexAndEdgeListGraph in BGL. Of the two graph classes provided
|
||||||
* @param k Number of cones to divide space into
|
in BGL: `adjacency_list` and `adjacency_matrix`, only `adjacency_list` is such a model.
|
||||||
* @param start An iterator pointing to the first point (vertex) in the graph.
|
So pls use `adjacency_list` to be your graph type. Note that there are seven template parameters for
|
||||||
* (default: NULL)
|
`boost::adjacency_list`: `OutEdgeList`, `VertexList`, `Directed`, `VertexProperties`, `EdgeProperties`,
|
||||||
* @param end An iterator pointing to the place that passes the last point. (default: NULL)
|
`GraphProperties`, `EdgeList`, of which we require `VertexProperties` be `Point_2` from \cgal,
|
||||||
* @param ray0 The direction of the first ray. This allows arbitary direction of the first ray.
|
and other parameters can be chosen freely. Here `Point_2` is passed directly as bundled properties
|
||||||
* (default: positive x-axis)
|
to `adjacency_list` because this makes our implementation much more straightforward than using property maps.
|
||||||
*/
|
For detailed information about bundled properties, pls refer to
|
||||||
//#ifdef GXX11
|
http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/bundles.html.
|
||||||
// template <typename PointInputIterator=Point_2*>
|
*/
|
||||||
//#else
|
template <typename Kernel_, typename Graph_>
|
||||||
template <typename PointInputIterator>
|
class Construct_yao_graph_2 {
|
||||||
//#endif
|
|
||||||
Yao_graph_2(const unsigned int k,
|
|
||||||
const PointInputIterator& start=NULL,
|
|
||||||
const PointInputIterator& end=NULL,
|
|
||||||
const Direction_2& ray0 = Direction_2(1,0)
|
|
||||||
)
|
|
||||||
: Cone_spanners_2<Kernel, Directedness, EdgeProperty>(k, start, end, ray0)
|
|
||||||
{
|
|
||||||
build_edges();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief copy constructor
|
public:
|
||||||
* @param x another `Yao_graph_2` object to copy from.
|
typedef Kernel_ kernel_type;
|
||||||
*/
|
typedef Graph_ graph_type;
|
||||||
Yao_graph_2 (const Yao_graph_2& x)
|
|
||||||
: Cone_spanners_2<Kernel, Directedness, EdgeProperty>(x) {}
|
|
||||||
|
|
||||||
/** @brief This function implements the algorithm for adding edges to build the Yao graph.
|
private:
|
||||||
*
|
typedef typename Kernel_::Direction_2 Direction_2;
|
||||||
* The algorithm implemented is a slight adaptation to the algorithm for Theta graph described in
|
typedef typename Kernel_::Point_2 Point_2;
|
||||||
* Giri Narasimhan and Michiel Smid, Chapter 4: Spanners based on the Theta graph, Geometric Spanner Networks,
|
typedef typename Kernel_::Line_2 Line_2;
|
||||||
* Cambridge University Press, 2007.
|
typedef Less_by_direction_2<Kernel_, Graph_> Less_by_direction;
|
||||||
* The adaptation lies in the way how the 'closest' node is searched.
|
// a type for the set to store vertices sorted by a direction
|
||||||
* A binary tree search is not possible here, so the search here has complexity O(n),
|
typedef std::set<typename Graph_::vertex_descriptor, Less_by_direction> Point_set;
|
||||||
* giving rise to the complexity of O(n^2) of the entire algorithm.
|
|
||||||
*
|
|
||||||
* @return the constructed graph object.
|
|
||||||
*/
|
|
||||||
virtual Graph& build_edges() {
|
|
||||||
unsigned int i; // ray index of the cw ray
|
|
||||||
unsigned int j; // index of the ccw ray
|
|
||||||
|
|
||||||
for (i = 0; i < this->num_cones; i++) {
|
/* Store the number of cones. */
|
||||||
j = (i+1) % this->num_cones;
|
unsigned int cone_number;
|
||||||
add_edges_in_cone(this->rays[i], this->rays[j]);
|
|
||||||
}
|
|
||||||
return this->g;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Construct edges bounded by two directions.
|
/* Store the directions of the rays dividing the plane. The initial direction will be
|
||||||
*
|
* stored in rays[0].
|
||||||
* @param cwBound The direction that bounds the cone on the clockwise
|
*/
|
||||||
* direction.
|
std::vector<Direction_2> rays;
|
||||||
* @param ccwBound The direction that bounds the cone on the counter-clockwise
|
|
||||||
* direction.
|
public:
|
||||||
* @return The updated underlying graph.
|
/*! \brief Constructor.
|
||||||
*
|
*
|
||||||
* @see G. Narasimhan and M. Smid, Geometric Spanner Networks: Cambridge
|
* Constructs a `Construct_yao_graph_2` object.
|
||||||
* University Press, 2007,
|
*
|
||||||
*/
|
* \param k Number of cones to divide space into
|
||||||
void add_edges_in_cone(const Direction_2& cwBound, const Direction_2& ccwBound) {
|
* \param initial_direction A direction denoting one of the rays deviding the
|
||||||
if (ccwBound == cwBound) {
|
* cones. This allows arbitary rotations of the rays that divide
|
||||||
// Degenerate case - k = 1
|
* the plane. (default: positive x-axis)
|
||||||
// not allowed.
|
*/
|
||||||
throw std::out_of_range("k should be >= 2");
|
Construct_yao_graph_2 (unsigned int k,
|
||||||
|
Direction_2 initial_direction = Direction_2(1,0) )
|
||||||
|
|
||||||
|
{
|
||||||
|
if (k<2) {
|
||||||
|
std::cout << "The number of cones should be larger than 1!" << std::endl;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cone_number = k;
|
||||||
|
/* Initialize a functor, specialization will happen here depending on the kernel type to
|
||||||
|
compute the cone boundaries either exactly or inexactly */
|
||||||
|
Compute_cone_boundaries_2<Kernel_> compute_cones;
|
||||||
|
// compute the rays using the functor
|
||||||
|
compute_cones(k, initial_direction, rays);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Copy constructor.
|
||||||
|
* \param x another Construct_yao_graph_2 object to copy from.
|
||||||
|
*/
|
||||||
|
Construct_yao_graph_2 (const Construct_yao_graph_2& x) : cone_number(x.cone_number), rays(x.rays) {}
|
||||||
|
|
||||||
|
/*! \brief Operator to construct a Yao graph.
|
||||||
|
*
|
||||||
|
* This operator implements the algorithm for adding edges to build the Yao graph.
|
||||||
|
* The algorithm implemented is described in:
|
||||||
|
* Giri Narasimhan and Michiel Smid, Chapter 4: Spanners based on the Yao graph, Geometric Spanner Networks,
|
||||||
|
* Cambridge University Press, 2007.
|
||||||
|
* This algorithm has the complexity of O(n*log(n)), which is optimal.
|
||||||
|
*
|
||||||
|
* \param start[in] An iterator pointing to the first point (vertex).
|
||||||
|
* \param end[in] An iterator pointing to the place that passes the last point.
|
||||||
|
* \param g[out] The constructed graph object.
|
||||||
|
*/
|
||||||
|
template <typename PointInputIterator>
|
||||||
|
Graph_& operator()(const PointInputIterator& start,
|
||||||
|
const PointInputIterator& end,
|
||||||
|
Graph_& g) {
|
||||||
|
|
||||||
|
// add vertices into the graph
|
||||||
|
for (PointInputIterator curr = start; curr != end; ++curr) {
|
||||||
|
g[boost::add_vertex(g)] = *curr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int i; // ray index of the cw ray
|
||||||
|
unsigned int j; // index of the ccw ray
|
||||||
|
|
||||||
|
// add edges into the graph for every cone
|
||||||
|
for (i = 0; i < cone_number; i++) {
|
||||||
|
j = (i+1) % cone_number;
|
||||||
|
add_edges_in_cone(rays[i], rays[j], g);
|
||||||
|
}
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief returns the number of cones.
|
||||||
|
*/
|
||||||
|
const unsigned int number_of_cones() const {
|
||||||
|
return cone_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief returns the vector of the directions of the rays dividing the plane.
|
||||||
|
*
|
||||||
|
* \return a vector of Direction_2
|
||||||
|
*/
|
||||||
|
const std::vector<Direction_2>& directions() const {
|
||||||
|
return rays;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/* \brief Construct edges in one cone bounded by two directions.
|
||||||
|
|
||||||
|
\param cwBound The direction of the clockwise boundary of the cone.
|
||||||
|
\param ccwBound The direction of the counter-clockwise boundary.
|
||||||
|
\param g The Yao graph to be built.
|
||||||
|
*/
|
||||||
|
void add_edges_in_cone(const Direction_2& cwBound, const Direction_2& ccwBound, Graph_& g) {
|
||||||
|
if (ccwBound == cwBound) {
|
||||||
|
// Degenerate case, not allowed.
|
||||||
|
throw std::out_of_range("The cw boundary and the ccw boundary shouldn't be same!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ordering
|
||||||
|
// here D1 is the reverse of D1 in the book, we find this is easier to implement
|
||||||
|
const Less_by_direction orderD1 (g, ccwBound);
|
||||||
|
const Less_by_direction orderD2 (g, cwBound);
|
||||||
|
|
||||||
|
typename Graph_::vertex_iterator vit, ve;
|
||||||
|
boost::tie(vit, ve) = boost::vertices(g);
|
||||||
|
|
||||||
|
// Step 1: Sort S according to order induced by D1
|
||||||
|
std::vector<typename Graph_::vertex_descriptor> S(vit, ve);
|
||||||
|
std::sort(S.begin (), S.end (), orderD1);
|
||||||
|
|
||||||
|
// Step 2: Initialise an empty set to store vertices sorted by orderD2
|
||||||
|
Point_set pst(orderD2);
|
||||||
|
|
||||||
|
// Step 3: visit S in orderD1
|
||||||
|
// insert 'it' into pst
|
||||||
|
// search the min in pst
|
||||||
|
for (typename std::vector<typename Graph_::vertex_descriptor>::const_iterator
|
||||||
|
it = S.begin(); it != S.end(); ++it) {
|
||||||
|
Less_euclidean_distance comp(g[*it], g);
|
||||||
|
|
||||||
|
pst.insert(*it);
|
||||||
|
// Find the last added node - O(logn)
|
||||||
|
typename Point_set::iterator it2 = pst.find(*it);
|
||||||
|
// Find minimum in pst from last ended node - O(n)
|
||||||
|
typename Point_set::iterator min = std::min_element(++it2, pst.end(), comp);
|
||||||
|
// add an edge
|
||||||
|
if (min != pst.end()) {
|
||||||
|
typename Graph_::edge_descriptor existing_e;
|
||||||
|
bool existing;
|
||||||
|
// check whether the edge already exists
|
||||||
|
boost::tie(existing_e, existing)=boost::edge(*it, *min, g);
|
||||||
|
if (!existing)
|
||||||
|
boost::add_edge(*it, *min, g);
|
||||||
|
//else
|
||||||
|
// std::cout << "Edge " << *it << ", " << *min << " already exists!" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ordering
|
} // end of for
|
||||||
Graph& g = this->g;
|
|
||||||
// here D1 is the reverse of D1 in the book, we find this is easier to implement
|
|
||||||
const vertex_smaller_2 orderD1 (g, ccwBound);
|
|
||||||
const vertex_smaller_2 orderD2 (g, cwBound);
|
|
||||||
|
|
||||||
typename Graph::vertex_iterator vit, ve;
|
}; // end of add edges in cone
|
||||||
boost::tie(vit, ve) = boost::vertices(g);
|
|
||||||
|
|
||||||
// Step 1: Sort S according to order induced by D1
|
|
||||||
std::vector<typename Graph::vertex_descriptor> S(vit, ve);
|
|
||||||
std::sort(S.begin (), S.end (), orderD1);
|
|
||||||
|
|
||||||
// Step 2: Initialise an empty set to store vertices sorted by orderD2
|
/* Functor for comparing Euclidean distances of two vertices in a graph g to a given vertex.
|
||||||
pointSet pst(orderD2);
|
It is implemented by encapsulating the CGAL::has_smaller_distance_to_point() function.
|
||||||
|
*/
|
||||||
|
struct Less_euclidean_distance {
|
||||||
|
const Point_2& p;
|
||||||
|
const Graph_& g;
|
||||||
|
|
||||||
// Step 3: visit S in orderD1
|
// constructor
|
||||||
// * insert 'it' into T
|
Less_euclidean_distance(const Point_2&p, const Graph_& g) : p(p), g(g) {}
|
||||||
// search the min in T
|
|
||||||
for (typename std::vector<typename Graph::vertex_descriptor>::const_iterator
|
|
||||||
it = S.begin(); it != S.end(); ++it)
|
|
||||||
{
|
|
||||||
Compare_Euclidean_Distance comp(g[*it], g);
|
|
||||||
|
|
||||||
pst.insert(*it);
|
// operator
|
||||||
// Find the last added node - O(logn)
|
bool operator() (const typename Point_set::iterator::value_type& i, const typename Point_set::iterator::value_type& j) {
|
||||||
typename pointSet::iterator it2 = pst.find(*it);
|
const Point_2& p1 = g[i];
|
||||||
// Find minimum in tree from last ended node - O(n)
|
const Point_2& p2 = g[j];
|
||||||
typename pointSet::iterator min = std::min_element(++it2, pst.end(), comp);
|
return has_smaller_distance_to_point(p, p1, p2);
|
||||||
if (min != pst.end())
|
}
|
||||||
boost::add_edge(*it, *min, g);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}; // class Construct_yao_graph_2
|
||||||
|
|
||||||
/* functor for comparing Euclidean distances of two vertices to a given vertex */
|
|
||||||
struct Compare_Euclidean_Distance {
|
|
||||||
const Point_2& p;
|
|
||||||
const Graph& g;
|
|
||||||
|
|
||||||
Compare_Euclidean_Distance(const Point_2&p, const Graph& g) : p(p), g(g) {}
|
|
||||||
bool operator() (const typename pointSet::iterator::value_type& x, const typename pointSet::iterator::value_type& y) {
|
|
||||||
const Point_2& px = g[x];
|
|
||||||
const Point_2& py = g[y];
|
|
||||||
return (px.x()-p.x())*(px.x()-p.x()) + (px.y()-p.y())*(px.y()-p.y()) < (py.x()-p.x())*(py.x()-p.x()) + (py.y()-p.y())*(py.y()-p.y());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // class yao_graph
|
|
||||||
|
|
||||||
/* serialization, to implement in future
|
|
||||||
|
|
||||||
template < typename Kernel, typename Directedness, typename EdgeProperty >
|
|
||||||
std::istream& operator>> (std::istream& is, Yao_graph_2<Kernel, Directedness, EdgeProperty>& yao_graph);
|
|
||||||
|
|
||||||
template < typename Kernel, typename Directedness, typename EdgeProperty >
|
|
||||||
std::ostream& operator<< (std::ostream& os, const Yao_graph_2<Kernel, Directedness, EdgeProperty>& yao_graph);
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
} // namespace CGAL
|
} // namespace CGAL
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue