int flags;
int level; /* depth in graph hierarchy */
graph_t *parent; /* smallest containing cluster */
+#ifdef DEBUG
+ graph_t *orig; /* original of derived graph */
+#endif
} gdata;
#define GDATA(g) ((gdata*)(GD_alg(g)))
#define NPORTS(g) (GDATA(g)->nports)
#define LEVEL(g) (GDATA(g)->level)
#define GPARENT(g) (GDATA(g)->parent)
+#ifdef DEBUG
+#define GORIG(g) (GDATA(g)->orig)
+#endif
/* ndata is attached to nodes in real graphs.
* Real nodes also use "builtin" fields:
#include <clusteredges.h>
#include <dbg.h>
-#define DFLT_overlap "scale" /* default overlap value */
-
typedef struct {
attrsym_t *G_coord;
attrsym_t *G_width;
ED_count(de)++;
}
+/* copyAttr:
+ * Copy given attribute from g to dg.
+ */
+static void
+copyAttr (graph_t* g, graph_t* dg, char* attr)
+{
+ char* ov_val;
+ Agsym_t* ov;
+
+ if ((ov = agfindattr(g, attr))) {
+ ov_val = agxget(g,ov->index);
+ ov = agfindattr(dg, attr);
+ if (ov)
+ agxset (dg, ov->index, ov_val);
+ else
+ agraphattr(dg, attr, ov_val);
+ }
+}
+
/* deriveGraph:
* Create derived graph of g by collapsing clusters into
* nodes. An edge is created between nodes if there is
fprintf(stderr, "derive graph %s of %s\n", name, g->name);
dg = agopen(name, AGRAPHSTRICT);
GD_alg(dg) = (void *) NEW(gdata); /* freed in freeDeriveGraph */
+#ifdef DEBUG
+ GORIG(dg) = g;
+#endif
GD_ndim(dg) = GD_ndim(g);
- /* Set up overlap value in case needed.
- * If already set, probably came from command line.
- * Otherwise, if set in the graph, use it.
- * Else, use default.
+ /* Copy attributes from g.
*/
- if (!agfindattr(dg, "overlap")) {
- Agsym_t* ov;
- if ((ov = agfindattr(g, "overlap")))
- agraphattr(dg, "overlap", agxget(g,ov->index));
- else
- agraphattr(dg, "overlap", DFLT_overlap);
- }
+ copyAttr(g,dg,"overlap");
+ copyAttr(g,dg,"sep");
/* create derived nodes from clusters */
for (i = 1; i <= GD_n_cluster(g); i++) {
int pinned;
xparams xpms;
+#ifdef DEBUG
+ incInd();
+#endif
+ if (Verbose) {
+#ifdef DEBUG
+ prIndent();
+#endif
+ fprintf (stderr, "layout %s\n", g->name);
+ }
/* initialize derived node pointers */
for (n = agfstnode(g); n; n = agnxtnode(g, n))
DNODE(n) = 0;
/* clean up temp graphs */
freeDerivedGraph(dg, cc);
free(cc);
+ if (Verbose) {
+#ifdef DEBUG
+ prIndent ();
+#endif
+ fprintf (stderr, "end %s\n", g->name);
+ }
+#ifdef DEBUG
+ decInd();
+#endif
}
/* setBB;
fdpParms_t fdp_parms = {
1, /* useGrid */
1, /* useNew */
- 1, /* seed */
-1, /* numIters */
- -1, /* maxIter */
50, /* unscaled */
0.0, /* C */
1.0, /* Tfact */
- -1.0, /* K */
+ -1.0, /* K - set in initParams; used in init_edge */
-1.0, /* T0 */
- seed_val, /* seed mode */
- 10, /* overlap removal mode */
};
#define D_useGrid (fdp_parms.useGrid)
#define D_useNew (fdp_parms.useNew)
-#define D_seed (fdp_parms.seed)
#define D_numIters (fdp_parms.numIters)
-#define D_maxIters (fdp_parms.maxIters)
#define D_unscaled (fdp_parms.unscaled)
#define D_C (fdp_parms.C)
#define D_Tfact (fdp_parms.Tfact)
#define D_K (fdp_parms.K)
#define D_T0 (fdp_parms.T0)
-#define D_smode (fdp_parms.smode)
-#define D_tries (fdp_parms.tries)
/* Actual parameters used; initialized using fdp_parms, then possibly
* updated with graph-specific values.
double K; /* spring constant; ideal distance */
double T0; /* initial temperature */
seedMode smode; /* seed mode */
- int tries; /* overlap removal mode */
double Cell; /* grid cell size */
double Cell2; /* Cell*Cell */
double K2; /* K*K */
#define T_Ht2 (parms.Ht2)
#define T_pass1 (parms.pass1)
#define T_loopcnt (parms.loopcnt)
-#define T_tries (parms.tries)
#define EXPFACTOR 1.2
#define DFLT_maxIters 600
#define DFLT_K 0.3
#define DFLT_Cell 0.0
+#define DFLT_seed 1
+#define DFLT_smode seed_val
static double cool(double temp, int t)
{
#ifdef DEBUG
if (Verbose) {
prIndent();
- fprintf(stderr, "tlayout %s : T0 %f\n", g->name, T_T0);
+ fprintf(stderr, "tlayout %s(%s) : T0 %f\n", g->name, GORIG(g->root)->name, T_T0);
}
#endif
ret = 1;
xpms->T0 = cool(T_T0, T_pass1);
xpms->K = T_K;
xpms->C = T_C;
- xpms->tries = T_tries;
xpms->numIters = T_maxIters - T_pass1;
if (T_numIters >= 0) {
/* fdp_initParams:
* Initialize parameters based on root graph attributes.
+ * Return K value.
*/
void fdp_initParams(graph_t * g)
{
T_useGrid = D_useGrid;
T_useNew = D_useNew;
- T_tries = D_tries;
T_numIters = D_numIters;
T_unscaled = D_unscaled;
T_Cell = DFLT_Cell;
T_C = D_C;
T_Tfact = D_Tfact;
- if (D_maxIters == -1)
- T_maxIters = late_int(g, agfindattr(g, "maxiter"), DFLT_maxIters, 0);
- else
- T_maxIters = D_maxIters;
- if (D_K == -1.0)
- T_K = late_double(g, agfindattr(g, "K"), DFLT_K, 0.0);
- else
- T_K = D_K;
+ T_maxIters = late_int(g, agfindattr(g, "maxiter"), DFLT_maxIters, 0);
+ D_K = T_K = late_double(g, agfindattr(g, "K"), DFLT_K, 0.0);
if (D_T0 == -1.0) {
T_T0 = late_double(g, agfindattr(g, "T0"), -1.0, 0.0);
} else
T_T0 = D_T0;
if (fdp_setSeed(&T_smode, agget(g, "start"))) {
- T_smode = D_smode;
- T_seed = D_seed;
+ T_smode = DFLT_smode;
+ T_seed = DFLT_seed;
}
T_pass1 = (T_unscaled * T_maxIters) / 100;
T_Cell = 3 * T_K;
T_Cell2 = T_Cell * T_Cell;
}
+#ifdef DEBUG
if (Verbose) {
+ prIndent();
fprintf(stderr,
- "Params %s: K %f T0 %f Tfact %f maxIters %d unscaled %d\n",
- g->name, T_K, T_T0, T_Tfact, T_maxIters, T_unscaled);
+ "Params %s : K %f T0 %f Tfact %f maxIters %d unscaled %d\n",
+ g->name,
+ T_K, T_T0, T_Tfact, T_maxIters, T_unscaled);
}
+#endif
}
static void
double dist2;
if (cellp) {
- if (Verbose >= 3)
+#ifdef DEBUG
+ if (Verbose >= 3) {
+ prIndent();
fprintf(stderr, " doNeighbor (%d,%d) : %d\n", i, j,
gLength(cellp));
+ }
+#endif
for (; nodes != 0; nodes = nodes->next) {
p = nodes->node;
for (qs = cellp->nodes; qs != 0; qs = qs->next) {
node_list *q;
NOTUSED(dt);
- if (Verbose >= 3)
+#ifdef DEBUG
+ if (Verbose >= 3) {
+ prIndent();
fprintf(stderr, "gridRepulse (%d,%d) : %d\n", i, j,
gLength(cellp));
+ }
+#endif
for (p = nodes; p != 0; p = p->next) {
for (q = nodes; q != 0; q = q->next)
if (p != q)
typedef struct {
int useGrid; /* use grid for speed up */
int useNew; /* encode x-K into attractive force */
- long seed; /* seed for position RNG */
int numIters; /* actual iterations in layout */
- int maxIters; /* max iterations in layout */
int unscaled; /* % of iterations used in pass 1 */
double C; /* Repulsion factor in xLayout */
double Tfact; /* scale temp from default expression */
double K; /* spring constant; ideal distance */
double T0; /* initial temperature */
- seedMode smode; /* seed mode */
- int tries; /* overlap removal */
} fdpParms_t;
extern fdpParms_t fdp_parms;
/* #define MS */
/* Use alternate force function */
/* #define ALT */
-#define BOX /* Use bbox to determine overlap, else use circles */
+#define BOX /* Use bbox to determine overlap, else use circles */
/* #define OFF 0.0 */
#define OFF PS2INCH(8)
+#define DFLT_overlap "scale" /* default overlap value */
+
#define WD2(n) (ND_width(n)/2.0 + OFF)
#define HT2(n) (ND_height(n)/2.0 + OFF)
/* init_params:
* Initialize local parameters
*/
-static void init_params(char *name, int n, xparams * xpms)
+static void init_params(graph_t* g, int n, xparams * xpms)
{
xParams.K = xpms->K;
xParams.numIters = xpms->numIters;
if (Verbose) {
prIndent();
fprintf(stderr,
- "xLayout %s : n = %d K = %f T0 = %f loop %d C %f\n", name,
+ "xLayout %s(%s) : n = %d K = %f T0 = %f loop %d C %f\n",
+ g->name, GORIG(g->root)->name,
xParams.numIters, xParams.K, xParams.T0, xParams.loopcnt,
xParams.C);
}
#endif
}
-#define T0 xParams.T0
-#define K xParams.K
-#define numIters xParams.numIters
-#define loopcnt xParams.loopcnt
-#define C xParams.C
+#define X_T0 xParams.T0
+#define X_K xParams.K
+#define X_numIters xParams.numIters
+#define X_loopcnt xParams.loopcnt
+#define X_C xParams.C
+
+#define DFLT_tries 9
static double cool(int t)
{
- return (T0 * (numIters - t)) / numIters;
+ return (X_T0 * (X_numIters - t)) / X_numIters;
}
#define EPSILON 0.01
dist = sqrt(dist2);
din = RAD(p) + RAD(q);
if (ov = overlap(p, q)) {
- factor = C;
+ factor = X_C;
} else {
ov = 0;
- if (dist <= din + K)
- factor = C * (K - (dist - din)) / K;
+ if (dist <= din + X_K)
+ factor = X_C * (X_K - (dist - din)) / X_K;
else
factor = 0.0;
}
#else
force = K2 / dist2;
if ((ov = overlap(p, q)))
- force *= C;
+ force *= X_C;
#endif
+#ifdef DEBUG
if (Verbose == 4) {
+ prIndent();
dist = sqrt(dist2);
fprintf(stderr, " ov Fr %f dist %f\n", force * dist, dist);
}
+#endif
DISP(q)[0] += xdelta * force;
DISP(q)[1] += ydelta * force;
DISP(p)[0] -= xdelta * force;
xdelta = ND_pos(q)[0] - ND_pos(p)[0];
ydelta = ND_pos(q)[1] - ND_pos(p)[1];
dist = sqrt(xdelta * xdelta + ydelta * ydelta);
- force = (dout * dout) / (K * dist);
+ force = (dout * dout) / (X_K * dist);
#elif defined(ALT)
xdelta = ND_pos(q)[0] - ND_pos(p)[0];
ydelta = ND_pos(q)[1] - ND_pos(p)[1];
dist = sqrt(xdelta * xdelta + ydelta * ydelta);
din = RAD(p) + RAD(q);
- if (dist < K + din)
+ if (dist < X_K + din)
return;
dout = dist - din;
- force = (dout * dout) / ((K + din) * dist);
+ force = (dout * dout) / ((X_K + din) * dist);
#else
if (overlap(p, q)) {
- if (Verbose == 4)
+#ifdef DEBUG
+ if (Verbose == 4) {
+ prIndent();
fprintf(stderr, "ov 1 Fa 0 din %f\n", RAD(p) + RAD(q));
+ }
+#endif
return;
}
xdelta = ND_pos(q)[0] - ND_pos(p)[0];
dist = sqrt(xdelta * xdelta + ydelta * ydelta);
din = RAD(p) + RAD(q);
dout = dist - din;
- force = (dout * dout) / ((K + din) * dist);
+ force = (dout * dout) / ((X_K + din) * dist);
#endif
- if (Verbose == 4)
+#ifdef DEBUG
+ if (Verbose == 4) {
+ prIndent();
fprintf(stderr, " ov 0 Fa %f din %f \n", force * dist, din);
+ }
+#endif
DISP(q)[0] -= xdelta * force;
DISP(q)[1] -= ydelta * force;
DISP(p)[0] += xdelta * force;
double disp[NDIM]; /* incremental displacement */
int overlaps = 0;
+#ifdef DEBUG
if (Verbose == 4)
fprintf(stderr, "=================\n");
+#endif
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
DISP(n)[0] = DISP(n)[1] = 0;
* at this stage.
* Returns non-zero if overlaps still exist.
*/
-#undef K
static int x_layout(graph_t * g, xparams * pxpms, int tries)
{
double K;
xparams xpms;
-
ov = cntOverlaps(g);;
if (ov == 0)
return 0;
xpms = *pxpms;
K = xpms.K;
while (ov && (try < tries)) {
+
+#ifdef DEBUG
if (Verbose) {
- fprintf(stderr, "try %d (%d): %d overlaps on %s \n", try, tries, ov,
- g->name);
+ prIndent();
+ fprintf(stderr, "try %d (%d): %d overlaps on %s(%s) \n", try, tries, ov,
+ g->name, GORIG(g->root)->name);
}
+#endif
- init_params(g->name, nnodes, &xpms);
- for (i = 0; i < loopcnt; i++) {
+ init_params(g, nnodes, &xpms);
+ for (i = 0; i < X_loopcnt; i++) {
temp = cool(i);
if (temp <= 0.0)
break;
xpms.K += K; /* increase distance */
}
if (Verbose && ov)
- fprintf(stderr, "Warning: %d overlaps remain on %s\n", ov,
- g->name);
+ fprintf(stderr, "Warning: %d overlaps remain on %s(%s)\n", ov,
+ g->name, GORIG(g->root)->name);
return ov;
}
-/* set shape of derived cluster nodes as boxes before calling
- * adjustNodes
+/* fdp_xLayout:
+ * Use overlap parameter to determine if and how to remove overlaps.
+ * In addition to the usual values accepted by removeOverlap, overlap
+ * can begin with "n:" to indicate the given number of tries using
+ * x_layout to remove overlaps.
+ * Thus,
+ * NULL or "" => dflt overlap
+ * "mode" => dflt tries, then removeOverlap with mode
+ * "n:" => n tries only
+ * "n:mode" => n tries, then removeOverlap with mode
+ * "0:" => no overlap removal
*/
void fdp_xLayout(graph_t * g, xparams * xpms)
{
- int tries = xpms->tries;
-
- if (tries == 0) /* No overlap removal */
- return;
- else if (tries == 1) { /* No expansion, just adjust */
- removeOverlap(g);
- }
- else if (tries > 1) { /* Try expansion tries times, then adjust */
- if (x_layout(g, xpms, tries - 1))
- removeOverlap(g);
- }
- else { /* Try expansion -tries times; no adjust */
- x_layout(g, xpms, -1 * tries);
+ int tries;
+ char* ovlp = agget (g, "overlap");
+ char* cp;
+ char* rest;
+
+ if (Verbose) {
+#ifdef DEBUG
+ prIndent();
+#endif
+ fprintf (stderr, "xLayout ");
+ }
+ if (!ovlp || (*ovlp == '\0')) {
+ ovlp = DFLT_overlap;
+ }
+ if ((cp = strchr(ovlp, ':'))) {
+ cp++;
+ rest = cp;
+ tries = atoi (ovlp);
+ if (tries < 0) tries = 0;
}
+ else {
+ tries = DFLT_tries;
+ rest = ovlp;
+ }
+ if (Verbose) {
+#ifdef DEBUG
+ prIndent();
+#endif
+ fprintf (stderr, "tries = %d, mode = %s\n", tries, rest);
+ }
+ if (tries && !x_layout(g, xpms, tries))
+ return;
+ removeOverlapAs(g, rest);
+
}