43#define GRAPHTYPEMASK 192
45#define MAKEFWDEDGE(new, old) \
50 info = (Agedgeinfo_t *)newp->base.data; \
51 *info = *(Agedgeinfo_t *)old->base.data; \
53 newp->base.data = (Agrec_t *)info; \
54 AGTAIL(newp) = AGHEAD(old); \
55 AGHEAD(newp) = AGTAIL(old); \
56 ED_tail_port(newp) = ED_head_port(old); \
57 ED_head_port(newp) = ED_tail_port(old); \
58 ED_edge_type(newp) = VIRTUAL; \
59 ED_to_orig(newp) = old; \
79static int edgecmp(
const void *,
const void *);
81 unsigned,
unsigned,
int);
83 unsigned,
unsigned,
int);
99 edges = gv_recalloc(edges, n_edges, n_edges + CHUNK, sizeof(edge_t *)); \
148 const size_t sz = b->
size;
149 for (
size_t i = 0; i < sz / 2; ++i) {
152 b->
list[sz - 1 - i] = tmp;
156 uint32_t tmp = b->
sflag;
168 const size_t sz =
s->size;
171 for (
size_t i = 0; i < sz / 2; ++i) {
174 s->
list[sz - 1 - i] = tmp;
178 for (
size_t i = 0; i < sz; ++i) {
212 double tmp =
ND_rw(n);
253 int i, j, k, n_nodes;
257 edge_t *e, *e0, *e1, *ea, *eb, *le0, *le1, **edges =
NULL;
268 agwarningf(
"edge labels with splines=curved not supported in dot - use "
294 unsigned n_edges = 0;
305 for (j = 0; j <
GD_rank(g)[i].n; j++) {
318 for (k = 0; (e =
ND_out(n).list[k]); k++) {
322 edges[n_edges++] = e;
323 if (n_edges %
CHUNK == 0)
329 edges[n_edges++] = e;
330 if (n_edges %
CHUNK == 0)
340 double tmp =
ND_rw(n);
344 for (k = 0; (e =
ND_other(n).list[k]); k++) {
346 edges[n_edges++] = e;
347 if (n_edges %
CHUNK == 0)
360 qsort(edges, n_edges,
sizeof(edges[0]),
edgecmp);
375 for (
unsigned l = 0; l < n_edges;) {
376 const unsigned ind = l;
388 for (
cnt = 1; l < n_edges;
cnt++, l++) {
416 for (
unsigned ii = 1; ii <
cnt; ii++)
435 sizey =
MIN(upy, dwny);
438 for (
unsigned b = 0; b <
cnt; b++) {
514 if (
ND_in(n).size == 0)
564static int edgecmp(
const void *x,
const void *y) {
569#pragma GCC diagnostic push
570#pragma GCC diagnostic ignored "-Wcast-qual"
575#pragma GCC diagnostic pop
579 edge_t *e0, *e1, *ea, *eb, *le0, *le1;
580 int et0, et1, v0, v1, rv;
953#pragma GCC diagnostic push
954#pragma GCC diagnostic ignored "-Wcast-qual"
959#pragma GCC diagnostic pop
997 unsigned ind,
unsigned cnt,
int et,
1002 double leftend, rightend, ctrx, ctry, miny, maxy;
1003 double uminx, umaxx;
1004 double lminx = 0.0, lmaxx = 0.0;
1008 for (
unsigned i = 0; i <
cnt; i++) {
1009 earray[i] = edges[ind + i];
1017 leftend = tp.
x +
ND_rw(tn);
1018 rightend = hp.
x -
ND_lw(hn);
1019 ctrx = (leftend + rightend) / 2.0;
1034 maxy = miny +
ED_label(e)->dimen.y;
1035 uminx = ctrx -
ED_label(e)->dimen.x / 2.0;
1036 umaxx = ctrx +
ED_label(e)->dimen.x / 2.0;
1039 for (i = 1; i < n_lbls; i++) {
1043 lminx = ctrx -
ED_label(e)->dimen.x / 2.0;
1044 lmaxx = ctrx +
ED_label(e)->dimen.x / 2.0;
1061 ctry = miny +
ED_label(e)->dimen.y / 2.0;
1085 if (
ps ==
NULL || pn == 0) {
1098 for (; i <
cnt; i++) {
1102 lminx = (2 * leftend + rightend) / 3.0;
1103 lmaxx = (leftend + 2 * rightend) / 3.0;
1142 if (
ps ==
NULL || pn == 0) {
1155 unsigned cnt,
int et) {
1163 stepy =
cnt > 1 ?
ND_ht(tn) / (double)(
cnt - 1) : 0.;
1166 for (
unsigned i = 0; i <
cnt; i++) {
1209 double midx, midy, leftx, rightx;
1212 static atomic_flag warned;
1216 if (!atomic_flag_test_and_set(&warned)) {
1217 agwarningf(
"flat edge between adjacent nodes one of which has a record "
1218 "shape - replace records with HTML-like labels\n");
1224 unsigned labels = 0;
1226 for (
unsigned i = 0; i <
cnt; i++) {
1248 subg =
agsubg(auxg,
"xxx", 1);
1250 agset(subg,
"rank",
"source");
1260 for (
unsigned i = 0; i <
cnt; i++) {
1294 }
else if (n == auxh) {
1312 for (
unsigned i = 0; i <
cnt; i++) {
1320 if ((auxe == hvye) & !
ED_alg(auxe))
1328 for (
size_t j = 0; j < auxbz->
size;) {
1332 if (j >= auxbz->
size)
1389 bool ps_needs_free =
false;
1465 const size_t boxn =
sizeof(boxes) /
sizeof(boxes[0]);
1467 for (i = 0; i < tend.
boxn; i++)
1469 for (
size_t j = 0; j < boxn; j++)
1471 for (i = hend.
boxn - 1; i >= 0; i--)
1474 ps_needs_free =
true;
1490 edge_t **edges,
unsigned ind,
unsigned cnt,
1491 edge_t *e,
bool use_splines) {
1494 double stepx, stepy, vspace;
1509 stepy = vspace / (
cnt + 1);
1514 for (
unsigned i = 0; i <
cnt; i++) {
1522 boxes[boxn].
LL.
x = b.
LL.
x;
1523 boxes[boxn].
UR.
y = b.
LL.
y;
1524 boxes[boxn].
UR.
x = b.
UR.
x + (i + 1) * stepx;
1525 boxes[boxn].
LL.
y = b.
LL.
y - (i + 1) * stepy;
1528 boxes[boxn].
UR.
y = boxes[boxn - 1].
LL.
y;
1530 boxes[boxn].
LL.
y = boxes[boxn].
UR.
y - stepy;
1533 boxes[boxn].
UR.
x = b.
UR.
x;
1534 boxes[boxn].
UR.
y = b.
LL.
y;
1535 boxes[boxn].
LL.
x = b.
LL.
x - (i + 1) * stepx;
1536 boxes[boxn].
LL.
y = boxes[boxn - 1].
UR.
y;
1538 assert(boxn ==
sizeof(boxes) /
sizeof(boxes[0]));
1540 for (j = 0; j < tend.
boxn; j++)
1542 for (
size_t k = 0; k < boxn; k++)
1544 for (j = hend.
boxn - 1; j >= 0; j--)
1573 edge_t **edges,
unsigned ind,
unsigned cnt,
int et) {
1579 double stepx, stepy, vspace;
1592 for (
unsigned i = 1; i <
cnt; i++) {
1637 stepy = vspace / (
cnt + 1);
1642 for (
unsigned i = 0; i <
cnt; i++) {
1650 boxes[boxn].
LL.
x = b.
LL.
x;
1651 boxes[boxn].
LL.
y = b.
UR.
y;
1652 boxes[boxn].
UR.
x = b.
UR.
x + (i + 1) * stepx;
1653 boxes[boxn].
UR.
y = b.
UR.
y + (i + 1) * stepy;
1656 boxes[boxn].
LL.
y = boxes[boxn - 1].
UR.
y;
1658 boxes[boxn].
UR.
y = boxes[boxn].
LL.
y + stepy;
1661 boxes[boxn].
UR.
x = b.
UR.
x;
1662 boxes[boxn].
LL.
y = b.
UR.
y;
1663 boxes[boxn].
LL.
x = b.
LL.
x - (i + 1) * stepx;
1664 boxes[boxn].
UR.
y = boxes[boxn - 1].
LL.
y;
1666 assert(boxn ==
sizeof(boxes) /
sizeof(boxes[0]));
1668 for (j = 0; j < tend.
boxn; j++)
1670 for (
size_t k = 0; k < boxn; k++)
1672 for (j = hend.
boxn - 1; j >= 0; j--)
1693 return (p1.
y - p2.
y) * (p3.
x - p2.
x) - (p3.
y - p2.
y) * (p1.
x - p2.
x) > 0;
1718 double width, height;
1748 if (
leftOf(endp, startp, lp)) {
1749 lp.
x += width / 2.0;
1750 lp.
y -= height / 2.0;
1752 lp.
x -= width / 2.0;
1753 lp.
y += height / 2.0;
1756 points_append(
points, startp);
1757 points_append(
points, startp);
1758 points_append(
points, lp);
1759 points_append(
points, lp);
1760 points_append(
points, lp);
1761 points_append(
points, endp);
1762 points_append(
points, endp);
1765 points_append(
points, startp);
1766 points_append(
points, startp);
1767 points_append(
points, endp);
1768 points_append(
points, endp);
1776 edge_t **edges,
unsigned ind,
unsigned cnt,
1785 points_t pointfs = {0};
1786 points_t pointfs2 = {0};
1794 bool hackflag =
false;
1834 boxes_t boxes = {0};
1854 if (!smode || si > 0) {
1878 ps[3] =
ps[2] =
ps[pn - 1];
1885 points_free(&pointfs);
1886 points_free(&pointfs2);
1890 for (
size_t i = 0; i < pn; i++) {
1891 points_append(&pointfs,
ps[i]);
1899 boxes_clear(&boxes);
1913 b.
UR.
y = hend.boxes[hend.boxn - 1].UR.y;
1914 b.
LL.
y = hend.boxes[hend.boxn - 1].LL.y;
1917 hend.boxes[hend.boxn++] = b;
1932 ps[3] =
ps[2] =
ps[pn - 1];
1937 points_free(&pointfs);
1938 points_free(&pointfs2);
1941 for (
size_t i = 0; i < pn; i++) {
1942 points_append(&pointfs,
ps[i]);
1952 points_sync(&pointfs);
1955 points_free(&pointfs);
1956 points_free(&pointfs2);
1960 for (
size_t k = 1; k + 1 < points_size(&pointfs); k++)
1961 points_at(&pointfs, k)->x -=
dx;
1963 for (
size_t k = 0; k < points_size(&pointfs); k++)
1964 points_append(&pointfs2, points_get(&pointfs, k));
1965 points_sync(&pointfs2);
1968 for (
unsigned j = 1; j <
cnt; j++) {
1974 for (
size_t k = 1; k + 1 < points_size(&pointfs); k++)
1975 points_at(&pointfs, k)->x += sp->
Multisep;
1976 points_clear(&pointfs2);
1977 for (
size_t k = 0; k < points_size(&pointfs); k++)
1978 points_append(&pointfs2, points_get(&pointfs, k));
1979 points_sync(&pointfs2);
1981 points_size(&pointfs2), &
sinfo);
1983 points_free(&pointfs);
1984 points_free(&pointfs2);
1991 const boxes_t *boxes) {
1992 edge_t *uleft, *uright, *lleft, *lright;
1994 uleft = uright =
NULL;
2004 lleft = lright =
NULL;
2014 for (
int i = 0; i < tendp->
boxn; i++)
2016 const size_t fb = P->
nbox + 1;
2017 const size_t lb = fb + boxes_size(boxes) - 3;
2018 for (
size_t i = 0; i < boxes_size(boxes); i++)
2019 add_box(P, boxes_get(boxes, i));
2020 for (
int i = hendp->
boxn - 1; i >= 0; i--)
2056 for (
size_t i = fb - 1; i < lb + 1; i++) {
2058 if ((i - fb) % 2 == 0) {
2059 if (bp1->
LL.
x >= bp1->
UR.
x) {
2060 double x = (bp1->
LL.
x + bp1->
UR.
x) / 2;
2066 double x = (bp1->
LL.
x + bp1->
UR.
x) / 2;
2072 for (
size_t i = 0; i + 1 < P->
nbox; i++) {
2074 if (i >= fb && i <= lb && (i - fb) % 2 == 0) {
2077 if (bp1->
UR.
x - MINW < bp2->LL.x)
2079 }
else if (i + 1 >= fb && i < lb && (i + 1 - fb) % 2 == 0) {
2082 if (bp1->
UR.
x - MINW < bp2->LL.x)
2095 left1 =
GD_rank(g)[r + 1].v[0];
2129 assert(!points_is_empty(plist));
2130 points_append(plist, points_get(plist, points_size(plist) - 1));
2131 points_append(plist, points_get(plist, points_size(plist) - 1));
2183 for (i = 0; (f =
ND_in(
aghead(e)).list[i]); i++) {
2207#define REAL_CLUSTER(n) (ND_clust(n) == g ? NULL : ND_clust(n))
2225 if (cl && cl != tcl && cl != hcl)
2230 if (cl && cl != tcl && cl != hcl &&
cl_vninside(cl, adj))
2234 if (cl && cl != tcl && cl != hcl &&
cl_vninside(cl, adj))
2258 left_cl = right_cl =
NULL;
2316 for (i =
ND_order(vn) + dir; i >= 0 && i <
rank->n; i += dir) {
2343 if (
ND_out(n0).size == 1 && e1) {
2359 if (
ND_in(n0).size == 1 && e1) {
2360 e0 =
ND_in(n0).list[0];
2368 e0 =
ND_in(na).list[0];
2371 e1 =
ND_in(nb).list[0];
2378void showpath(
path *p) {
2381 fprintf(stderr,
"%%!PS\n");
2382 for (
size_t i = 0; i < p->
nbox; i++) {
2386 "newpath %.04f %.04f moveto %.04f %.04f lineto %.04f %.04f lineto "
2387 "%.04f %.04f lineto closepath stroke\n",
2388 LL.
x, LL.
y, UR.
x, LL.
y, UR.
x, UR.
y, LL.
x, UR.
y);
2390 fprintf(stderr,
"showpage\n");
int normalize(graph_t *g)
static agxbuf last
last message
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static WUR char * agxbuse(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
static void * gv_alloc(size_t size)
void setEdgeType(graph_t *g, int defaultValue)
void updateBB(graph_t *g, textlabel_t *lp)
void dot_init_node_edge(graph_t *g)
void dot_cleanup(graph_t *g)
void dot_mincross(Agraph_t *)
void dot_sameports(Agraph_t *)
void dot_rank(Agraph_t *)
void dot_position(Agraph_t *)
static bool leftOf(pointf p1, pointf p2, pointf p3)
Return true if p3 is to left of ray p1->p2.
static boxf maximal_bbox(graph_t *g, spline_info_t *, Agnode_t *, Agedge_t *, Agedge_t *)
static void make_flat_bottom_edges(graph_t *g, spline_info_t *sp, path *P, edge_t **edges, unsigned ind, unsigned cnt, edge_t *e, bool use_splines)
static void swap_bezier(bezier *b)
static void make_flat_edge(graph_t *, spline_info_t *, path *, Agedge_t **, unsigned, unsigned, int)
static int straight_len(Agnode_t *)
static bool pathscross(Agnode_t *, Agnode_t *, Agedge_t *, Agedge_t *)
static edge_t * cloneEdge(graph_t *g, node_t *tn, node_t *hn, edge_t *orig)
static void setState(graph_t *auxg, attr_state_t *attr_state)
static void edge_normalize(graph_t *g)
static void makeSimpleFlatLabels(node_t *tn, node_t *hn, edge_t **edges, unsigned ind, unsigned cnt, int et, unsigned n_lbls)
static int makeLineEdge(graph_t *g, edge_t *fe, points_t *points, node_t **hp)
static Agedge_t * top_bound(Agedge_t *, int)
static bool swap_ends_p(edge_t *e)
int portcmp(port p0, port p1)
static void make_flat_labeled_edge(graph_t *g, spline_info_t *sp, path *P, edge_t *e, int et)
static bool spline_merge(node_t *n)
static void setEdgeLabelPos(graph_t *g)
static void make_flat_adj_edges(graph_t *g, edge_t **edges, unsigned ind, unsigned cnt, edge_t *e0, int et)
static bool cl_vninside(Agraph_t *, Agnode_t *)
static void place_vnlabel(Agnode_t *)
static Agraph_t * cl_bound(graph_t *, Agnode_t *, Agnode_t *)
static void make_regular_edge(graph_t *g, spline_info_t *, path *, Agedge_t **, unsigned, unsigned, int)
static void adjustregularpath(path *, size_t, size_t)
static graph_t * cloneGraph(graph_t *g, attr_state_t *attr_state)
#define MAKEFWDEDGE(new, old)
static void dot_splines_(graph_t *g, int normalize)
static boxf makeregularend(boxf, int, double)
static edge_t * getmainedge(edge_t *e)
static boxf rank_box(spline_info_t *sp, Agraph_t *, int)
static void cleanupCloneGraph(graph_t *g, attr_state_t *attr_state)
static void makeBottomFlatEnd(graph_t *g, spline_info_t *sp, path *P, node_t *n, edge_t *e, pathend_t *endp, bool isBegin)
static void recover_slack(Agedge_t *, path *)
static void makeFlatEnd(graph_t *g, spline_info_t *sp, path *P, node_t *n, edge_t *e, pathend_t *endp, bool isBegin)
static Agedge_t * straight_path(Agedge_t *, int, points_t *)
static int edgecmp(const void *, const void *)
void dot_splines(graph_t *g)
static int edgelblcmpfn(const void *x, const void *y)
static void resize_vn(Agnode_t *, double, double, double)
static void resetRW(graph_t *g)
static void makeSimpleFlat(node_t *tn, node_t *hn, edge_t **edges, unsigned ind, unsigned cnt, int et)
static void completeregularpath(path *, Agedge_t *, Agedge_t *, pathend_t *, pathend_t *, const boxes_t *)
static void setflags(Agedge_t *, int, int, int)
static pointf transformf(pointf p, pointf del, int flip)
static void swap_spline(splines *s)
static Agedge_t * bot_bound(Agedge_t *, int)
static node_t * cloneNode(graph_t *g, node_t *orign)
static void del(Dict_t *d, Dtlink_t **set, Agedge_t *e)
void update_bb_bz(boxf *bb, pointf *cp)
static pointf add_pointf(pointf p, pointf q)
Agsym_t * E_labelfontsize
Agsym_t * E_labelfontname
Agsym_t * E_labelfontcolor
Agsym_t * E_labeldistance
static int cnt(Dict_t *d, Dtlink_t **set)
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
int agset(void *obj, char *name, const char *value)
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
permits traversing the list of attributes of a given type
int agxset(void *obj, Agsym_t *sym, const char *value)
int agcopyattr(void *oldobj, void *newobj)
copies all of the attributes from one object to another
Agsym_t * agattr_html(Agraph_t *g, int kind, char *name, const char *value)
agattr, but creates HTML-like values
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Agedge_t * agnxtin(Agraph_t *g, Agedge_t *e)
#define agfindedgeattr(g, a)
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Agedge_t * agfstin(Agraph_t *g, Agnode_t *n)
#define AGOUT2IN(outedge)
Agedgepair_s.out -> Agedgepair_s.in/*#end#*/.
void agwarningf(const char *fmt,...)
int agerr(agerrlevel_t level, const char *fmt,...)
#define agfindgraphattr(g, a)
Agdesc_t Agundirected
undirected
int agisdirected(Agraph_t *g)
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Agdesc_t Agdirected
directed
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Agnode_t * agfstnode(Agraph_t *g)
#define agfindnodeattr(g, a)
Agraph_t * agraphof(void *obj)
char * agnameof(void *)
returns a string descriptor for the object.
Agraph_t * agroot(void *obj)
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
int aghtmlstr(const char *)
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
void mark_lowclusters(Agraph_t *root)
#define DEFINE_LIST(name, type)
#define neighbor(t, i, edim, elist)
int rank(graph_t *g, int balance, int maxiter)
void orthoEdges(Agraph_t *g, bool useLbls)
void dotneato_postprocess(Agraph_t *g)
bezier * new_spline(edge_t *e, size_t sz)
splines * getsplinepoints(edge_t *e)
void clip_and_install(edge_t *fe, node_t *hn, pointf *ps, size_t pn, splineInfo *info)
pointf * simpleSplineRoute(pointf, pointf, Ppoly_t, size_t *, int)
Given a simple (ccw) polygon, route an edge from tp to hp.
int routesplinesinit(void)
shape_kind shapeOf(node_t *)
void add_box(path *, boxf)
void beginpath(path *, Agedge_t *, int, pathend_t *, bool)
pointf * routesplines(path *, size_t *)
void routesplinesterm(void)
void makeSelfEdge(edge_t *edges[], size_t ind, size_t cnt, double sizex, double sizey, splineInfo *sinfo)
void endpath(path *, Agedge_t *, int, pathend_t *, bool)
pointf * routepolylines(path *pp, size_t *npoints)
int place_portlabel(edge_t *e, bool head_p)
void makeStraightEdges(graph_t *g, edge_t **edges, size_t e_cnt, int et, splineInfo *sinfo)
Agrec_t * data
stores programmer-defined data, access with AGDATA
Agraph_t * root
subgraphs - ancestors
implementation of Agrec_t
attrsym_t * N_peripheries
attrsym_t * E_label_float
attrsym_t * E_labelfontname
attrsym_t * E_labelfontcolor
attrsym_t * N_orientation
attrsym_t * E_labelfontsize
size_t nbox
number of subdivisions
bool(* swapEnds)(edge_t *e)
bool(* splineMerge)(node_t *n)
#define SET_RANKDIR(g, rd)