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; }
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; } } }
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; }