#### /Src/Dependencies/Boost/boost/graph/topology.hpp

C++ Header | 598 lines | 480 code | 92 blank | 26 comment | 50 complexity | 4c7dcc80fe97d97dc0f586ab57c77328 MD5 | raw file
```  1// Copyright 2009 The Trustees of Indiana University.
2
4// (See accompanying file LICENSE_1_0.txt or copy at
6
7//  Authors: Jeremiah Willcock
8//           Douglas Gregor
9//           Andrew Lumsdaine
10#ifndef BOOST_GRAPH_TOPOLOGY_HPP
11#define BOOST_GRAPH_TOPOLOGY_HPP
12
13#include <boost/config/no_tr1/cmath.hpp>
14#include <cmath>
15#include <boost/random/uniform_01.hpp>
16#include <boost/random/linear_congruential.hpp>
17#include <boost/math/constants/constants.hpp> // For root_two
18#include <boost/algorithm/minmax.hpp>
19#include <boost/config.hpp> // For BOOST_STATIC_CONSTANT
20#include <boost/math/special_functions/hypot.hpp>
21
22// Classes and concepts to represent points in a space, with distance and move
23// operations (used for Gurson-Atun layout), plus other things like bounding
24// boxes used for other layout algorithms.
25
26namespace boost {
27
28/***********************************************************
29 * Topologies                                              *
30 ***********************************************************/
31template<std::size_t Dims>
32class convex_topology
33{
34  public: // For VisualAge C++
35  struct point
36  {
37    BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims);
38    point() { }
39    double& operator[](std::size_t i) {return values[i];}
40    const double& operator[](std::size_t i) const {return values[i];}
41
42  private:
43    double values[Dims];
44  };
45
46  public: // For VisualAge C++
47  struct point_difference
48  {
49    BOOST_STATIC_CONSTANT(std::size_t, dimensions = Dims);
50    point_difference() {
51      for (std::size_t i = 0; i < Dims; ++i) values[i] = 0.;
52    }
53    double& operator[](std::size_t i) {return values[i];}
54    const double& operator[](std::size_t i) const {return values[i];}
55
56    friend point_difference operator+(const point_difference& a, const point_difference& b) {
57      point_difference result;
58      for (std::size_t i = 0; i < Dims; ++i)
59        result[i] = a[i] + b[i];
60      return result;
61    }
62
63    friend point_difference& operator+=(point_difference& a, const point_difference& b) {
64      for (std::size_t i = 0; i < Dims; ++i)
65        a[i] += b[i];
66      return a;
67    }
68
69    friend point_difference operator-(const point_difference& a) {
70      point_difference result;
71      for (std::size_t i = 0; i < Dims; ++i)
72        result[i] = -a[i];
73      return result;
74    }
75
76    friend point_difference operator-(const point_difference& a, const point_difference& b) {
77      point_difference result;
78      for (std::size_t i = 0; i < Dims; ++i)
79        result[i] = a[i] - b[i];
80      return result;
81    }
82
83    friend point_difference& operator-=(point_difference& a, const point_difference& b) {
84      for (std::size_t i = 0; i < Dims; ++i)
85        a[i] -= b[i];
86      return a;
87    }
88
89    friend point_difference operator*(const point_difference& a, const point_difference& b) {
90      point_difference result;
91      for (std::size_t i = 0; i < Dims; ++i)
92        result[i] = a[i] * b[i];
93      return result;
94    }
95
96    friend point_difference operator*(const point_difference& a, double b) {
97      point_difference result;
98      for (std::size_t i = 0; i < Dims; ++i)
99        result[i] = a[i] * b;
100      return result;
101    }
102
103    friend point_difference operator*(double a, const point_difference& b) {
104      point_difference result;
105      for (std::size_t i = 0; i < Dims; ++i)
106        result[i] = a * b[i];
107      return result;
108    }
109
110    friend point_difference operator/(const point_difference& a, const point_difference& b) {
111      point_difference result;
112      for (std::size_t i = 0; i < Dims; ++i)
113        result[i] = (b[i] == 0.) ? 0. : a[i] / b[i];
114      return result;
115    }
116
117    friend double dot(const point_difference& a, const point_difference& b) {
118      double result = 0;
119      for (std::size_t i = 0; i < Dims; ++i)
120        result += a[i] * b[i];
121      return result;
122    }
123
124  private:
125    double values[Dims];
126  };
127
128 public:
129  typedef point point_type;
130  typedef point_difference point_difference_type;
131
132  double distance(point a, point b) const
133  {
134    double dist = 0.;
135    for (std::size_t i = 0; i < Dims; ++i) {
136      double diff = b[i] - a[i];
137      dist = boost::math::hypot(dist, diff);
138    }
139    // Exact properties of the distance are not important, as long as
140    // < on what this returns matches real distances; l_2 is used because
141    // Fruchterman-Reingold also uses this code and it relies on l_2.
142    return dist;
143  }
144
145  point move_position_toward(point a, double fraction, point b) const
146  {
147    point result;
148    for (std::size_t i = 0; i < Dims; ++i)
149      result[i] = a[i] + (b[i] - a[i]) * fraction;
150    return result;
151  }
152
153  point_difference difference(point a, point b) const {
154    point_difference result;
155    for (std::size_t i = 0; i < Dims; ++i)
156      result[i] = a[i] - b[i];
157    return result;
158  }
159
160  point adjust(point a, point_difference delta) const {
161    point result;
162    for (std::size_t i = 0; i < Dims; ++i)
163      result[i] = a[i] + delta[i];
164    return result;
165  }
166
167  point pointwise_min(point a, point b) const {
168    BOOST_USING_STD_MIN();
169    point result;
170    for (std::size_t i = 0; i < Dims; ++i)
171      result[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION (a[i], b[i]);
172    return result;
173  }
174
175  point pointwise_max(point a, point b) const {
176    BOOST_USING_STD_MAX();
177    point result;
178    for (std::size_t i = 0; i < Dims; ++i)
179      result[i] = max BOOST_PREVENT_MACRO_SUBSTITUTION (a[i], b[i]);
180    return result;
181  }
182
183  double norm(point_difference delta) const {
184    double n = 0.;
185    for (std::size_t i = 0; i < Dims; ++i)
186      n = boost::math::hypot(n, delta[i]);
187    return n;
188  }
189
190  double volume(point_difference delta) const {
191    double n = 1.;
192    for (std::size_t i = 0; i < Dims; ++i)
193      n *= delta[i];
194    return n;
195  }
196
197};
198
199template<std::size_t Dims,
200         typename RandomNumberGenerator = minstd_rand>
201class hypercube_topology : public convex_topology<Dims>
202{
203  typedef uniform_01<RandomNumberGenerator, double> rand_t;
204
205 public:
206  typedef typename convex_topology<Dims>::point_type point_type;
207  typedef typename convex_topology<Dims>::point_difference_type point_difference_type;
208
209  explicit hypercube_topology(double scaling = 1.0)
210    : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)),
211      scaling(scaling)
212  { }
213
214  hypercube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
215    : gen_ptr(), rand(new rand_t(gen)), scaling(scaling) { }
216
217  point_type random_point() const
218  {
219    point_type p;
220    for (std::size_t i = 0; i < Dims; ++i)
221      p[i] = (*rand)() * scaling;
222    return p;
223  }
224
225  point_type bound(point_type a) const
226  {
227    BOOST_USING_STD_MIN();
228    BOOST_USING_STD_MAX();
229    point_type p;
230    for (std::size_t i = 0; i < Dims; ++i)
231      p[i] = min BOOST_PREVENT_MACRO_SUBSTITUTION (scaling, max BOOST_PREVENT_MACRO_SUBSTITUTION (-scaling, a[i]));
232    return p;
233  }
234
235  double distance_from_boundary(point_type a) const
236  {
237    BOOST_USING_STD_MIN();
238    BOOST_USING_STD_MAX();
239#ifndef BOOST_NO_STDC_NAMESPACE
240    using std::abs;
241#endif
242    BOOST_STATIC_ASSERT (Dims >= 1);
243    double dist = abs(scaling - a[0]);
244    for (std::size_t i = 1; i < Dims; ++i)
245      dist = min BOOST_PREVENT_MACRO_SUBSTITUTION (dist, abs(scaling - a[i]));
246    return dist;
247  }
248
249  point_type center() const {
250    point_type result;
251    for (std::size_t i = 0; i < Dims; ++i)
252      result[i] = scaling * .5;
253    return result;
254  }
255
256  point_type origin() const {
257    point_type result;
258    for (std::size_t i = 0; i < Dims; ++i)
259      result[i] = 0;
260    return result;
261  }
262
263  point_difference_type extent() const {
264    point_difference_type result;
265    for (std::size_t i = 0; i < Dims; ++i)
266      result[i] = scaling;
267    return result;
268  }
269
270 private:
271  shared_ptr<RandomNumberGenerator> gen_ptr;
272  shared_ptr<rand_t> rand;
273  double scaling;
274};
275
276template<typename RandomNumberGenerator = minstd_rand>
277class square_topology : public hypercube_topology<2, RandomNumberGenerator>
278{
279  typedef hypercube_topology<2, RandomNumberGenerator> inherited;
280
281 public:
282  explicit square_topology(double scaling = 1.0) : inherited(scaling) { }
283
284  square_topology(RandomNumberGenerator& gen, double scaling = 1.0)
285    : inherited(gen, scaling) { }
286};
287
288template<typename RandomNumberGenerator = minstd_rand>
289class rectangle_topology : public convex_topology<2>
290{
291  typedef uniform_01<RandomNumberGenerator, double> rand_t;
292
293  public:
294  rectangle_topology(double left, double top, double right, double bottom)
295    : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)),
296      left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION (left, right)),
297      top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION (top, bottom)),
298      right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION (left, right)),
299      bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION (top, bottom)) { }
300
301  rectangle_topology(RandomNumberGenerator& gen, double left, double top, double right, double bottom)
302    : gen_ptr(), rand(new rand_t(gen)),
303      left(std::min BOOST_PREVENT_MACRO_SUBSTITUTION (left, right)),
304      top(std::min BOOST_PREVENT_MACRO_SUBSTITUTION (top, bottom)),
305      right(std::max BOOST_PREVENT_MACRO_SUBSTITUTION (left, right)),
306      bottom(std::max BOOST_PREVENT_MACRO_SUBSTITUTION (top, bottom)) { }
307
308  typedef typename convex_topology<2>::point_type point_type;
309  typedef typename convex_topology<2>::point_difference_type point_difference_type;
310
311  point_type random_point() const
312  {
313    point_type p;
314    p[0] = (*rand)() * (right - left) + left;
315    p[1] = (*rand)() * (bottom - top) + top;
316    return p;
317  }
318
319  point_type bound(point_type a) const
320  {
321    BOOST_USING_STD_MIN();
322    BOOST_USING_STD_MAX();
323    point_type p;
324    p[0] = min BOOST_PREVENT_MACRO_SUBSTITUTION (right, max BOOST_PREVENT_MACRO_SUBSTITUTION (left, a[0]));
325    p[1] = min BOOST_PREVENT_MACRO_SUBSTITUTION (bottom, max BOOST_PREVENT_MACRO_SUBSTITUTION (top, a[1]));
326    return p;
327  }
328
329  double distance_from_boundary(point_type a) const
330  {
331    BOOST_USING_STD_MIN();
332    BOOST_USING_STD_MAX();
333#ifndef BOOST_NO_STDC_NAMESPACE
334    using std::abs;
335#endif
336    double dist = abs(left - a[0]);
337    dist = min BOOST_PREVENT_MACRO_SUBSTITUTION (dist, abs(right - a[0]));
338    dist = min BOOST_PREVENT_MACRO_SUBSTITUTION (dist, abs(top - a[1]));
339    dist = min BOOST_PREVENT_MACRO_SUBSTITUTION (dist, abs(bottom - a[1]));
340    return dist;
341  }
342
343  point_type center() const {
344    point_type result;
345    result[0] = (left + right) / 2.;
346    result[1] = (top + bottom) / 2.;
347    return result;
348  }
349
350  point_type origin() const {
351    point_type result;
352    result[0] = left;
353    result[1] = top;
354    return result;
355  }
356
357  point_difference_type extent() const {
358    point_difference_type result;
359    result[0] = right - left;
360    result[1] = bottom - top;
361    return result;
362  }
363
364 private:
365  shared_ptr<RandomNumberGenerator> gen_ptr;
366  shared_ptr<rand_t> rand;
367  double left, top, right, bottom;
368};
369
370template<typename RandomNumberGenerator = minstd_rand>
371class cube_topology : public hypercube_topology<3, RandomNumberGenerator>
372{
373  typedef hypercube_topology<3, RandomNumberGenerator> inherited;
374
375 public:
376  explicit cube_topology(double scaling = 1.0) : inherited(scaling) { }
377
378  cube_topology(RandomNumberGenerator& gen, double scaling = 1.0)
379    : inherited(gen, scaling) { }
380};
381
382template<std::size_t Dims,
383         typename RandomNumberGenerator = minstd_rand>
384class ball_topology : public convex_topology<Dims>
385{
386  typedef uniform_01<RandomNumberGenerator, double> rand_t;
387
388 public:
389  typedef typename convex_topology<Dims>::point_type point_type;
390  typedef typename convex_topology<Dims>::point_difference_type point_difference_type;
391
392  explicit ball_topology(double radius = 1.0)
393    : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)),
395  { }
396
397  ball_topology(RandomNumberGenerator& gen, double radius = 1.0)
399
400  point_type random_point() const
401  {
402    point_type p;
403    double dist_sum;
404    do {
405      dist_sum = 0.0;
406      for (std::size_t i = 0; i < Dims; ++i) {
408        p[i] = x;
409        dist_sum += x * x;
410      }
412    return p;
413  }
414
415  point_type bound(point_type a) const
416  {
417    BOOST_USING_STD_MIN();
418    BOOST_USING_STD_MAX();
419    double r = 0.;
420    for (std::size_t i = 0; i < Dims; ++i)
421      r = boost::math::hypot(r, a[i]);
422    if (r <= radius) return a;
423    double scaling_factor = radius / r;
424    point_type p;
425    for (std::size_t i = 0; i < Dims; ++i)
426      p[i] = a[i] * scaling_factor;
427    return p;
428  }
429
430  double distance_from_boundary(point_type a) const
431  {
432    double r = 0.;
433    for (std::size_t i = 0; i < Dims; ++i)
434      r = boost::math::hypot(r, a[i]);
436  }
437
438  point_type center() const {
439    point_type result;
440    for (std::size_t i = 0; i < Dims; ++i)
441      result[i] = 0;
442    return result;
443  }
444
445  point_type origin() const {
446    point_type result;
447    for (std::size_t i = 0; i < Dims; ++i)
449    return result;
450  }
451
452  point_difference_type extent() const {
453    point_difference_type result;
454    for (std::size_t i = 0; i < Dims; ++i)
455      result[i] = 2. * radius;
456    return result;
457  }
458
459 private:
460  shared_ptr<RandomNumberGenerator> gen_ptr;
461  shared_ptr<rand_t> rand;
463};
464
465template<typename RandomNumberGenerator = minstd_rand>
466class circle_topology : public ball_topology<2, RandomNumberGenerator>
467{
468  typedef ball_topology<2, RandomNumberGenerator> inherited;
469
470 public:
472
473  circle_topology(RandomNumberGenerator& gen, double radius = 1.0)
474    : inherited(gen, radius) { }
475};
476
477template<typename RandomNumberGenerator = minstd_rand>
478class sphere_topology : public ball_topology<3, RandomNumberGenerator>
479{
480  typedef ball_topology<3, RandomNumberGenerator> inherited;
481
482 public:
484
485  sphere_topology(RandomNumberGenerator& gen, double radius = 1.0)
486    : inherited(gen, radius) { }
487};
488
489template<typename RandomNumberGenerator = minstd_rand>
490class heart_topology
491{
492  // Heart is defined as the union of three shapes:
493  // Square w/ corners (+-1000, -1000), (0, 0), (0, -2000)
494  // Circle centered at (-500, -500) radius 500*sqrt(2)
495  // Circle centered at (500, -500) radius 500*sqrt(2)
496  // Bounding box (-1000, -2000) - (1000, 500*(sqrt(2) - 1))
497
498  struct point
499  {
500    point() { values[0] = 0.0; values[1] = 0.0; }
501    point(double x, double y) { values[0] = x; values[1] = y; }
502
503    double& operator[](std::size_t i)       { return values[i]; }
504    double  operator[](std::size_t i) const { return values[i]; }
505
506  private:
507    double values[2];
508  };
509
510  bool in_heart(point p) const
511  {
512#ifndef BOOST_NO_STDC_NAMESPACE
513    using std::abs;
514#endif
515
516    if (p[1] < abs(p[0]) - 2000) return false; // Bottom
517    if (p[1] <= -1000) return true; // Diagonal of square
518    if (boost::math::hypot(p[0] - -500, p[1] - -500) <= 500. * boost::math::constants::root_two<double>())
519      return true; // Left circle
520    if (boost::math::hypot(p[0] - 500, p[1] - -500) <= 500. * boost::math::constants::root_two<double>())
521      return true; // Right circle
522    return false;
523  }
524
525  bool segment_within_heart(point p1, point p2) const
526  {
527    // Assumes that p1 and p2 are within the heart
528    if ((p1[0] < 0) == (p2[0] < 0)) return true; // Same side of symmetry line
529    if (p1[0] == p2[0]) return true; // Vertical
530    double slope = (p2[1] - p1[1]) / (p2[0] - p1[0]);
531    double intercept = p1[1] - p1[0] * slope;
532    if (intercept > 0) return false; // Crosses between circles
533    return true;
534  }
535
536  typedef uniform_01<RandomNumberGenerator, double> rand_t;
537
538 public:
539  typedef point point_type;
540
541  heart_topology()
542    : gen_ptr(new RandomNumberGenerator), rand(new rand_t(*gen_ptr)) { }
543
544  heart_topology(RandomNumberGenerator& gen)
545    : gen_ptr(), rand(new rand_t(gen)) { }
546
547  point random_point() const
548  {
549    point result;
550    do {
551      result[0] = (*rand)() * (1000 + 1000 * boost::math::constants::root_two<double>()) - (500 + 500 * boost::math::constants::root_two<double>());
552      result[1] = (*rand)() * (2000 + 500 * (boost::math::constants::root_two<double>() - 1)) - 2000;
553    } while (!in_heart(result));
554    return result;
555  }
556
557  // Not going to provide clipping to bounding region or distance from boundary
558
559  double distance(point a, point b) const
560  {
561    if (segment_within_heart(a, b)) {
562      // Straight line
563      return boost::math::hypot(b[0] - a[0], b[1] - a[1]);
564    } else {
565      // Straight line bending around (0, 0)
566      return boost::math::hypot(a[0], a[1]) + boost::math::hypot(b[0], b[1]);
567    }
568  }
569
570  point move_position_toward(point a, double fraction, point b) const
571  {
572    if (segment_within_heart(a, b)) {
573      // Straight line
574      return point(a[0] + (b[0] - a[0]) * fraction,
575                   a[1] + (b[1] - a[1]) * fraction);
576    } else {
577      double distance_to_point_a = boost::math::hypot(a[0], a[1]);
578      double distance_to_point_b = boost::math::hypot(b[0], b[1]);
579      double location_of_point = distance_to_point_a /
580                                   (distance_to_point_a + distance_to_point_b);
581      if (fraction < location_of_point)
582        return point(a[0] * (1 - fraction / location_of_point),
583                     a[1] * (1 - fraction / location_of_point));
584      else
585        return point(
586          b[0] * ((fraction - location_of_point) / (1 - location_of_point)),
587          b[1] * ((fraction - location_of_point) / (1 - location_of_point)));
588    }
589  }
590
591 private:
592  shared_ptr<RandomNumberGenerator> gen_ptr;
593  shared_ptr<rand_t> rand;
594};
595
596} // namespace boost
597
598#endif // BOOST_GRAPH_TOPOLOGY_HPP
```