00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include "config.h"
00020 #endif
00021
00022
00023
00024
00025
00026
00027 #include "blockpath.h"
00028
00029 #define LEN(x,y) (sqrt((x)*(x) + (y)*(y)))
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 static double
00057 getRotation(block_t * sn, Agraph_t * g, double x, double y, double theta)
00058 {
00059 double mindist;
00060 Agraph_t *subg;
00061
00062 Agnode_t *n, *closest_node, *neighbor;
00063 nodelist_t *list;
00064 double len, newX, newY;
00065 int count;
00066
00067 subg = sn->sub_graph;
00068 #ifdef OLD
00069 parent = sn->parent;
00070 #endif
00071
00072 list = sn->circle_list;
00073
00074 if (sn->parent_pos >= 0) {
00075 theta += M_PI - sn->parent_pos;
00076 if (theta < 0)
00077 theta += 2 * M_PI;
00078
00079 return theta;
00080 }
00081
00082 count = sizeNodelist(list);
00083 if (count == 2) {
00084 return (theta - M_PI / 2.0);
00085 }
00086
00087
00088 neighbor = CHILD(sn);
00089 #ifdef OLD
00090 for (e = agfstedge(g, parent); e; e = agnxtedge(g, e, parent)) {
00091 n = e->head;
00092 if (n == parent)
00093 n = e->tail;
00094
00095 if ((BLOCK(n) == sn) && (PARENT(n) == parent)) {
00096 neighbor = n;
00097 break;
00098 }
00099 }
00100 #endif
00101 newX = ND_pos(neighbor)[0] + x;
00102 newY = ND_pos(neighbor)[1] + y;
00103 mindist = LEN(newX, newY);
00104 closest_node = neighbor;
00105
00106 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00107 if (n == neighbor)
00108 continue;
00109
00110 newX = ND_pos(n)[0] + x;
00111 newY = ND_pos(n)[1] + y;
00112
00113 len = LEN(newX, newY);
00114 if (len < mindist) {
00115 mindist = len;
00116 closest_node = n;
00117 }
00118 }
00119
00120
00121 if (neighbor != closest_node) {
00122 double rho = sn->rad0;
00123 double r = sn->radius - rho;
00124 double n_x = ND_pos(neighbor)[0];
00125 if (COALESCED(sn) && (-r < n_x)) {
00126 double R = LEN(x, y);
00127 double n_y = ND_pos(neighbor)[1];
00128 double phi = atan2(n_y, n_x + r);
00129 double l = r - rho / (cos(phi));
00130
00131 theta += M_PI / 2.0 - phi - asin((l / R) * (cos(phi)));
00132 } else {
00133 double phi = atan2(ND_pos(neighbor)[1], ND_pos(neighbor)[0]);
00134 theta += M_PI - phi - PSI(neighbor);
00135 if (theta > 2 * M_PI)
00136 theta -= 2 * M_PI;
00137 }
00138 } else
00139 theta = 0;
00140 return theta;
00141 }
00142
00143
00144
00145
00146
00147
00148 static void applyDelta(block_t * sn, double x, double y, double rotate)
00149 {
00150 block_t *child;
00151 Agraph_t *subg;
00152 Agnode_t *n;
00153
00154 subg = sn->sub_graph;
00155
00156 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
00157 double X, Y;
00158
00159 if (rotate != 0) {
00160 double tmpX, tmpY;
00161 double cosR, sinR;
00162
00163 tmpX = ND_pos(n)[0];
00164 tmpY = ND_pos(n)[1];
00165 cosR = cos(rotate);
00166 sinR = sin(rotate);
00167
00168 X = tmpX * cosR - tmpY * sinR;
00169 Y = tmpX * sinR + tmpY * cosR;
00170 } else {
00171 X = ND_pos(n)[0];
00172 Y = ND_pos(n)[1];
00173 }
00174
00175
00176 ND_pos(n)[0] = X + x;
00177 ND_pos(n)[1] = Y + y;
00178 }
00179
00180 for (child = sn->children.first; child; child = child->next)
00181 applyDelta(child, x, y, rotate);
00182 }
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196 typedef struct {
00197 double radius;
00198 double subtreeR;
00199 double nodeAngle;
00200 double firstAngle;
00201 double lastAngle;
00202 block_t *cp;
00203 node_t *neighbor;
00204 } posstate;
00205
00206
00207
00208
00209
00210
00211
00212
00213 static double
00214 doParent(Agraph_t * g, double theta, Agnode_t * n,
00215 int length, double min_dist, posstate * stp)
00216 {
00217 block_t *child;
00218 double mindistance;
00219 double childAngle;
00220 double deltaX, deltaY;
00221 double snRadius = stp->subtreeR;
00222 double firstAngle = stp->firstAngle;
00223 double lastAngle = stp->lastAngle;
00224 double rotateAngle;
00225 double incidentAngle;
00226
00227 int childCount = 0;
00228 double maxRadius = 0;
00229 double childRadius;
00230 double diameter = 0;
00231 double mindistAngle;
00232 int cnt, midChild;
00233 double midAngle = 0;
00234
00235 for (child = stp->cp; child; child = child->next) {
00236 if (BLK_PARENT(child) == n) {
00237 childCount++;
00238 if (maxRadius < child->radius) {
00239 maxRadius = child->radius;
00240 }
00241 diameter += 2 * child->radius + min_dist;
00242 }
00243 }
00244
00245 if (length == 1)
00246 childAngle = 0;
00247 else
00248 childAngle = theta - stp->nodeAngle / 2;
00249
00250 childRadius = length * diameter / (2 * M_PI);
00251
00252
00253
00254
00255
00256
00257 mindistance = stp->radius + min_dist + maxRadius;
00258 if (childRadius < mindistance)
00259 childRadius = mindistance;
00260
00261 if ((childRadius + maxRadius) > snRadius)
00262 snRadius = childRadius + maxRadius;
00263
00264 mindistAngle = min_dist / childRadius;
00265
00266 cnt = 0;
00267 midChild = (childCount + 1) / 2;
00268 for (child = stp->cp; child; child = child->next) {
00269 if (BLK_PARENT(child) != n)
00270 continue;
00271 if (sizeNodelist(child->circle_list) <= 0)
00272 continue;
00273
00274 incidentAngle = child->radius / childRadius;
00275 if (length == 1) {
00276 if (childAngle != 0)
00277 childAngle += incidentAngle;
00278
00279 if (firstAngle < 0)
00280 firstAngle = childAngle;
00281
00282 lastAngle = childAngle;
00283 } else {
00284 if (childCount == 1) {
00285 childAngle = theta;
00286 } else {
00287 childAngle += incidentAngle + mindistAngle / 2;
00288 }
00289 }
00290
00291 deltaX = childRadius * cos(childAngle);
00292 deltaY = childRadius * sin(childAngle);
00293
00294
00295
00296
00297
00298
00299 rotateAngle = getRotation(child, g, deltaX, deltaY, childAngle);
00300 applyDelta(child, deltaX, deltaY, rotateAngle);
00301
00302 if (length == 1) {
00303 childAngle += incidentAngle + mindistAngle;
00304 } else {
00305 childAngle += incidentAngle + mindistAngle / 2;
00306 }
00307 cnt++;
00308 if (cnt == midChild)
00309 midAngle = childAngle;
00310 }
00311
00312 if ((length > 1) && (n == stp->neighbor)) {
00313 PSI(n) = midAngle;
00314 }
00315
00316 stp->subtreeR = snRadius;
00317 stp->firstAngle = firstAngle;
00318 stp->lastAngle = lastAngle;
00319 return maxRadius;
00320 }
00321
00322
00323
00324
00325 static double
00326 position(Agraph_t * g, int childCount, int length, nodelist_t * path,
00327 block_t * sn, double min_dist)
00328 {
00329 nodelistitem_t *item;
00330 Agnode_t *n;
00331 posstate state;
00332 int counter = 0;
00333 double maxRadius = 0.0;
00334 double angle;
00335 double theta = 0.0;
00336
00337 state.cp = sn->children.first;
00338 state.subtreeR = sn->radius;
00339 state.radius = sn->radius;
00340 state.neighbor = CHILD(sn);
00341 state.nodeAngle = 2 * M_PI / length;
00342 state.firstAngle = -1;
00343 state.lastAngle = -1;
00344
00345 for (item = path->first; item; item = item->next) {
00346 n = item->curr;
00347
00348 if (length != 1) {
00349 theta = counter * state.nodeAngle;
00350 counter++;
00351 }
00352
00353 if (ISPARENT(n))
00354 maxRadius = doParent(g, theta, n, length, min_dist, &state);
00355 }
00356
00357
00358
00359
00360
00361
00362
00363 if (childCount == 1) {
00364 applyDelta(sn, -(maxRadius + min_dist / 2), 0, 0);
00365 sn->radius += min_dist / 2 + maxRadius;
00366 SET_COALESCED(sn);
00367 } else
00368 sn->radius = state.subtreeR;
00369
00370 angle = (state.firstAngle + state.lastAngle) / 2.0 - M_PI;
00371 return angle;
00372 }
00373
00374
00375
00376
00377 static void doBlock(Agraph_t * g, block_t * sn, double min_dist)
00378 {
00379 block_t *child;
00380 nodelist_t *longest_path;
00381 int childCount, length;
00382 double centerAngle = M_PI;
00383
00384
00385 childCount = 0;
00386 for (child = sn->children.first; child; child = child->next) {
00387 doBlock(g, child, min_dist);
00388 childCount++;
00389 }
00390
00391
00392 longest_path = layout_block(g, sn, min_dist);
00393 sn->circle_list = longest_path;
00394 length = sizeNodelist(longest_path);
00395
00396
00397 if (childCount > 0)
00398 centerAngle =
00399 position(g, childCount, length, longest_path, sn, min_dist);
00400
00401 if ((length == 1) && (BLK_PARENT(sn))) {
00402 sn->parent_pos = centerAngle;
00403 if (sn->parent_pos < 0)
00404 sn->parent_pos += 2 * M_PI;
00405 }
00406 }
00407
00408 void circPos(Agraph_t * g, block_t * sn, circ_state * state)
00409 {
00410 doBlock(g, sn, state->min_dist);
00411 }