/* initItem: */ static void initItem(node_t * n, nitem * p, expand_t margin) { int x = POINTS(SCALE * ND_pos(n)[0]); int y = POINTS(SCALE * ND_pos(n)[1]); int w2, h2; box b; if (margin.doAdd) { w2 = SCALE * (POINTS(ND_width(n)/2.0) + margin.x); h2 = SCALE * (POINTS(ND_height(n)/2.0) + margin.y); } else { w2 = POINTS(margin.x * SCALE2 * ND_width(n)); h2 = POINTS(margin.y * SCALE2 * ND_height(n)); } b.LL.x = x - w2; b.LL.y = y - h2; b.UR.x = x + w2; b.UR.y = y + h2; p->pos.x = x; p->pos.y = y; p->np = n; p->bb = b; }
/* applyAttr: * Attractive force = weight*(d*d)/K * or force = (d - L(e))*weight(e) */ static void applyAttr (Agnode_t* p, Agnode_t* q, Agedge_t* e) { double xdelta, ydelta; double force; double dist; double dist2; xdelta = ND_pos(q)[0] - ND_pos(p)[0]; ydelta = ND_pos(q)[1] - ND_pos(p)[1]; dist2 = xdelta*xdelta + ydelta*ydelta; while (dist2 == 0.0) { xdelta = 5 - rand()%10; ydelta = 5 - rand()%10; dist2 = xdelta*xdelta + ydelta*ydelta; } dist = sqrt (dist2); if (T_useNew) force = (ED_factor(e) * (dist - ED_dist(e)))/dist; else force = (ED_factor(e) * dist)/ED_dist(e); DISP(q)[0] -= xdelta * force; DISP(q)[1] -= ydelta * force; DISP(p)[0] += xdelta * force; DISP(p)[1] += ydelta * force; }
point coord(node_t * n) { pointf pf; pf.x = ND_pos(n)[0]; pf.y = ND_pos(n)[1]; return cvt2pt(pf); }
/* evalPositions: * The input is laid out, but node coordinates * are relative to smallest containing cluster. * Walk through all nodes and clusters, translating * the positions to absolute coordinates. * Assume that when called, g's bounding box is * in absolute coordinates and that box of root graph * has LL at origin. */ static void evalPositions(graph_t * g, graph_t* rootg) { int i; graph_t *subg; node_t *n; boxf bb; boxf sbb; bb = BB(g); /* translate nodes in g */ if (g != rootg) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { if (PARENT(n) != g) continue; ND_pos(n)[0] += bb.LL.x; ND_pos(n)[1] += bb.LL.y; } } /* translate top-level clusters and recurse */ for (i = 1; i <= GD_n_cluster(g); i++) { subg = GD_clust(g)[i]; if (g != rootg) { sbb = BB(subg); sbb.LL.x += bb.LL.x; sbb.LL.y += bb.LL.y; sbb.UR.x += bb.LL.x; sbb.UR.y += bb.LL.y; BB(subg) = sbb; } evalPositions(subg, rootg); } }
/* 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++; } }
pointf coord(node_t * n) { pointf r; r.x = POINTS_PER_INCH * ND_pos(n)[0]; r.y = POINTS_PER_INCH * ND_pos(n)[1]; return r; }
static void copyPos(Agraph_t * g) { Agnode_t *n; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { ND_coord_i(n).x = POINTS(ND_pos(n)[0]); ND_coord_i(n).y = POINTS(ND_pos(n)[1]); } }
/* applyRep: * Repulsive force = (K*K)/d * or K*K/d*d */ static void applyRep (Agnode_t* p, Agnode_t* q) { double xdelta, ydelta; xdelta = ND_pos(q)[0] - ND_pos(p)[0]; ydelta = ND_pos(q)[1] - ND_pos(p)[1]; doRep (p, q, xdelta, ydelta, xdelta*xdelta + ydelta*ydelta); }
static void initPos(Agraph_t * g) { Agnode_t *n; Agedge_t *e; double *pvec; char *p; point *sp; int pn; attrsym_t *N_pos = agfindnodeattr(g, "pos"); attrsym_t *E_pos = agfindedgeattr(g, "pos"); assert(N_pos); if (!E_pos) { if (doEdges) fprintf(stderr, "Warning: turning off doEdges, graph %s\n", g->name); doEdges = 0; } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { pvec = ND_pos(n); p = agxget(n, N_pos->index); if (p[0] && (sscanf(p, "%lf,%lf", pvec, pvec + 1) == 2)) { int i; for (i = 0; i < NDIM; i++) pvec[i] = pvec[i] / PSinputscale; } else { fprintf(stderr, "could not find pos for node %s in graph %s\n", n->name, g->name); exit(1); } ND_coord_i(n).x = POINTS(ND_pos(n)[0]); ND_coord_i(n).y = POINTS(ND_pos(n)[1]); } if (doEdges) { for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { if ((sp = user_spline(E_pos, e, &pn)) != 0) { clip_and_install(e, sp, pn); free(sp); } else { fprintf(stderr, "Missing edge pos for edge %s - %s in graph %s\n", n->name, e->head->name, g->name); exit(1); } } } } }
static void resetCoord (Agraph_t* g) { node_t* np = agfstnode(g); double* sp = ND_pos(np); double* ps = sp; for (np = agfstnode(g); np; np = agnxtnode(g, np)) { ND_pos(np) = 0; ND_coord(np).x = INCH2PS(ps[0]); ND_coord(np).y = INCH2PS(ps[1]); ps += 2; } free (sp); }
/* makeInfo: * For each node in the graph, create a Info data structure */ static int makeInfo(Agraph_t * graph) { Agnode_t *node; int i; Info_t *ip; expand_t pmargin; int (*polyf)(Poly *, Agnode_t *, float, float); nsites = agnnodes(graph); geominit(); nodeInfo = N_GNEW(nsites, Info_t); node = agfstnode(graph); ip = nodeInfo; pmargin = sepFactor (graph); if (pmargin.doAdd) { polyf = makeAddPoly; /* we need inches for makeAddPoly */ pmargin.x = PS2INCH(pmargin.x); pmargin.y = PS2INCH(pmargin.y); } else polyf = makePoly; for (i = 0; i < nsites; i++) { ip->site.coord.x = ND_pos(node)[0]; ip->site.coord.y = ND_pos(node)[1]; if (polyf(&ip->poly, node, pmargin.x, pmargin.y)) { free (nodeInfo); nodeInfo = NULL; return 1; } ip->site.sitenbr = i; ip->site.refcnt = 1; ip->node = node; ip->verts = NULL; node = agnxtnode(graph, node); ip++; } return 0; }
int user_pos(attrsym_t * posptr, attrsym_t * pinptr, node_t * np, int nG) { double *pvec; char *p, c; double z; if (posptr == NULL) return FALSE; pvec = ND_pos(np); p = agxget(np, posptr->index); if (p[0]) { c = '\0'; if ((Ndim >= 3) && (sscanf(p, "%lf,%lf,%lf%c", pvec, pvec+1, pvec+2, &c) >= 3)){ ND_pinned(np) = P_SET; if (PSinputscale > 0.0) { int i; for (i = 0; i < Ndim; i++) pvec[i] = pvec[i] / PSinputscale; } if (Ndim > 3) jitter_d(np, nG, 3); if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr->index)))) ND_pinned(np) = P_PIN; return TRUE; } else if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) { ND_pinned(np) = P_SET; if (PSinputscale > 0.0) { int i; for (i = 0; i < Ndim; i++) pvec[i] = pvec[i] / PSinputscale; } if (Ndim > 2) { if (N_z && (p = agxget(np, N_z->index)) && (sscanf(p,"%lf",&z) == 1)) { if (PSinputscale > 0.0) { pvec[2] = z / PSinputscale; } else pvec[2] = z; jitter_d(np, nG, 3); } else jitter3d(np, nG); } if ((c == '!') || (pinptr && mapbool(agxget(np, pinptr->index)))) ND_pinned(np) = P_PIN; return TRUE; } else agerr(AGERR, "node %s, position %s, expected two doubles\n", np->name, p); } return FALSE; }
void neato_cleanup_node(node_t * n) { if (ND_shape(n)) { ND_shape(n)->fns->freefn(n); } free(ND_pos(n)); free_label(ND_label(n)); memset(&(n->u), 0, sizeof(Agnodeinfo_t)); }
/* initItem: */ static void initItem(node_t * n, nitem * p, double margin) { int x = POINTS(SCALE * ND_pos(n)[0]); int y = POINTS(SCALE * ND_pos(n)[1]); int w2 = POINTS(margin * SCALE2 * ND_width(n)); int h2 = POINTS(margin * SCALE2 * ND_height(n)); box b; b.LL.x = x - w2; b.LL.y = y - h2; b.UR.x = x + w2; b.UR.y = y + h2; p->pos.x = x; p->pos.y = y; p->np = n; p->bb = b; }
/* fdp_tLayout: * Given graph g with ports nodes, layout g respecting ports. * If some node have position information, it may be useful to * reset temperature and other parameters to reflect this. */ void fdp_tLayout (graph_t* g, xparams* xpms) { int i; int reset; bport_t* pp = PORTS(g); double temp; Grid* grid; pointf ctr; Agnode_t* n; reset = init_params(g, xpms); temp = T0; ctr = initPositions (g, pp); if (T_useGrid) { grid = mkGrid (agnnodes (g)); adjustGrid (grid, agnnodes (g)); for (i = 0; i < loopcnt; i++) { temp = cool (temp, i); gAdjust (g, temp, pp, grid); } delGrid (grid); } else { for (i = 0; i < loopcnt; i++) { temp = cool (temp, i); adjust (g, temp, pp); } } if ((ctr.x != 0.0) || (ctr.y != 0.0)) { for (n = agfstnode(g); n; n = agnxtnode(g,n)) { ND_pos(n)[0] += ctr.x; ND_pos(n)[1] += ctr.y; } } dumpstat (g); if (reset) reset_params (); }
static void dumpG(graph_t * g) { node_t *n; /* point p; */ edge_t *e; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { fprintf(stderr, " node %s \n", n->name); for (e = agfstout(g, n); e; e = agnxtout(g, e)) { fprintf(stderr, " %s - %s \n", e->tail->name, e->head->name); } #ifdef OLD p = coord(n); fprintf(stderr, " %s pos (%f,%f) (%d,%d)\n", n->name, ND_pos(n)[0], ND_pos(n)[1], p.x, p.y); fprintf(stderr, " width %f height %f xsize %d ysize %d\n", ND_width(n), ND_height(n), ND_xsize(n), ND_ysize(n)); #endif } }
void dumpstat (graph_t* g) { double dx, dy; double l, max2 = 0.0; node_t* np; edge_t* ep; for (np = agfstnode(g); np; np = agnxtnode(g,np)) { dx = DISP(np)[0]; dy = DISP(np)[1]; l = dx*dx + dy*dy; if (l > max2) max2 = l; fprintf (stderr, "%s: (%f,%f) (%f,%f)\n", np->name, ND_pos(np)[0], ND_pos(np)[1], DISP(np)[0], DISP(np)[1]); } fprintf (stderr, "max delta = %f\n", sqrt(max2)); for (np = agfstnode(g); np; np = agnxtnode(g,np)) { for (ep = agfstout(g,np); ep; ep = agnxtout(g,ep)) { dx = ND_pos(np)[0] - ND_pos(ep->head)[0]; dy = ND_pos(np)[1] - ND_pos(ep->head)[1]; fprintf (stderr, " %s -- %s (%f)\n", np->name, ep->head->name, sqrt(dx*dx + dy*dy)); } } }
/* applyDelta: * Recursively apply rotation rotate followed by translation (x,y) * to block sn and its children. */ static void applyDelta(block_t * sn, double x, double y, double rotate) { block_t *child; Agraph_t *subg; Agnode_t *n; subg = sn->sub_graph; for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { double X, Y; if (rotate != 0) { double tmpX, tmpY; double cosR, sinR; tmpX = ND_pos(n)[0]; tmpY = ND_pos(n)[1]; cosR = cos(rotate); sinR = sin(rotate); X = tmpX * cosR - tmpY * sinR; Y = tmpX * sinR + tmpY * cosR; } else { X = ND_pos(n)[0]; Y = ND_pos(n)[1]; } /* translate */ ND_pos(n)[0] = X + x; ND_pos(n)[1] = Y + y; } for (child = sn->children.first; child; child = child->next) applyDelta(child, x, y, rotate); }
/* circularLayout: * Do circular layout of g. * Assume g is strict. * g is a "connected" component of the derived graph of the * original graph. * We make state static so that it keeps a record of block numbers used * in a graph; it gets reset when a new root graph is used. */ void circularLayout(Agraph_t * g, Agraph_t* realg) { block_t *root; static circ_state state; if (agnnodes(g) == 1) { Agnode_t *n = agfstnode(g); ND_pos(n)[0] = 0; ND_pos(n)[1] = 0; return; } initGraphAttrs(g, &state); if (mapbool(agget(realg, "oneblock"))) root = createOneBlock(g, &state); else root = createBlocktree(g, &state); circPos(g, root, &state); cleanup(root, &state); }
static pointf get_centroid(Agraph_t *g) { int cnt = 0; static pointf sum = {0.0, 0.0}; static Agraph_t *save; Agnode_t *n; sum.x = (GD_bb(g).LL.x + GD_bb(g).UR.x) / 2.0; sum.y = (GD_bb(g).LL.y + GD_bb(g).UR.y) / 2.0; return sum; if (save == g) return sum; save = g; for (n = agfstnode(g); n; n = agnxtnode(g,n)) { sum.x += ND_pos(n)[0]; sum.y += ND_pos(n)[1]; cnt++; } sum.x = sum.x / cnt; sum.y = sum.y / cnt; return sum; }
static void attachPos (Agraph_t* g) { node_t* np; double* ps = N_NEW(2*agnnodes(g), double); for (np = agfstnode(g); np; np = agnxtnode(g, np)) { ND_pos(np) = ps; ps[0] = PS2INCH(ND_coord(np).x); ps[1] = PS2INCH(ND_coord(np).y); ps += 2; } }
/* dump: */ void dump(graph_t * g, int level, int doBB) { node_t *n; boxf bb; double w, h; pointf pos; if (Verbose < level) return; prIndent(); fprintf(stderr, "Graph %s : %d nodes\n", g->name, agnnodes(g)); dumpBB(g); if (Verbose > level) { incInd(); dumpSG(g); decInd(); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { pos.x = ND_pos(n)[0]; pos.y = ND_pos(n)[1]; prIndent(); w = ND_width(n); h = ND_height(n); if (doBB) { bb.LL.x = pos.x - w / 2.0; bb.LL.y = pos.y - h / 2.0; bb.UR.x = bb.LL.x + w; bb.UR.y = bb.LL.y + h; fprintf(stderr, "%s: (%f,%f) ((%f,%f) , (%f,%f))\n", n->name, pos.x, pos.y, bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y); } else { fprintf(stderr, "%s: (%f,%f) (%f,%f) \n", n->name, pos.x, pos.y, w, h); } } } }
static void scaleGraph (graph_t * g, node_t* root, pointf sc) { pointf ctr; node_t* n; ctr.x = ND_pos(root)[0]; ctr.y = ND_pos(root)[1]; for (n = agfstnode(g); n; n = agnxtnode (g, n)) { if (n == root) continue; ND_pos(n)[0] = sc.x*(ND_pos(n)[0] - ctr.x) + ctr.x; ND_pos(n)[1] = sc.y*(ND_pos(n)[1] - ctr.y) + ctr.y; } }
/* getPos: */ static real *getPos(Agraph_t * g, spring_electrical_control ctrl) { Agnode_t *n; real *pos = N_NEW(Ndim * agnnodes(g), real); int ix, i; if (agfindnodeattr(g, "pos") == NULL) return pos; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { i = ND_id(n); if (hasPos(n)) { for (ix = 0; ix < Ndim; ix++) { pos[i * Ndim + ix] = ND_pos(n)[ix]; } } } return pos; }
/* initLayout: * Initialize node coordinates. If the node already has * a position, use it. * Return true if some node is fixed. */ int initLayout(vtx_data * graph, int n, int dim, double **coords, node_t ** nodes) { node_t *np; double *xp; double *yp; double *pt; int i, d; int pinned = 0; xp = coords[0]; yp = coords[1]; for (i = 0; i < n; i++) { np = nodes[i]; if (hasPos(np)) { pt = ND_pos(np); *xp++ = *pt++; *yp++ = *pt++; if (dim > 2) { for (d = 2; d < dim; d++) coords[d][i] = *pt++; } if (isFixed(np)) pinned = 1; } else { *xp++ = drand48(); *yp++ = drand48(); if (dim > 2) { for (d = 2; d < dim; d++) coords[d][i] = drand48(); } } } for (d = 0; d < dim; d++) orthog1(n, coords[d]); return pinned; }
static void initialPositions(graph_t * g) { int i; node_t *np; attrsym_t *possym; attrsym_t *pinsym; double *pvec; char *p; char c; possym = agfindattr(g->proto->n, "pos"); if (!possym) return; pinsym = agfindattr(g->proto->n, "pin"); for (i = 0; (np = GD_neato_nlist(g)[i]); i++) { p = agxget(np, possym->index); if (p[0]) { pvec = ND_pos(np); c = '\0'; if (sscanf(p, "%lf,%lf%c", pvec, pvec + 1, &c) >= 2) { if (PSinputscale > 0.0) { int i; for (i = 0; i < NDIM; i++) pvec[i] = pvec[i] / PSinputscale; } ND_pinned(np) = P_SET; if ((c == '!') || (pinsym && mapbool(agxget(np, pinsym->index)))) ND_pinned(np) = P_PIN; } else fprintf(stderr, "Warning: node %s, position %s, expected two floats\n", np->name, p); } } }
/* initPositions: * Create initial layout of nodes * TODO : * Position nodes near neighbors with positions. * Use bbox to reset K. */ static pointf initPositions (graph_t* g, bport_t* pp) { int nG = agnnodes (g) - NPORTS (g); double size; Agnode_t* np; int n_pos = 0; /* no. of nodes with position info */ box bb; pointf ctr; /* center of boundary ellipse */ long local_seed; double PItimes2 = M_PI * 2.0; for (np = agfstnode(g); np; np = agnxtnode(g,np)) { if (ND_pinned(np)) { if (n_pos) { bb.LL.x = MIN(ND_pos(np)[0],bb.LL.x); bb.LL.y = MIN(ND_pos(np)[1],bb.LL.y); bb.UR.x = MAX(ND_pos(np)[0],bb.UR.x); bb.UR.y = MAX(ND_pos(np)[1],bb.UR.y); } else { bb.UR.x = bb.LL.x = ND_pos(np)[0]; bb.UR.y = bb.LL.y = ND_pos(np)[1]; } n_pos++; } } size = T_K * (sqrt((double)nG) + 1.0); Wd = Ht = expFactor*(size/2.0); if (n_pos == 1) { ctr.x = bb.LL.x; ctr.y = bb.LL.y; } else if (n_pos > 1) { double alpha, area, width, height, quot; ctr.x = (bb.LL.x + bb.UR.x)/2.0; ctr.y = (bb.LL.y + bb.UR.y)/2.0; width = expFactor*(bb.UR.x - bb.LL.x); height = expFactor*(bb.UR.y - bb.LL.y); area = 4.0*Wd*Ht; quot = (width*height)/area; if (quot >= 1.0) { /* If bbox has large enough area, use it */ Wd = width/2.0; Ht = height/2.0; } else if (quot > 0.0) { /* else scale up to have enough area */ quot = 2.0*sqrt(quot); Wd = width/quot; Ht = height/quot; } else { /* either width or height is 0 */ if (width > 0) { height = area/width; Wd = width/2.0; Ht = height/2.0; } else if (height > 0) { width = area/height; Wd = width/2.0; Ht = height/2.0; } /* If width = height = 0, use Wd and Ht as defined above for * the case the n_pos == 0. */ } /* Construct enclosing ellipse */ alpha = atan2 (Ht, Wd); Wd = Wd/cos(alpha); Ht = Ht/sin(alpha); } else { ctr.x = ctr.y = 0; } Wd2 = Wd*Wd; Ht2 = Ht*Ht; /* Set seed value */ if (smode == seed_val) local_seed = T_seed; else { #ifdef MSWIN32 local_seed = time(NULL); #else local_seed = getpid() ^ time(NULL); #endif } srand48(local_seed); /* If ports, place ports on and nodes within an ellipse centered at origin * with halfwidth Wd and halfheight Ht. * If no ports, place nodes within a rectangle centered at origin * with halfwidth Wd and halfheight Ht. Nodes with a given position * are translated. Wd and Ht are set to contain all positioned points. * The reverse translation will be applied to all * nodes at the end of the layout. * TODO: place unfixed points using adjacent ports or fixed pts. */ if (pp) { while (pp->e) { /* position ports on ellipse */ np = pp->n; ND_pos(np)[0] = Wd * cos(pp->alpha); ND_pos(np)[1] = Ht * sin(pp->alpha); ND_pinned(np) = P_SET; pp++; } for (np = agfstnode(g); np; np = agnxtnode(g,np)) { if (IS_PORT(np)) continue; if (ND_pinned(np)) { ND_pos(np)[0] -= ctr.x; ND_pos(np)[1] -= ctr.y; } else { double angle = PItimes2 * drand48(); double radius = 0.9 * drand48(); ND_pos(np)[0] = radius * Wd * cos(angle); ND_pos(np)[1] = radius * Ht * sin(angle); } } } else { if (n_pos) { /* If positioned nodes */ for (np = agfstnode(g); np; np = agnxtnode(g,np)) { if (ND_pinned(np)) { ND_pos(np)[0] -= ctr.x; ND_pos(np)[1] -= ctr.y; } else { ND_pos(np)[0] = Wd * (2.0*drand48() - 1.0); ND_pos(np)[1] = Ht * (2.0*drand48() - 1.0); } } } else { /* No ports or positions; place randomly */ for (np = agfstnode(g); np; np = agnxtnode(g,np)) { ND_pos(np)[0] = Wd * (2.0*drand48() - 1.0); ND_pos(np)[1] = Ht * (2.0*drand48() - 1.0); } } } return ctr; }
/* 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; expand_t margin; pointf *aarr; int m; margin = sepFactor (g); if (margin.doAdd) { /* we use inches below */ margin.x = PS2INCH(margin.x); margin.y = PS2INCH(margin.y); } for (n = agfstnode(g); n; n = agnxtnode(g, n)) { double w2, h2; if (margin.doAdd) { w2 = (ND_width(n) / 2.0) + margin.x; h2 = (ND_height(n) / 2.0) + margin.y; } else { w2 = margin.x * ND_width(n) / 2.0; h2 = margin.y * 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; }
/* getRotation: * The function determines how much the block should be rotated * for best positioning with parent, assuming its center is at x and y * relative to the parent. * angle gives the angle of the new position, i.e., tan(angle) = y/x. * If sn has 2 nodes, we arrange the line of the 2 normal to angle. * If sn has 1 node, parent_pos has already been set to the * correct angle assuming no rotation. * Otherwise, we find the node in sn connected to the parent and rotate * the block so that it is closer or at least visible to its node in the * parent. * * For COALESCED blocks, if neighbor is in left half plane, * use unCOALESCED case. * Else let theta be angle, R = LEN(x,y), pho the radius of actual * child block, phi be angle of neighbor in actual child block, * and r the distance from center of coalesced block to center of * actual block. Then, the angle to rotate the coalesced block to * that the edge from the parent is tangent to the neighbor on the * actual child block circle is * alpha = theta + M_PI/2 - phi - arcsin((l/R)*(sin B)) * where l = r - rho/(cos phi) and beta = M_PI/2 + phi. * Thus, * alpha = theta + M_PI/2 - phi - arcsin((l/R)*(cos phi)) */ static double getRotation(block_t * sn, Agraph_t * g, double x, double y, double theta) { double mindist2; Agraph_t *subg; /* Agedge_t* e; */ Agnode_t *n, *closest_node, *neighbor; nodelist_t *list; double len2, newX, newY; int count; subg = sn->sub_graph; #ifdef OLD parent = sn->parent; #endif list = sn->circle_list; if (sn->parent_pos >= 0) { theta += M_PI - sn->parent_pos; if (theta < 0) theta += 2 * M_PI; return theta; } count = sizeNodelist(list); if (count == 2) { return (theta - M_PI / 2.0); } /* Find node in block connected to block's parent */ neighbor = CHILD(sn); #ifdef OLD for (e = agfstedge(g, parent); e; e = agnxtedge(g, e, parent)) { n = e->head; if (n == parent) n = e->tail; if ((BLOCK(n) == sn) && (PARENT(n) == parent)) { neighbor = n; break; } } #endif newX = ND_pos(neighbor)[0] + x; newY = ND_pos(neighbor)[1] + y; mindist2 = LEN2(newX, newY); /* save sqrts by using sqr of dist to find min */ closest_node = neighbor; for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { if (n == neighbor) continue; newX = ND_pos(n)[0] + x; newY = ND_pos(n)[1] + y; len2 = LEN2(newX, newY); if (len2 < mindist2) { mindist2 = len2; closest_node = n; } } /* if((neighbor != closest_node) && !ISPARENT(neighbor)) { */ if (neighbor != closest_node) { double rho = sn->rad0; double r = sn->radius - rho; double n_x = ND_pos(neighbor)[0]; if (COALESCED(sn) && (-r < n_x)) { double R = LEN(x, y); double n_y = ND_pos(neighbor)[1]; double phi = atan2(n_y, n_x + r); double l = r - rho / (cos(phi)); theta += M_PI / 2.0 - phi - asin((l / R) * (cos(phi))); } else { /* Origin still at center of this block */ double phi = atan2(ND_pos(neighbor)[1], ND_pos(neighbor)[0]); theta += M_PI - phi - PSI(neighbor); if (theta > 2 * M_PI) theta -= 2 * M_PI; } } else theta = 0; return theta; }
static void updatePos (Agraph_t* g, double temp, bport_t* pp) { Agnode_t* n; double temp2; double len2; double x,y,d; double dx,dy; temp2 = temp * temp; for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if (ND_pinned(n) & P_FIX) continue; dx = DISP(n)[0]; dy = DISP(n)[1]; len2 = dx*dx + dy*dy; /* limit by temperature */ if (len2 < temp2) { x = ND_pos(n)[0] + dx; y = ND_pos(n)[1] + dy; } else { double fact = temp/(sqrt(len2)); x = ND_pos(n)[0] + dx*fact; y = ND_pos(n)[1] + dy*fact; } /* if ports, limit by boundary */ if (pp) { d = sqrt((x*x)/Wd2 + (y*y)/Ht2); if (IS_PORT(n)) { ND_pos(n)[0] = x/d; ND_pos(n)[1] = y/d; } else if (d >= 1.0) { ND_pos(n)[0] = 0.95*x/d; ND_pos(n)[1] = 0.95*y/d; } else { ND_pos(n)[0] = x; ND_pos(n)[1] = y; } } else { ND_pos(n)[0] = x; ND_pos(n)[1] = y; } } }