rescale_layout.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. ///////////////////////////////////////
  11. // //
  12. // This file contains the functions //
  13. // for distorting the layout. //
  14. // //
  15. // Four methods are available: //
  16. // 1) Uniform denisity - rectilinear //
  17. // 2) Uniform denisity - polar //
  18. // 3) Fisheye - rectilinear //
  19. // 4) Fisheye - Ploar //
  20. // //
  21. ///////////////////////////////////////
  22. #include <assert.h>
  23. #include <limits.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <math.h>
  28. #include <time.h>
  29. #include <neatogen/matrix_ops.h>
  30. #include <neatogen/delaunay.h>
  31. #include <common/arith.h>
  32. #include <topfish/hierarchy.h>
  33. #include <util/alloc.h>
  34. #include <util/sort.h>
  35. static double *compute_densities(v_data *graph, size_t n, double *x, double *y)
  36. {
  37. // compute density of every node by calculating the average edge length in a 2-D layout
  38. int j, neighbor;
  39. double sum;
  40. double *densities = gv_calloc(n, sizeof(double));
  41. for (size_t i = 0; i < n; i++) {
  42. sum = 0;
  43. for (j = 1; j < graph[i].nedges; j++) {
  44. neighbor = graph[i].edges[j];
  45. sum += hypot(x[i] - x[neighbor], y[i] - y[neighbor]);
  46. }
  47. densities[i] = sum / graph[i].nedges;
  48. }
  49. return densities;
  50. }
  51. static double *smooth_vec(double *vec, int *ordering, size_t n, int interval) {
  52. // smooth 'vec' by setting each components to the average of is 'interval'-neighborhood in 'ordering'
  53. assert(interval >= 0);
  54. double sum;
  55. double *smoothed_vec = gv_calloc(n, sizeof(double));
  56. size_t n1 = MIN(1 + (size_t)interval, n);
  57. sum = 0;
  58. for (size_t i = 0; i < n1; i++) {
  59. sum += vec[ordering[i]];
  60. }
  61. size_t len = n1;
  62. for (size_t i = 0; i < MIN(n, (size_t)interval); i++) {
  63. smoothed_vec[ordering[i]] = sum / (double)len;
  64. if (len < n) {
  65. sum += vec[ordering[len++]];
  66. }
  67. }
  68. if (n <= (size_t)interval) {
  69. return smoothed_vec;
  70. }
  71. for (size_t i = (size_t)interval; i < n - (size_t)interval - 1; i++) {
  72. smoothed_vec[ordering[i]] = sum / (double)len;
  73. sum +=
  74. vec[ordering[i + (size_t)interval + 1]] - vec[ordering[i - (size_t)interval]];
  75. }
  76. for (size_t i = MAX(n - (size_t)interval - 1, (size_t)interval); i < n; i++) {
  77. smoothed_vec[ordering[i]] = sum / (double)len;
  78. sum -= vec[ordering[i - (size_t)interval]];
  79. len--;
  80. }
  81. return smoothed_vec;
  82. }
  83. static int cmp(const void *a, const void *b, void *context) {
  84. const int *x = a;
  85. const int *y = b;
  86. const double *place = context;
  87. if (place[*x] < place[*y]) {
  88. return -1;
  89. }
  90. if (place[*x] > place[*y]) {
  91. return 1;
  92. }
  93. return 0;
  94. }
  95. void quicksort_place(double *place, int *ordering, size_t size) {
  96. gv_sort(ordering, size, sizeof(ordering[0]), cmp, place);
  97. }
  98. #define DIST(x1, y1, x2, y2) hypot((x1) - (x2), (y1) - (y2))
  99. static void rescale_layout_polarFocus(v_data *graph, size_t n, double *x_coords,
  100. double *y_coords, double x_focus,
  101. double y_focus, int interval,
  102. double distortion) {
  103. // Polar distortion - auxiliary function
  104. double *densities = NULL;
  105. double *distances = gv_calloc(n, sizeof(double));
  106. double *orig_distances = gv_calloc(n, sizeof(double));
  107. double ratio;
  108. for (size_t i = 0; i < n; i++)
  109. {
  110. distances[i] = DIST(x_coords[i], y_coords[i], x_focus, y_focus);
  111. }
  112. assert(n <= INT_MAX);
  113. copy_vector((int)n, distances, orig_distances);
  114. int *ordering = gv_calloc(n, sizeof(int));
  115. for (size_t i = 0; i < n; i++)
  116. {
  117. ordering[i] = (int)i;
  118. }
  119. quicksort_place(distances, ordering, n);
  120. densities = compute_densities(graph, n, x_coords, y_coords);
  121. double *smoothed_densities = smooth_vec(densities, ordering, n, interval);
  122. // rescale distances
  123. if (distortion < 1.01 && distortion > 0.99)
  124. {
  125. for (size_t i = 1; i < n; i++)
  126. {
  127. distances[ordering[i]] = distances[ordering[i - 1]] + (orig_distances[ordering[i]] -
  128. orig_distances[ordering
  129. [i -
  130. 1]]) / smoothed_densities[ordering[i]];
  131. }
  132. } else
  133. {
  134. double factor;
  135. // just to make milder behavior:
  136. if (distortion >= 0)
  137. {
  138. factor = sqrt(distortion);
  139. }
  140. else
  141. {
  142. factor = -sqrt(-distortion);
  143. }
  144. for (size_t i = 1; i < n; i++)
  145. {
  146. distances[ordering[i]] =
  147. distances[ordering[i - 1]] + (orig_distances[ordering[i]] -
  148. orig_distances[ordering
  149. [i -
  150. 1]]) /
  151. pow(smoothed_densities[ordering[i]], factor);
  152. }
  153. }
  154. // compute new coordinate:
  155. for (size_t i = 0; i < n; i++)
  156. {
  157. if (orig_distances[i] == 0)
  158. {
  159. ratio = 0;
  160. }
  161. else
  162. {
  163. ratio = distances[i] / orig_distances[i];
  164. }
  165. x_coords[i] = x_focus + (x_coords[i] - x_focus) * ratio;
  166. y_coords[i] = y_focus + (y_coords[i] - y_focus) * ratio;
  167. }
  168. free(densities);
  169. free(smoothed_densities);
  170. free(distances);
  171. free(orig_distances);
  172. free(ordering);
  173. }
  174. void
  175. rescale_layout_polar(double *x_coords, double *y_coords,
  176. double *x_foci, double *y_foci, int num_foci,
  177. size_t n, int interval, double width,
  178. double height, double distortion) {
  179. // Polar distortion - main function
  180. double minX, maxX, minY, maxY;
  181. double aspect_ratio;
  182. v_data *graph;
  183. double scaleX;
  184. double scale_ratio;
  185. // compute original aspect ratio
  186. minX = maxX = x_coords[0];
  187. minY = maxY = y_coords[0];
  188. for (size_t i = 1; i < n; i++)
  189. {
  190. minX = fmin(minX, x_coords[i]);
  191. minY = fmin(minY, y_coords[i]);
  192. maxX = fmax(maxX, x_coords[i]);
  193. maxY = fmax(maxY, y_coords[i]);
  194. }
  195. aspect_ratio = (maxX - minX) / (maxY - minY);
  196. // construct mutual neighborhood graph
  197. assert(n <= INT_MAX);
  198. graph = UG_graph(x_coords, y_coords, (int)n);
  199. if (num_foci == 1)
  200. { // accelerate execution of most common case
  201. rescale_layout_polarFocus(graph, n, x_coords, y_coords, x_foci[0],
  202. y_foci[0], interval, distortion);
  203. } else
  204. {
  205. // average-based rescale
  206. double *final_x_coords = gv_calloc(n, sizeof(double));
  207. double *final_y_coords = gv_calloc(n, sizeof(double));
  208. double *cp_x_coords = gv_calloc(n, sizeof(double));
  209. double *cp_y_coords = gv_calloc(n, sizeof(double));
  210. assert(n <= INT_MAX);
  211. for (int i = 0; i < num_foci; i++) {
  212. copy_vector((int)n, x_coords, cp_x_coords);
  213. copy_vector((int)n, y_coords, cp_y_coords);
  214. rescale_layout_polarFocus(graph, n, cp_x_coords, cp_y_coords,
  215. x_foci[i], y_foci[i], interval, distortion);
  216. scadd(final_x_coords, (int)n - 1, 1.0 / num_foci, cp_x_coords);
  217. scadd(final_y_coords, (int)n - 1, 1.0 / num_foci, cp_y_coords);
  218. }
  219. copy_vector((int)n, final_x_coords, x_coords);
  220. copy_vector((int)n, final_y_coords, y_coords);
  221. free(final_x_coords);
  222. free(final_y_coords);
  223. free(cp_x_coords);
  224. free(cp_y_coords);
  225. }
  226. free(graph[0].edges);
  227. free(graph);
  228. minX = maxX = x_coords[0];
  229. minY = maxY = y_coords[0];
  230. for (size_t i = 1; i < n; i++) {
  231. minX = fmin(minX, x_coords[i]);
  232. minY = fmin(minY, y_coords[i]);
  233. maxX = fmax(maxX, x_coords[i]);
  234. maxY = fmax(maxY, y_coords[i]);
  235. }
  236. // shift points:
  237. for (size_t i = 0; i < n; i++) {
  238. x_coords[i] -= minX;
  239. y_coords[i] -= minY;
  240. }
  241. // rescale x_coords to maintain aspect ratio:
  242. scaleX = aspect_ratio * (maxY - minY) / (maxX - minX);
  243. for (size_t i = 0; i < n; i++) {
  244. x_coords[i] *= scaleX;
  245. }
  246. // scale the layout to fit full drawing area:
  247. scale_ratio =
  248. MIN((width) / (aspect_ratio * (maxY - minY)),
  249. (height) / (maxY - minY));
  250. for (size_t i = 0; i < n; i++) {
  251. x_coords[i] *= scale_ratio;
  252. y_coords[i] *= scale_ratio;
  253. }
  254. }