/* makeInfo: * For each node in the graph, create a Info data structure */ static void makeInfo(Agraph_t * graph) { Agnode_t *node; int i; Info_t *ip; nsites = agnnodes(graph); geominit(); nodeInfo = N_GNEW(nsites, Info_t); node = agfstnode(graph); ip = nodeInfo; pmargin = expFactor (graph); for (i = 0; i < nsites; i++) { ip->site.coord.x = ND_pos(node)[0]; ip->site.coord.y = ND_pos(node)[1]; makePoly(&ip->poly, node, pmargin); ip->site.sitenbr = i; ip->site.refcnt = 1; ip->node = node; ip->verts = NULL; node = agnxtnode(graph, node); ip++; } }
/* scAdjust: * Scale the layout. * equal > 0 => scale uniformly in x and y to remove overlaps * equal = 0 => scale separately in x and y to remove overlaps * equal < 0 => scale down uniformly in x and y to remove excess space * The last assumes there are no overlaps at present. * Based on Marriott, Stuckey, Tam and He, * "Removing Node Overlapping in Graph Layout Using Constrained Optimization", * Constraints,8(2):143--172, 2003. */ int scAdjust(graph_t * g, int equal) { int nnodes = agnnodes(g); info *nlist = N_GNEW(nnodes, info); info *p = nlist; node_t *n; pointf s; int i; double margin; pointf *aarr; int m; margin = expFactor (g); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { double w2 = margin * ND_width(n) / 2.0; double h2 = margin * ND_height(n) / 2.0; p->pos.x = ND_pos(n)[0]; p->pos.y = ND_pos(n)[1]; p->bb.LL.x = p->pos.x - w2; p->bb.LL.y = p->pos.y - h2; p->bb.UR.x = p->pos.x + w2; p->bb.UR.y = p->pos.y + h2; p->wd2 = w2; p->ht2 = h2; p->np = n; p++; } if (equal < 0) { s.x = s.y = compress(nlist, nnodes); if (s.x == 0) { /* overlaps exist */ free(nlist); return 0; } fprintf(stderr, "compress %g \n", s.x); } else { aarr = mkOverlapSet(nlist, nnodes, &m); if (m == 0) { /* no overlaps */ free(aarr); free(nlist); return 0; } if (equal) { s.x = s.y = computeScale(aarr, m); } else { s = computeScaleXY(aarr, m); } free(aarr); } p = nlist; for (i = 0; i < nnodes; i++) { ND_pos(p->np)[0] = s.x * p->pos.x; ND_pos(p->np)[1] = s.y * p->pos.y; p++; } free(nlist); return 1; }
/* cAdjust: * Use optimization to remove overlaps. * Modifications; * - do y;x then x;y and use the better one * - for all overlaps (or if overlap with leftmost nodes), add a constraint; * constraint could move both x and y away, or the smallest, or some * mixture. * - follow by a scale down using actual shapes * We use an optimization based on Marriott, Stuckey, Tam and He, * "Removing Node Overlapping in Graph Layout Using Constrained Optimization", * Constraints,8(2):143--172, 2003. * We solve 2 constraint problem, one in X, one in Y. In each dimension, * we require relative positions to remain the same. That is, if two nodes * have the same x originally, they have the same x at the end, and if one * node is to the left of another, it remains to the left. In addition, if * two nodes could overlap by moving their X coordinates, we insert a constraint * to keep the two nodes sufficiently apart. Similarly, for Y. * * mode = AM_ORTHOXY => first X, then Y * mode = AM_ORTHOYX => first Y, then X * mode = AM_ORTHO => first X, then Y * mode = AM_ORTHO_YX => first Y, then X * In the last 2 cases, relax the constraints as follows: during the X pass, * if two nodes actually intersect and a smaller move in the Y direction * will remove the overlap, we don't force the nodes apart in the X direction, * but leave it for the Y pass to remove any remaining overlaps. Without this, * the X pass will remove all overlaps, and the Y pass only compresses in the * Y direction, causing a skewing of the aspect ratio. * * mode = AM_ORTHOXY => first X, then Y * mode = AM_ORTHOYX => first Y, then X * mode = AM_ORTHO => first X, then Y * mode = AM_ORTHO_YX => first Y, then X */ int cAdjust(graph_t * g, int mode) { double margin; int ret, i, nnodes = agnnodes(g); nitem *nlist = N_GNEW(nnodes, nitem); nitem *p = nlist; node_t *n; margin = expFactor (g); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { initItem(n, p, margin); p++; } if (overlaps(nlist, nnodes)) { point pt; switch ((adjust_mode)mode) { case AM_ORTHOXY: constrainX(g, nlist, nnodes, intersectY, 1); constrainY(g, nlist, nnodes, intersectX, 1); break; case AM_ORTHOYX: constrainY(g, nlist, nnodes, intersectX, 1); constrainX(g, nlist, nnodes, intersectY, 1); break; case AM_ORTHO : constrainX(g, nlist, nnodes, intersectY0, 1); constrainY(g, nlist, nnodes, intersectX, 1); case AM_ORTHO_YX : constrainY(g, nlist, nnodes, intersectX0, 1); constrainX(g, nlist, nnodes, intersectY, 1); case AM_PORTHOXY: constrainX(g, nlist, nnodes, intersectY, 0); constrainY(g, nlist, nnodes, intersectX, 0); break; case AM_PORTHOYX: constrainY(g, nlist, nnodes, intersectX, 0); constrainX(g, nlist, nnodes, intersectY, 0); break; case AM_PORTHO_YX : constrainY(g, nlist, nnodes, intersectX0, 0); constrainX(g, nlist, nnodes, intersectY, 0); break; case AM_PORTHO : default : constrainX(g, nlist, nnodes, intersectY0, 0); constrainY(g, nlist, nnodes, intersectX, 0); break; } p = nlist; for (i = 0; i < nnodes; i++) { n = p->np; pt = p->pos; ND_pos(n)[0] = PS2INCH(pt.x) / SCALE; ND_pos(n)[1] = PS2INCH(pt.y) / SCALE; p++; } ret = 1; } else ret = 0; free(nlist); return ret; }