topology.hpp 20 KB

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