/* This software may only be used by you under license from AT&T Corp. ("AT&T"). A copy of AT&T's Source Code Agreement is available at AT&T's Internet website having the URL: If you received this software without first entering into a license with AT&T, you have an infringing copy of this software and cannot use it without violating AT&T's intellectual property rights. */ #pragma prototyped /* * Written by Emden R. Gansner * Derived from Graham Wills' algorithm described in GD'97. */ #include "circle.h" #include "adjust.h" #include "pack.h" #include "neatoprocs.h" void twopi_nodesize(node_t* n, boolean flip) { int w; w = ND_xsize(n) = POINTS(ND_width(n)); ND_lw_i(n) = ND_rw_i(n) = w / 2; ND_ht_i(n) = ND_ysize(n) = POINTS(ND_height(n)); } static void twopi_init_node (node_t* n) { common_init_node(n); twopi_nodesize(n,GD_left_to_right(n->graph)); ND_pos(n) = ALLOC(GD_ndim(n->graph),0,double); ND_alg(n) = (void*)NEW(cdata); } static void twopi_initPort(node_t* n, edge_t* e, char* name) { port_t port; if (name == NULL) return; port = ND_shape(n)->portfn(n,name); #ifdef NOTDEF if (n->GD_left_to_right(graph)) port.p = invflip_pt(port.p); #endif port.order = 0; if (e->tail == n) ED_tail_port(e) = port; else ED_head_port(e) = port; } static void twopi_init_edge (edge_t* e) { common_init_edge(e); ED_factor(e) = late_double(e,E_weight,1.0,0.0); twopi_initPort(e->tail,e,agget(e,"tailport")); twopi_initPort(e->head,e,agget(e,"headport")); } static void twopi_init_node_edge(graph_t *g) { node_t* n; edge_t* e; char* str; int i = 0; GD_neato_nlist(g) = N_NEW(agnnodes(g) + 1,node_t*); for (n = agfstnode(g); n; n = agnxtnode(g,n)) { GD_neato_nlist(g)[i++] = n; twopi_init_node(n); } for (n = agfstnode(g); n; n = agnxtnode(g,n)) { for (e = agfstout(g,n); e; e = agnxtout(g,e)) { twopi_init_edge(e); str = agget(e,"label"); if (str && str[0]) GD_has_edge_labels(g) = TRUE; } } } void twopi_init_graph(graph_t *g) { UseRankdir = FALSE; graph_init(g); GD_drawing(g)->engine = TWOPI; /* GD_ndim(g) = late_int(g,agfindattr(g,"dim"),2,2); */ Ndim = GD_ndim(g) = 2; /* The algorithm only makes sense in 2D */ twopi_init_node_edge(g); } /* twopi_layout: */ void twopi_layout(Agraph_t* g) { Agnode_t* ctr = 0; char* s; twopi_init_graph(g); s = agget (g, "root"); if (s && (*s != '\0')) { ctr = agfindnode (g, s); if (!ctr) { agerr (AGWARN, "specified root node \"%s\" was not found.", s); agerr (AGPREV, "Using default calculation for root node\n"); } } if (agnnodes(g)) { Agraph_t** ccs; Agraph_t* sg; Agnode_t* c = NULL; int ncc; int i; ccs = ccomps (g, &ncc, 0); if (ncc == 1) { circleLayout (g,ctr); adjustNodes (g); spline_edges(g); } else { pack_info pinfo; pack_mode pmode = getPackMode (g,l_node); for (i = 0; i < ncc; i++) { sg = ccs[i]; if (ctr && agcontains (sg, ctr)) c = ctr; else c = 0; nodeInduce (sg); circleLayout (sg,c); adjustNodes (sg); } spline_edges(g); pinfo.margin = getPack (g, CL_OFFSET, CL_OFFSET); pinfo.doSplines = 1; pinfo.mode = pmode; pinfo.fixed = 0; packSubgraphs (ncc, ccs, g, &pinfo); } for (i = 0; i < ncc; i++) { agdelete (g, ccs[i]); } } dotneato_postprocess(g, twopi_nodesize); } static void twopi_cleanup_node(node_t* n) { free (ND_alg(n)); if (ND_shape(n)) ND_shape(n)->freefn(n); free_label(ND_label(n)); memset(&(n->u),0,sizeof(Agnodeinfo_t)); } static void twopi_free_splines(edge_t* e) { int i; if (ED_spl(e)) { for (i = 0; i < ED_spl(e)->size; i++) free(ED_spl(e)->list[i].list); free(ED_spl(e)->list); free(ED_spl(e)); } ED_spl(e) = NULL; } static void twopi_cleanup_edge(edge_t* e) { twopi_free_splines(e); free_label(ED_label(e)); memset(&(e->u),0,sizeof(Agedgeinfo_t)); } static void twopi_cleanup_graph(graph_t* g) { free(GD_neato_nlist(g)); free_ugraph(g); free_label(GD_label(g)); memset(&(g->u),0,sizeof(Agraphinfo_t)); } void twopi_cleanup(graph_t* g) { node_t *n; edge_t *e; for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { twopi_cleanup_edge(e); } twopi_cleanup_node(n); } twopi_cleanup_graph(g); }