in order to specify the roots of separate components.
<DT><A NAME=d:root HREF=#a:root><STRONG>root</STRONG></A>
<DD> This specifies nodes to be used as the center of the
layout and the root of the generated spanning tree. As a graph attribute,
- this gives the name of the node. As a node attribute (circo only), it
+ this gives the name of the node. As a node attribute, it
specifies that the node should be used as a central node. In twopi,
this will actually be the central node. In circo, the block containing
the node will be central in the drawing of its connected component.
<P>
If the root attribute is defined as the empty string, twopi will reset it
to name of the node picked as the root node.
+ <P>
+ For twopi, it is possible to have multiple roots, presumably one for each
+ component. If more than one node in a component is marked as the root, twopi
+ will pick one.
<DT><A NAME=d:rotate HREF=#a:rotate><STRONG>rotate</STRONG></A>
<DD> If 90, set drawing orientation to landscape.
:root:GN:string/bool:<none>(graphs)/false(nodes); twopi,circo
This specifies nodes to be used as the center of the
layout and the root of the generated spanning tree. As a graph attribute,
-this gives the name of the node. As a node attribute (circo only), it
+this gives the name of the node. As a node attribute, it
specifies that the node should be used as a central node. In twopi,
this will actually be the central node. In circo, the block containing
the node will be central in the drawing of its connected component.
<P>
If the root attribute is defined as the empty string, twopi will reset it
to name of the node picked as the root node.
+<P>
+For twopi, it is possible to have multiple roots, presumably one for each
+component. If more than one node in a component is marked as the root, twopi
+will pick one.
:rotate:G:int:0;
If 90, set drawing orientation to landscape.
:rotation:G:double:0; sfdp
twopi_init_node_edge(g);
}
+static Agnode_t* findRootNode (Agraph_t* sg, Agsym_t* rootattr)
+{
+ Agnode_t* n;
+
+ for (n = agfstnode(sg); n; n = agnxtnode(sg,n)) {
+ if (mapbool(agxget(n,rootattr))) return n;
+ }
+ return NULL;
+
+}
+
/* twopi_layout:
*/
void twopi_layout(Agraph_t * g)
Agnode_t *ctr = 0;
char *s;
int setRoot = 0;
+ int setLocalRoot = 0;
pointf sc;
int doScale = 0;
int r;
+ Agsym_t* rootattr;
if (agnnodes(g) == 0) return;
twopi_init_graph(g);
- s = agget(g, "root");
if ((s = agget(g, "root"))) {
if (*s) {
ctr = agfindnode(g, s);
setRoot = 1;
}
}
+ if ((rootattr = agattr(g, AGNODE, "root", 0))) {
+ setLocalRoot = 1;
+ }
if ((s = agget(g, "scale")) && *s) {
if ((r = sscanf (s, "%lf,%lf",&sc.x,&sc.y))) {
Agnode_t *n;
int ncc;
int i;
+ Agnode_t* lctr;
ccs = ccomps(g, &ncc, 0);
if (ncc == 1) {
- c = circleLayout(g, ctr);
+ if (ctr)
+ lctr = ctr;
+ else if (!(lctr = findRootNode(g, rootattr)))
+ lctr = 0;
+ c = circleLayout(g, lctr);
if (setRoot && !ctr)
ctr = c;
+ if (setLocalRoot && !lctr)
+ agxset (c, rootattr, "1");
n = agfstnode(g);
free(ND_alg(n));
ND_alg(n) = NULL;
for (i = 0; i < ncc; i++) {
sg = ccs[i];
if (ctr && agcontains(sg, ctr))
- c = ctr;
- else
- c = 0;
+ lctr = ctr;
+ else if (!(lctr = findRootNode(sg, rootattr)))
+ lctr = 0;
nodeInduce(sg);
- c = circleLayout(sg, c);
+ c = circleLayout(sg, lctr);
if (setRoot && !ctr)
ctr = c;
+ if (setLocalRoot && (!lctr || (lctr == ctr)))
+ agxset (c, rootattr, "1");
adjustNodes(sg);
}
n = agfstnode(g);