1 // Copyright 2004 The Trustees of Indiana University.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  Authors: Jeremiah Willcock
8 //           Douglas Gregor
9 //           Andrew Lumsdaine
10 #ifndef BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP
11 #define BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP
12 
13 // Gursoy-Atun graph layout, based on:
14 // "Neighbourhood Preserving Load Balancing: A Self-Organizing Approach"
15 // in EuroPar 2000, p. 234 of LNCS 1900
16 // http://springerlink.metapress.com/link.asp?id=pcu07ew5rhexp9yt
17 
18 #include <cmath>
19 #include <vector>
20 #include <exception>
21 #include <algorithm>
22 
23 #include <boost/graph/visitors.hpp>
24 #include <boost/graph/properties.hpp>
25 #include <boost/random/uniform_01.hpp>
26 #include <boost/random/linear_congruential.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <boost/graph/breadth_first_search.hpp>
29 #include <boost/graph/dijkstra_shortest_paths.hpp>
30 #include <boost/graph/named_function_params.hpp>
31 
32 namespace boost {
33 
34 namespace detail {
35 
36 struct over_distance_limit : public std::exception {};
37 
38 template <typename PositionMap, typename NodeDistanceMap,  typename Topology,
39           typename Graph>
40 struct update_position_visitor {
41   typedef typename Topology::point_type Point;
42   PositionMap position_map;
43   NodeDistanceMap node_distance;
44   const Topology& space;
45   Point input_vector;
46   double distance_limit;
47   double learning_constant;
48   double falloff_ratio;
49 
50   typedef boost::on_examine_vertex event_filter;
51 
52   typedef typename graph_traits<Graph>::vertex_descriptor
53     vertex_descriptor;
54 
update_position_visitorboost::detail::update_position_visitor55   update_position_visitor(PositionMap position_map,
56                           NodeDistanceMap node_distance,
57                           const Topology& space,
58                           const Point& input_vector,
59                           double distance_limit,
60                           double learning_constant,
61                           double falloff_ratio):
62     position_map(position_map), node_distance(node_distance),
63     space(space),
64     input_vector(input_vector), distance_limit(distance_limit),
65     learning_constant(learning_constant), falloff_ratio(falloff_ratio) {}
66 
operator ()boost::detail::update_position_visitor67   void operator()(vertex_descriptor v, const Graph&) const
68   {
69 #ifndef BOOST_NO_STDC_NAMESPACE
70     using std::pow;
71 #endif
72 
73     if (get(node_distance, v) > distance_limit)
74       throw over_distance_limit();
75     Point old_position = get(position_map, v);
76     double distance = get(node_distance, v);
77     double fraction =
78       learning_constant * pow(falloff_ratio, distance * distance);
79     put(position_map, v,
80         space.move_position_toward(old_position, fraction, input_vector));
81   }
82 };
83 
84 template<typename EdgeWeightMap>
85 struct gursoy_shortest
86 {
87   template<typename Graph, typename NodeDistanceMap, typename UpdatePosition>
88   static inline void
runboost::detail::gursoy_shortest89   run(const Graph& g, typename graph_traits<Graph>::vertex_descriptor s,
90       NodeDistanceMap node_distance,  UpdatePosition& update_position,
91       EdgeWeightMap weight)
92   {
93     boost::dijkstra_shortest_paths(g, s, weight_map(weight).
94       visitor(boost::make_dijkstra_visitor(std::make_pair(
95        boost::record_distances(node_distance, boost::on_edge_relaxed()),
96         update_position))));
97   }
98 };
99 
100 template<>
101 struct gursoy_shortest<dummy_property_map>
102 {
103   template<typename Graph, typename NodeDistanceMap, typename UpdatePosition>
104   static inline void
runboost::detail::gursoy_shortest105   run(const Graph& g, typename graph_traits<Graph>::vertex_descriptor s,
106       NodeDistanceMap node_distance,  UpdatePosition& update_position,
107       dummy_property_map)
108   {
109     boost::breadth_first_search(g, s,
110       visitor(boost::make_bfs_visitor(std::make_pair(
111         boost::record_distances(node_distance, boost::on_tree_edge()),
112         update_position))));
113   }
114 };
115 
116 } // namespace detail
117 
118 template <typename VertexListAndIncidenceGraph,  typename Topology,
119           typename PositionMap, typename Diameter, typename VertexIndexMap,
120           typename EdgeWeightMap>
121 void
gursoy_atun_step(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,Diameter diameter,double learning_constant,VertexIndexMap vertex_index_map,EdgeWeightMap weight)122 gursoy_atun_step
123   (const VertexListAndIncidenceGraph& graph,
124    const Topology& space,
125    PositionMap position,
126    Diameter diameter,
127    double learning_constant,
128    VertexIndexMap vertex_index_map,
129    EdgeWeightMap weight)
130 {
131 #ifndef BOOST_NO_STDC_NAMESPACE
132   using std::pow;
133   using std::exp;
134 #endif
135 
136   typedef typename graph_traits<VertexListAndIncidenceGraph>::vertex_iterator
137     vertex_iterator;
138   typedef typename graph_traits<VertexListAndIncidenceGraph>::vertex_descriptor
139     vertex_descriptor;
140   typedef typename Topology::point_type point_type;
141   vertex_iterator i, iend;
142   std::vector<double> distance_from_input_vector(num_vertices(graph));
143   typedef boost::iterator_property_map<std::vector<double>::iterator,
144                                        VertexIndexMap,
145                                        double, double&>
146     DistanceFromInputMap;
147   DistanceFromInputMap distance_from_input(distance_from_input_vector.begin(),
148                                            vertex_index_map);
149   std::vector<double> node_distance_map_vector(num_vertices(graph));
150   typedef boost::iterator_property_map<std::vector<double>::iterator,
151                                        VertexIndexMap,
152                                        double, double&>
153     NodeDistanceMap;
154   NodeDistanceMap node_distance(node_distance_map_vector.begin(),
155                                 vertex_index_map);
156   point_type input_vector = space.random_point();
157   vertex_descriptor min_distance_loc
158     = graph_traits<VertexListAndIncidenceGraph>::null_vertex();
159   double min_distance = 0.0;
160   bool min_distance_unset = true;
161   for (boost::tie(i, iend) = vertices(graph); i != iend; ++i) {
162     double this_distance = space.distance(get(position, *i), input_vector);
163     put(distance_from_input, *i, this_distance);
164     if (min_distance_unset || this_distance < min_distance) {
165       min_distance = this_distance;
166       min_distance_loc = *i;
167     }
168     min_distance_unset = false;
169   }
170   assert (!min_distance_unset); // Graph must have at least one vertex
171   boost::detail::update_position_visitor<
172       PositionMap, NodeDistanceMap, Topology,
173       VertexListAndIncidenceGraph>
174     update_position(position, node_distance, space,
175                     input_vector, diameter, learning_constant,
176                     exp(-1. / (2 * diameter * diameter)));
177   std::fill(node_distance_map_vector.begin(), node_distance_map_vector.end(), 0);
178   try {
179     typedef detail::gursoy_shortest<EdgeWeightMap> shortest;
180     shortest::run(graph, min_distance_loc, node_distance, update_position,
181                   weight);
182   } catch (detail::over_distance_limit) {
183     /* Thrown to break out of BFS or Dijkstra early */
184   }
185 }
186 
187 template <typename VertexListAndIncidenceGraph,  typename Topology,
188           typename PositionMap, typename VertexIndexMap,
189           typename EdgeWeightMap>
gursoy_atun_refine(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,int nsteps,double diameter_initial,double diameter_final,double learning_constant_initial,double learning_constant_final,VertexIndexMap vertex_index_map,EdgeWeightMap weight)190 void gursoy_atun_refine(const VertexListAndIncidenceGraph& graph,
191                         const Topology& space,
192                         PositionMap position,
193                         int nsteps,
194                         double diameter_initial,
195                         double diameter_final,
196                         double learning_constant_initial,
197                         double learning_constant_final,
198                         VertexIndexMap vertex_index_map,
199                         EdgeWeightMap weight)
200 {
201 #ifndef BOOST_NO_STDC_NAMESPACE
202   using std::pow;
203   using std::exp;
204 #endif
205 
206   typedef typename graph_traits<VertexListAndIncidenceGraph>::vertex_iterator
207     vertex_iterator;
208   typedef typename graph_traits<VertexListAndIncidenceGraph>::vertex_descriptor
209     vertex_descriptor;
210   typedef typename Topology::point_type point_type;
211   vertex_iterator i, iend;
212   double diameter_ratio = (double)diameter_final / diameter_initial;
213   double learning_constant_ratio =
214     learning_constant_final / learning_constant_initial;
215   std::vector<double> distance_from_input_vector(num_vertices(graph));
216   typedef boost::iterator_property_map<std::vector<double>::iterator,
217                                        VertexIndexMap,
218                                        double, double&>
219     DistanceFromInputMap;
220   DistanceFromInputMap distance_from_input(distance_from_input_vector.begin(),
221                                            vertex_index_map);
222   std::vector<int> node_distance_map_vector(num_vertices(graph));
223   typedef boost::iterator_property_map<std::vector<int>::iterator,
224                                        VertexIndexMap, double, double&>
225     NodeDistanceMap;
226   NodeDistanceMap node_distance(node_distance_map_vector.begin(),
227                                 vertex_index_map);
228   for (int round = 0; round < nsteps; ++round) {
229     double part_done = (double)round / (nsteps - 1);
230     int diameter = (int)(diameter_initial * pow(diameter_ratio, part_done));
231     double learning_constant =
232       learning_constant_initial * pow(learning_constant_ratio, part_done);
233     gursoy_atun_step(graph, space, position, diameter, learning_constant,
234                      vertex_index_map, weight);
235   }
236 }
237 
238 template <typename VertexListAndIncidenceGraph,  typename Topology,
239           typename PositionMap, typename VertexIndexMap,
240           typename EdgeWeightMap>
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,int nsteps,double diameter_initial,double diameter_final,double learning_constant_initial,double learning_constant_final,VertexIndexMap vertex_index_map,EdgeWeightMap weight)241 void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
242                         const Topology& space,
243                         PositionMap position,
244                         int nsteps,
245                         double diameter_initial,
246                         double diameter_final,
247                         double learning_constant_initial,
248                         double learning_constant_final,
249                         VertexIndexMap vertex_index_map,
250                         EdgeWeightMap weight)
251 {
252   typedef typename graph_traits<VertexListAndIncidenceGraph>::vertex_iterator
253     vertex_iterator;
254   vertex_iterator i, iend;
255   for (boost::tie(i, iend) = vertices(graph); i != iend; ++i) {
256     put(position, *i, space.random_point());
257   }
258   gursoy_atun_refine(graph, space,
259                      position, nsteps,
260                      diameter_initial, diameter_final,
261                      learning_constant_initial, learning_constant_final,
262                      vertex_index_map, weight);
263 }
264 
265 template <typename VertexListAndIncidenceGraph,  typename Topology,
266           typename PositionMap, typename VertexIndexMap>
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,int nsteps,double diameter_initial,double diameter_final,double learning_constant_initial,double learning_constant_final,VertexIndexMap vertex_index_map)267 void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
268                         const Topology& space,
269                         PositionMap position,
270                         int nsteps,
271                         double diameter_initial,
272                         double diameter_final,
273                         double learning_constant_initial,
274                         double learning_constant_final,
275                         VertexIndexMap vertex_index_map)
276 {
277   gursoy_atun_layout(graph, space, position, nsteps,
278                      diameter_initial, diameter_final,
279                      learning_constant_initial, learning_constant_final,
280                      vertex_index_map, dummy_property_map());
281 }
282 
283 template <typename VertexListAndIncidenceGraph, typename Topology,
284           typename PositionMap>
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,int nsteps,double diameter_initial,double diameter_final=1.0,double learning_constant_initial=0.8,double learning_constant_final=0.2)285 void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
286                         const Topology& space,
287                         PositionMap position,
288                         int nsteps,
289                         double diameter_initial,
290                         double diameter_final = 1.0,
291                         double learning_constant_initial = 0.8,
292                         double learning_constant_final = 0.2)
293 {
294   gursoy_atun_layout(graph, space, position, nsteps, diameter_initial,
295                      diameter_final, learning_constant_initial,
296                      learning_constant_final, get(vertex_index, graph));
297 }
298 
299 template <typename VertexListAndIncidenceGraph, typename Topology,
300           typename PositionMap>
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,int nsteps)301 void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
302                         const Topology& space,
303                         PositionMap position,
304                         int nsteps)
305 {
306 #ifndef BOOST_NO_STDC_NAMESPACE
307   using std::sqrt;
308 #endif
309 
310   gursoy_atun_layout(graph, space, position, nsteps,
311                      sqrt((double)num_vertices(graph)));
312 }
313 
314 template <typename VertexListAndIncidenceGraph, typename Topology,
315           typename PositionMap>
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position)316 void gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
317                         const Topology& space,
318                         PositionMap position)
319 {
320   gursoy_atun_layout(graph, space, position, num_vertices(graph));
321 }
322 
323 template<typename VertexListAndIncidenceGraph, typename Topology,
324          typename PositionMap, typename P, typename T, typename R>
325 void
gursoy_atun_layout(const VertexListAndIncidenceGraph & graph,const Topology & space,PositionMap position,const bgl_named_params<P,T,R> & params)326 gursoy_atun_layout(const VertexListAndIncidenceGraph& graph,
327                    const Topology& space,
328                    PositionMap position,
329                    const bgl_named_params<P,T,R>& params)
330 {
331 #ifndef BOOST_NO_STDC_NAMESPACE
332   using std::sqrt;
333 #endif
334 
335   std::pair<double, double> diam(sqrt(double(num_vertices(graph))), 1.0);
336   std::pair<double, double> learn(0.8, 0.2);
337   gursoy_atun_layout(graph, space, position,
338                      choose_param(get_param(params, iterations_t()),
339                                   num_vertices(graph)),
340                      choose_param(get_param(params, diameter_range_t()),
341                                   diam).first,
342                      choose_param(get_param(params, diameter_range_t()),
343                                   diam).second,
344                      choose_param(get_param(params, learning_constant_range_t()),
345                                   learn).first,
346                      choose_param(get_param(params, learning_constant_range_t()),
347                                   learn).second,
348                      choose_const_pmap(get_param(params, vertex_index), graph,
349                                        vertex_index),
350                      choose_param(get_param(params, edge_weight),
351                                   dummy_property_map()));
352 }
353 
354 /***********************************************************
355  * Topologies                                              *
356  ***********************************************************/
357 template<std::size_t Dims>
358 class convex_topology
359 {
360   struct point
361   {
pointboost::convex_topology::point362     point() { }
operator []boost::convex_topology::point363     double& operator[](std::size_t i) {return values[i];}
operator []boost::convex_topology::point364     const double& operator[](std::size_t i) const {return values[i];}
365 
366   private:
367     double values[Dims];
368   };
369 
370  public:
371   typedef point point_type;
372 
distance(point a,point b) const373   double distance(point a, point b) const
374   {
375     double dist = 0;
376     for (std::size_t i = 0; i < Dims; ++i) {
377       double diff = b[i] - a[i];
378       dist += diff * diff;
379     }
380     // Exact properties of the distance are not important, as long as
381     // < on what this returns matches real distances
382     return dist;
383   }
384 
move_position_toward(point a,double fraction,point b) const385   point move_position_toward(point a, double fraction, point b) const
386   {
387     point result;
388     for (std::size_t i = 0; i < Dims; ++i)
389       result[i] = a[i] + (b[i] - a[i]) * fraction;
390     return result;
391   }
392 };
393 
394 template<std::size_t Dims,
395          typename RandomNumberGenerator = minstd_rand>
396 class hypercube_topology : public convex_topology<Dims>
397 {
398   typedef uniform_01<RandomNumberGenerator, double> rand_t;
399 
400  public:
401   typedef typename convex_topology<Dims>::point_type point_type;
402 
hypercube_topology(double scaling=1.0)403   explicit hypercube_topology(double scaling = 1.0)
404     : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)),
405       scaling(scaling)
406   { }
407 
hypercube_topology(RandomNumberGenerator & gen,double scaling=1.0)408   hypercube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
409     : gen_ptr(), rand(new rand_t(gen)), scaling(scaling) { }
410 
random_point() const411   point_type random_point() const
412   {
413     point_type p;
414     for (std::size_t i = 0; i < Dims; ++i)
415       p[i] = (*rand)() * scaling;
416     return p;
417   }
418 
419  private:
420   shared_ptr<RandomNumberGenerator> gen_ptr;
421   shared_ptr<rand_t> rand;
422   double scaling;
423 };
424 
425 template<typename RandomNumberGenerator = minstd_rand>
426 class square_topology : public hypercube_topology<2, RandomNumberGenerator>
427 {
428   typedef hypercube_topology<2, RandomNumberGenerator> inherited;
429 
430  public:
square_topology(double scaling=1.0)431   explicit square_topology(double scaling = 1.0) : inherited(scaling) { }
432 
square_topology(RandomNumberGenerator & gen,double scaling=1.0)433   square_topology(RandomNumberGenerator& gen, double scaling = 1.0)
434     : inherited(gen, scaling) { }
435 };
436 
437 template<typename RandomNumberGenerator = minstd_rand>
438 class cube_topology : public hypercube_topology<3, RandomNumberGenerator>
439 {
440   typedef hypercube_topology<3, RandomNumberGenerator> inherited;
441 
442  public:
cube_topology(double scaling=1.0)443   explicit cube_topology(double scaling = 1.0) : inherited(scaling) { }
444 
cube_topology(RandomNumberGenerator & gen,double scaling=1.0)445   cube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
446     : inherited(gen, scaling) { }
447 };
448 
449 template<std::size_t Dims,
450          typename RandomNumberGenerator = minstd_rand>
451 class ball_topology : public convex_topology<Dims>
452 {
453   typedef uniform_01<RandomNumberGenerator, double> rand_t;
454 
455  public:
456   typedef typename convex_topology<Dims>::point_type point_type;
457 
ball_topology(double radius=1.0)458   explicit ball_topology(double radius = 1.0)
459     : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)),
460       radius(radius)
461   { }
462 
ball_topology(RandomNumberGenerator & gen,double radius=1.0)463   ball_topology(RandomNumberGenerator& gen, double radius = 1.0)
464     : gen_ptr(), rand(new rand_t(gen)), radius(radius) { }
465 
random_point() const466   point_type random_point() const
467   {
468     point_type p;
469     double dist_sum;
470     do {
471       dist_sum = 0.0;
472       for (std::size_t i = 0; i < Dims; ++i) {
473         double x = (*rand)() * 2*radius - radius;
474         p[i] = x;
475         dist_sum += x * x;
476       }
477     } while (dist_sum > radius*radius);
478     return p;
479   }
480 
481  private:
482   shared_ptr<RandomNumberGenerator> gen_ptr;
483   shared_ptr<rand_t> rand;
484   double radius;
485 };
486 
487 template<typename RandomNumberGenerator = minstd_rand>
488 class circle_topology : public ball_topology<2, RandomNumberGenerator>
489 {
490   typedef ball_topology<2, RandomNumberGenerator> inherited;
491 
492  public:
circle_topology(double radius=1.0)493   explicit circle_topology(double radius = 1.0) : inherited(radius) { }
494 
circle_topology(RandomNumberGenerator & gen,double radius=1.0)495   circle_topology(RandomNumberGenerator& gen, double radius = 1.0)
496     : inherited(gen, radius) { }
497 };
498 
499 template<typename RandomNumberGenerator = minstd_rand>
500 class sphere_topology : public ball_topology<3, RandomNumberGenerator>
501 {
502   typedef ball_topology<3, RandomNumberGenerator> inherited;
503 
504  public:
sphere_topology(double radius=1.0)505   explicit sphere_topology(double radius = 1.0) : inherited(radius) { }
506 
sphere_topology(RandomNumberGenerator & gen,double radius=1.0)507   sphere_topology(RandomNumberGenerator& gen, double radius = 1.0)
508     : inherited(gen, radius) { }
509 };
510 
511 template<typename RandomNumberGenerator = minstd_rand>
512 class heart_topology
513 {
514   // Heart is defined as the union of three shapes:
515   // Square w/ corners (+-1000, -1000), (0, 0), (0, -2000)
516   // Circle centered at (-500, -500) radius 500*sqrt(2)
517   // Circle centered at (500, -500) radius 500*sqrt(2)
518   // Bounding box (-1000, -2000) - (1000, 500*(sqrt(2) - 1))
519 
520   struct point
521   {
pointboost::heart_topology::point522     point() { values[0] = 0.0; values[1] = 0.0; }
pointboost::heart_topology::point523     point(double x, double y) { values[0] = x; values[1] = y; }
524 
operator []boost::heart_topology::point525     double& operator[](std::size_t i)       { return values[i]; }
operator []boost::heart_topology::point526     double  operator[](std::size_t i) const { return values[i]; }
527 
528   private:
529     double values[2];
530   };
531 
in_heart(point p) const532   bool in_heart(point p) const
533   {
534 #ifndef BOOST_NO_STDC_NAMESPACE
535     using std::abs;
536     using std::pow;
537 #endif
538 
539     if (p[1] < abs(p[0]) - 2000) return false; // Bottom
540     if (p[1] <= -1000) return true; // Diagonal of square
541     if (pow(p[0] - -500, 2) + pow(p[1] - -500, 2) <= 500000)
542       return true; // Left circle
543     if (pow(p[0] - 500, 2) + pow(p[1] - -500, 2) <= 500000)
544       return true; // Right circle
545     return false;
546   }
547 
segment_within_heart(point p1,point p2) const548   bool segment_within_heart(point p1, point p2) const
549   {
550     // Assumes that p1 and p2 are within the heart
551     if ((p1[0] < 0) == (p2[0] < 0)) return true; // Same side of symmetry line
552     if (p1[0] == p2[0]) return true; // Vertical
553     double slope = (p2[1] - p1[1]) / (p2[0] - p1[0]);
554     double intercept = p1[1] - p1[0] * slope;
555     if (intercept > 0) return false; // Crosses between circles
556     return true;
557   }
558 
559   typedef uniform_01<RandomNumberGenerator, double> rand_t;
560 
561  public:
562   typedef point point_type;
563 
heart_topology()564   heart_topology()
565     : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)) { }
566 
heart_topology(RandomNumberGenerator & gen)567   heart_topology(RandomNumberGenerator& gen)
568     : gen_ptr(), rand(new rand_t(gen)) { }
569 
random_point() const570   point random_point() const
571   {
572 #ifndef BOOST_NO_STDC_NAMESPACE
573     using std::sqrt;
574 #endif
575 
576     point result;
577     double sqrt2 = sqrt(2.);
578     do {
579       result[0] = (*rand)() * (1000 + 1000 * sqrt2) - (500 + 500 * sqrt2);
580       result[1] = (*rand)() * (2000 + 500 * (sqrt2 - 1)) - 2000;
581     } while (!in_heart(result));
582     return result;
583   }
584 
distance(point a,point b) const585   double distance(point a, point b) const
586   {
587 #ifndef BOOST_NO_STDC_NAMESPACE
588     using std::sqrt;
589 #endif
590     if (segment_within_heart(a, b)) {
591       // Straight line
592       return sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]));
593     } else {
594       // Straight line bending around (0, 0)
595       return sqrt(a[0] * a[0] + a[1] * a[1]) + sqrt(b[0] * b[0] + b[1] * b[1]);
596     }
597   }
598 
move_position_toward(point a,double fraction,point b) const599   point move_position_toward(point a, double fraction, point b) const
600   {
601 #ifndef BOOST_NO_STDC_NAMESPACE
602     using std::sqrt;
603 #endif
604 
605     if (segment_within_heart(a, b)) {
606       // Straight line
607       return point(a[0] + (b[0] - a[0]) * fraction,
608                    a[1] + (b[1] - a[1]) * fraction);
609     } else {
610       double distance_to_point_a = sqrt(a[0] * a[0] + a[1] * a[1]);
611       double distance_to_point_b = sqrt(b[0] * b[0] + b[1] * b[1]);
612       double location_of_point = distance_to_point_a /
613                                    (distance_to_point_a + distance_to_point_b);
614       if (fraction < location_of_point)
615         return point(a[0] * (1 - fraction / location_of_point),
616                      a[1] * (1 - fraction / location_of_point));
617       else
618         return point(
619           b[0] * ((fraction - location_of_point) / (1 - location_of_point)),
620           b[1] * ((fraction - location_of_point) / (1 - location_of_point)));
621     }
622   }
623 
624  private:
625   shared_ptr<RandomNumberGenerator> gen_ptr;
626   shared_ptr<rand_t> rand;
627 };
628 
629 } // namespace boost
630 
631 #endif // BOOST_GRAPH_GURSOY_ATUN_LAYOUT_HPP
632