From 24e1b22b0868407cebee3cff08738e414484f3b0 Mon Sep 17 00:00:00 2001 From: Weisheng Si Date: Thu, 21 May 2015 09:15:29 +1000 Subject: [PATCH] Compiled successfully version first --- .../Cone_spanners_2/dijkstra_theta.cpp | 26 +- .../Cone_spanners_2/exact_theta_io.cpp | 39 +- .../examples/Cone_spanners_2/theta_io.cpp | 33 +- .../include/CGAL/Compute_cone_boundaries_2.h | 183 +++++++++ .../include/CGAL/Construct_theta_graph_2.h | 377 ++++++++++-------- .../include/CGAL/Construct_yao_graph_2.h | 352 +++++++++------- 6 files changed, 650 insertions(+), 360 deletions(-) create mode 100644 Cone_spanners_2/include/CGAL/Compute_cone_boundaries_2.h diff --git a/Cone_spanners_2/examples/Cone_spanners_2/dijkstra_theta.cpp b/Cone_spanners_2/examples/Cone_spanners_2/dijkstra_theta.cpp index c7aebebde15..1f56b108b15 100644 --- a/Cone_spanners_2/examples/Cone_spanners_2/dijkstra_theta.cpp +++ b/Cone_spanners_2/examples/Cone_spanners_2/dijkstra_theta.cpp @@ -1,9 +1,9 @@ /** @file dijkstra_theta.cpp * - * An example application that calculates the shortest paths on a constructed Theta graph - * by calling the Dijkstra's algorithm from BGL. + * An example application that constructs Theta graph first and then calculates + * the shortest paths on this graph by calling the Dijkstra's algorithm from BGL. */ - +// Authors: Weisheng Si, Quincy Tse #include #include #include @@ -18,7 +18,7 @@ #include #include -#include +#include using namespace boost; @@ -32,11 +32,10 @@ struct Edge_property { /** record the Euclidean length of the edge */ 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 -typedef CGAL::Theta_graph_2 T; -// obtain the graph type by boost::adjacency_list -typedef T::Graph Graph; +typedef adjacency_list Graph; 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_end; + // initialize the functor + // If the initial direction is omitted, the x-axis will be used + CGAL::Construct_theta_graph_2 theta(k); + // create an adjacency_list object + Graph g; // construct the theta graph on the vertex list - T t(k, input_begin, input_end, Direction_2(1,0)); - - // 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(); + theta(input_begin, input_end, g); // select a source vertex for dijkstra's algorithm graph_traits::vertex_descriptor v0; diff --git a/Cone_spanners_2/examples/Cone_spanners_2/exact_theta_io.cpp b/Cone_spanners_2/examples/Cone_spanners_2/exact_theta_io.cpp index 0c7d51930e3..b657fb10f98 100644 --- a/Cone_spanners_2/examples/Cone_spanners_2/exact_theta_io.cpp +++ b/Cone_spanners_2/examples/Cone_spanners_2/exact_theta_io.cpp @@ -1,9 +1,10 @@ /** @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. */ +// authors: Weisheng Si, Quincy Tse #include #include #include @@ -14,22 +15,24 @@ #include -#include +#include +#include #include // select the kernel type typedef CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt Kernel; typedef Kernel::Point_2 Point_2; typedef Kernel::Direction_2 Direction_2; -// define the theta graph to use the selected kernel and to be undirected -typedef CGAL::Theta_graph_2 T; -// obtain the graph type by boost::adjacency_list -typedef T::Graph Graph; +typedef boost::adjacency_list Graph; int main(int argc, char ** argv) { if (argc < 3) { - std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; + std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; return 1; } @@ -46,13 +49,13 @@ int main(int argc, char ** argv) { return 1; } - Direction_2 startingray; + Direction_2 initial_direction; if (argc == 3) - startingray = Direction_2(1, 0); + initial_direction = Direction_2(1, 0); // default initial_direction else if (argc == 5) - startingray = Direction_2(atof(argv[3]), atof(argv[4])); + initial_direction = Direction_2(atof(argv[3]), atof(argv[4])); else { - std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; + std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; return 1; } @@ -60,16 +63,18 @@ int main(int argc, char ** argv) { std::istream_iterator input_begin( inf ); std::istream_iterator input_end; - // construct the theta graph on the vertex list - T t(k, input_begin, input_end, startingray); + // initialize the functor + CGAL::Construct_theta_graph_2 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 unsigned int n = boost::num_vertices(g); - // generate gnuplot files for plotting this graph, 'e' stands for 'exact' - std::string fileprefix = "et" + std::to_string(k) + "n" + std::to_string(n); + // generate gnuplot files for plotting this graph + std::string fileprefix = "t" + std::to_string(k) + "n" + std::to_string(n); CGAL::gnuplot_output_2(g, fileprefix); return 0; diff --git a/Cone_spanners_2/examples/Cone_spanners_2/theta_io.cpp b/Cone_spanners_2/examples/Cone_spanners_2/theta_io.cpp index 5b826f7b5ad..18c87d836ef 100644 --- a/Cone_spanners_2/examples/Cone_spanners_2/theta_io.cpp +++ b/Cone_spanners_2/examples/Cone_spanners_2/theta_io.cpp @@ -4,6 +4,7 @@ * and then generates the Gnuplot files to plot the Theta graph. */ +// authors: Weisheng Si, Quincy Tse #include #include #include @@ -15,22 +16,24 @@ #include #include -#include +#include #include // select the kernel type typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_2 Point_2; typedef Kernel::Direction_2 Direction_2; -// define the theta graph to use the selected kernel and to be undirected -typedef CGAL::Theta_graph_2 T; -// obtain the graph type by boost::adjacency_list -typedef T::Graph Graph; +// it is important that the edgelist is 'setS', such that duplicate edges will be automatically removed. +typedef boost::adjacency_list Graph; int main(int argc, char ** argv) { if (argc < 3) { - std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; + std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; return 1; } @@ -47,13 +50,13 @@ int main(int argc, char ** argv) { return 1; } - Direction_2 startingray; + Direction_2 initial_direction; if (argc == 3) - startingray = Direction_2(1, 0); + initial_direction = Direction_2(1, 0); // default initial_direction else if (argc == 5) - startingray = Direction_2(atof(argv[3]), atof(argv[4])); + initial_direction = Direction_2(atof(argv[3]), atof(argv[4])); else { - std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; + std::cout << "Usage: " << argv[0] << " [ ]" << std::endl; return 1; } @@ -61,11 +64,13 @@ int main(int argc, char ** argv) { std::istream_iterator input_begin( inf ); std::istream_iterator input_end; - // construct the theta graph on the vertex list - T t(k, input_begin, input_end, startingray); + // initialize the functor + CGAL::Construct_theta_graph_2 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 unsigned int n = boost::num_vertices(g); diff --git a/Cone_spanners_2/include/CGAL/Compute_cone_boundaries_2.h b/Cone_spanners_2/include/CGAL/Compute_cone_boundaries_2.h new file mode 100644 index 00000000000..8561130764f --- /dev/null +++ b/Cone_spanners_2/include/CGAL/Compute_cone_boundaries_2.h @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 +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& 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 { +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 x(CGAL::shift(Polynomial(-1), 1)); + Polynomial twox(2*x); + Polynomial a(1), b(x); + for (unsigned int i = 2; i <= cone_number; ++i) { + Polynomial 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 diff --git a/Cone_spanners_2/include/CGAL/Construct_theta_graph_2.h b/Cone_spanners_2/include/CGAL/Construct_theta_graph_2.h index 711f8206a86..7122293c58d 100644 --- a/Cone_spanners_2/include/CGAL/Construct_theta_graph_2.h +++ b/Cone_spanners_2/include/CGAL/Construct_theta_graph_2.h @@ -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. // // This file is part of CGAL (www.cgal.org). @@ -14,159 +14,219 @@ // // $URL$ // $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 - * builds a Theta graph on a set of given vertices in the plane. + * This header implements the functor for constructing Theta graphs. */ -#ifndef CGAL_THETA_GRAPH_2_H -#define CGAL_THETA_GRAPH_2_H +#ifndef CGAL_CONSTRUCT_THETA_GRAPH_2_H +#define CGAL_CONSTRUCT_THETA_GRAPH_2_H #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include - namespace CGAL { - /** - * \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 - class Theta_graph_2 : public Cone_spanners_2 - { - 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; +/*! \ingroup PkgConeBasedSpanners + + \brief A functor for constructing theta graphs with a given set of 2D points. + + \tparam Kernel_ The CGAL kernel used by this functor. If this parameter is + `CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt`, + the graph will be constructed exactly; otherwise, inexactly using an approximate PI=3.1415... - typedef Cone_spanners_2 base_class; - typedef typename base_class::Graph Graph; - typedef typename base_class::vertex_smaller_2 vertex_smaller_2; + \tparam Graph_ The graph type to store the constructed Theta graph. It should be a model of + 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. + So pls use `adjacency_list` to be your graph type. Note that there are seven template parameters for + `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 +class Construct_theta_graph_2 { - /** @brief constructs a Theta graph object. - * - * @param k Number of cones to divide space into - * @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 -//#else - template -//#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(k, start, end, ray0) - { - build_edges(); - } +public: + typedef Kernel_ kernel_type; + typedef Graph_ graph_type; - /** @brief copy constructor. - * @param x another Theta_graph_2 object to copy from. - */ - Theta_graph_2 (const Theta_graph_2& x) - : Cone_spanners_2(x) {} +private: + 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 Less_by_direction_2 Less_by_direction; - /** @brief This function implements the algorithm for adding edges to build the Theta graph. - * The algorithm implemented is described in - * 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. - * - * @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 + /* Store the number of cones. */ + unsigned int cone_number; - for (i = 0; i < this->num_cones; i++) { - j = (i+1) % this->num_cones; - add_edges_in_cone(this->rays[i], this->rays[j]); - } - return this->g; - } + /* Store the directions of the rays dividing the plane. The initial direction will be + * stored in rays[0]. + */ + std::vector rays; - /** @brief Construct edges in one cone bounded by two directions. - * - * @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"); - } +public: + /*! \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) ) - // Find angle bisector (requiring sqrt(), not exact) - Line_2 cwLine(ORIGIN, cwBound); - Line_2 ccwLine(ORIGIN, ccwBound); - Direction_2 bisectorDir = bisector(cwLine, ccwLine).direction(); - - // Rotational transformation of cw 90 degree - static const Transformation cw90( 0, 1, -1, 0); + { + if (k<2) { + std::cout << "The number of cones should be larger than 1!" << std::endl; + std::exit(1); + } - // Ordering - 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); - const vertex_smaller_2 orderMid(g, cw90(bisectorDir)); + 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 compute_cones; + // compute the rays using the functor + compute_cones(k, initial_direction, rays); + } - typename Graph::vertex_iterator vit, ve; - boost::tie(vit, ve) = boost::vertices(g); + /*! \brief Copy constructor. + * \param x another Construct_theta_graph_2 object to copy from. + */ + Construct_theta_graph_2 (const Construct_theta_graph_2& x) : cone_number(x.cone_number), rays(x.rays) {} - // Step 1: Sort S according to order induced by D1 - std::vector S(vit, ve); - std::sort(S.begin (), S.end (), orderD1); + /*! \brief Operator to construct a Theta graph. + * + * This operator implements the algorithm for adding edges to build the Theta graph. + * The algorithm implemented is described in: + * 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 + Graph_& operator()(const PointInputIterator& start, + const PointInputIterator& end, + Graph_& g) { - // Step 2: Initialise an empty set to store vertices sorted by orderD2 - typedef CGAL::ThetaDetail::Plane_Scan_Tree PSTree; - PSTree pst(orderD2, orderMid); + // 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& 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 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 PSTree; + PSTree pst(orderD2, orderMid); #ifndef NDEBUG #ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION - int i = 0; + int i = 0; #endif #endif - // Step 3: visit S in orderD1 - // * insert pi into T - // * ri = T.minAbove(pi) - for (typename std::vector::const_iterator - it = S.begin(); it != S.end(); ++it) { - pst.add(*it, *it); - const typename Graph::vertex_descriptor *const ri = pst.minAbove(*it); - if (NULL != ri) - boost::add_edge(*it, *ri, g); + // Step 3: visit S in orderD1 + // * insert pi into T + // * ri = T.minAbove(pi) + for (typename std::vector::const_iterator + it = S.begin(); it != S.end(); ++it) { + pst.add(*it, *it); + const typename Graph_::vertex_descriptor *const ri = pst.minAbove(*it); + if ( ri != NULL ) { + 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 #ifdef REALLY_VERBOSE_TREE_STATE_AFTER_EVERY_TREE_UPDATE__SAFE_TO_REMOVE_FOR_PRODUCTION @@ -180,50 +240,41 @@ namespace CGAL { // ...etc... // // The tree output shades the new value added, and states what action was taken. -std::cout << "graph Plane_Scan_Tree {" << std::endl << - pst << std::endl << std::endl; -int j = 1; -for (auto rit = S.rbegin(); rit <= it; ++rit) { - auto p = g[*rit]; - std::cout << "\t\"" << *rit << "\"[label=\"" << j++ << "\""; - if (rit == it) - std::cout << ",style=filled"; - std::cout << "];" << std::endl; -} + std::cout << "graph Plane_Scan_Tree {" << std::endl << + pst << std::endl << std::endl; + int j = 1; + for (auto rit = S.rbegin(); rit <= it; ++rit) { + auto p = g[*rit]; + std::cout << "\t\"" << *rit << "\"[label=\"" << j++ << "\""; + if (rit == it) + std::cout << ",style=filled"; + std::cout << "];" << std::endl; + } -if (pst.size() > 1) { - std::cout << "\t{rank=same;" << std::endl; - std::cout << "\"" << pst.begin()->first << "\""; - for (auto pit = ++(pst.begin()); pit != pst.end(); ++pit) { - std::cout << "--\"" << pit->first << "\""; - } - std::cout << "[color=white];" << std::endl; - std::cout << "rankdir=LR;" << std::endl; - std::cout << "}" << std::endl; -} + if (pst.size() > 1) { + std::cout << "\t{rank=same;" << std::endl; + std::cout << "\"" << pst.begin()->first << "\""; + for (auto pit = ++(pst.begin()); pit != pst.end(); ++pit) { + std::cout << "--\"" << pit->first << "\""; + } + std::cout << "[color=white];" << std::endl; + std::cout << "rankdir=LR;" << std::endl; + std::cout << "}" << std::endl; + } -std::cout << "\tlabel=\"" << ++i << ": Added (" << g[*it].x().to_double() << "," << g[*it].y().to_double() << ")."; -if (NULL != ri) - std::cout << " -- (" << g[*ri].x().to_double() << "," << g[*ri].y().to_double() << ")."; -std::cout << "\";" << std::endl; -std::cout << "\ttableloc=\"b\";" << std:: endl; -std::cout << "}" << std::endl << std::endl; + std::cout << "\tlabel=\"" << ++i << ": Added (" << g[*it].x().to_double() << "," << g[*it].y().to_double() << ")."; + if (NULL != ri) + std::cout << " -- (" << g[*ri].x().to_double() << "," << g[*ri].y().to_double() << ")."; + std::cout << "\";" << std::endl; + std::cout << "\ttableloc=\"b\";" << std:: endl; + std::cout << "}" << std::endl << std::endl; #endif #endif - } // end of for - }; // end of buildcone - -}; // class theta_graph + } // end of for + }; // end of add edges in cone +}; // 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& theta_graph); - - template < typename Kernel, typename Directedness, typename EdgeProperty > - std::ostream& operator<< (std::ostream& os, const Theta_graph_2& theta_graph); -*/ } // namespace CGAL diff --git a/Cone_spanners_2/include/CGAL/Construct_yao_graph_2.h b/Cone_spanners_2/include/CGAL/Construct_yao_graph_2.h index 679e683826f..cdd4291558f 100644 --- a/Cone_spanners_2/include/CGAL/Construct_yao_graph_2.h +++ b/Cone_spanners_2/include/CGAL/Construct_yao_graph_2.h @@ -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. // // This file is part of CGAL (www.cgal.org). @@ -14,187 +14,233 @@ // // $URL$ // $Id$ -// // -// Authors: Quincy Tse, Weisheng Si +// +// Authors: Weisheng Si, Quincy Tse -/** @file 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. - * +/*! \file Construct_yao_graph_2.h + * + * This header implements the functor for constructing Yao graphs. */ -#ifndef CGAL_YAO_GRAPH_2_H -#define CGAL_YAO_GRAPH_2_H +#ifndef CGAL_CONSTRUCT_YAO_GRAPH_2_H +#define CGAL_CONSTRUCT_YAO_GRAPH_2_H #include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include - namespace CGAL { - /** - * \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 - class Yao_graph_2 : public Cone_spanners_2 - { - public: - typedef typename Kernel::Direction_2 Direction_2; - typedef typename Kernel::Point_2 Point_2; - typedef typename Kernel::Aff_transformation_2 Transformation; +/*! \ingroup PkgConeBasedSpanners - typedef Cone_spanners_2 base_class; - typedef typename base_class::Graph Graph; - typedef typename base_class::vertex_smaller_2 vertex_smaller_2; + \brief A functor for constructing yao graphs with a given set of 2D points. - // a type for the set to store vertices sorted by a direction - typedef std::set pointSet; + \tparam Kernel_ The CGAL kernel used by this functor. If this parameter is + `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. - * - * @param k Number of cones to divide space into - * @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 arbitary direction of the first ray. - * (default: positive x-axis) - */ -//#ifdef GXX11 -// template -//#else - template -//#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(k, start, end, ray0) - { - build_edges(); - } + \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 + in BGL: `adjacency_list` and `adjacency_matrix`, only `adjacency_list` is such a model. + So pls use `adjacency_list` to be your graph type. Note that there are seven template parameters for + `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 +class Construct_yao_graph_2 { - /** @brief copy constructor - * @param x another `Yao_graph_2` object to copy from. - */ - Yao_graph_2 (const Yao_graph_2& x) - : Cone_spanners_2(x) {} +public: + typedef Kernel_ kernel_type; + typedef Graph_ graph_type; - /** @brief This function implements the algorithm for adding edges to build the Yao graph. - * - * The algorithm implemented is a slight adaptation to the algorithm for Theta graph described in - * Giri Narasimhan and Michiel Smid, Chapter 4: Spanners based on the Theta graph, Geometric Spanner Networks, - * Cambridge University Press, 2007. - * The adaptation lies in the way how the 'closest' node is searched. - * A binary tree search is not possible here, so the search here has complexity O(n), - * 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 +private: + typedef typename Kernel_::Direction_2 Direction_2; + typedef typename Kernel_::Point_2 Point_2; + typedef typename Kernel_::Line_2 Line_2; + typedef Less_by_direction_2 Less_by_direction; + // a type for the set to store vertices sorted by a direction + typedef std::set Point_set; - for (i = 0; i < this->num_cones; i++) { - j = (i+1) % this->num_cones; - add_edges_in_cone(this->rays[i], this->rays[j]); - } - return this->g; - } + /* Store the number of cones. */ + unsigned int cone_number; - /** @brief Construct edges bounded by two directions. - * - * @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. - * @return The updated underlying graph. - * - * @see G. Narasimhan and M. Smid, Geometric Spanner Networks: Cambridge - * University Press, 2007, - */ - 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"); + /* Store the directions of the rays dividing the plane. The initial direction will be + * stored in rays[0]. + */ + std::vector rays; + +public: + /*! \brief Constructor. + * + * Constructs a `Construct_yao_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_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 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 + 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& 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 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::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 - 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); + } // end of for - typename Graph::vertex_iterator vit, ve; - boost::tie(vit, ve) = boost::vertices(g); + }; // end of add edges in cone - // Step 1: Sort S according to order induced by D1 - std::vector S(vit, ve); - std::sort(S.begin (), S.end (), orderD1); - // Step 2: Initialise an empty set to store vertices sorted by orderD2 - pointSet pst(orderD2); + /* Functor for comparing Euclidean distances of two vertices in a graph g to a given vertex. + 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 - // * insert 'it' into T - // search the min in T - for (typename std::vector::const_iterator - it = S.begin(); it != S.end(); ++it) - { - Compare_Euclidean_Distance comp(g[*it], g); + // constructor + Less_euclidean_distance(const Point_2&p, const Graph_& g) : p(p), g(g) {} - pst.insert(*it); - // Find the last added node - O(logn) - typename pointSet::iterator it2 = pst.find(*it); - // Find minimum in tree from last ended node - O(n) - typename pointSet::iterator min = std::min_element(++it2, pst.end(), comp); - if (min != pst.end()) - boost::add_edge(*it, *min, g); - } + // operator + bool operator() (const typename Point_set::iterator::value_type& i, const typename Point_set::iterator::value_type& j) { + const Point_2& p1 = g[i]; + const Point_2& p2 = g[j]; + return has_smaller_distance_to_point(p, p1, p2); + } + }; - } +}; // 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& yao_graph); - - template < typename Kernel, typename Directedness, typename EdgeProperty > - std::ostream& operator<< (std::ostream& os, const Yao_graph_2& yao_graph); - -*/ } // namespace CGAL