dotsplines.c 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. /*
  11. * set edge splines.
  12. */
  13. #include <assert.h>
  14. #include <cgraph/list.h>
  15. #include <common/boxes.h>
  16. #include <dotgen/dot.h>
  17. #include <math.h>
  18. #include <stdbool.h>
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <util/agxbuf.h>
  23. #include <util/alloc.h>
  24. #ifdef ORTHO
  25. #include <ortho/ortho.h>
  26. #endif
  27. #define NSUB 9 /* number of subdivisions, re-aiming splines */
  28. #define CHUNK 128 /* in building list of edges */
  29. #define MINW 16 /* minimum width of a box in the edge path */
  30. #define HALFMINW 8
  31. #define FWDEDGE 16
  32. #define BWDEDGE 32
  33. #define MAINGRAPH 64
  34. #define AUXGRAPH 128
  35. #define GRAPHTYPEMASK 192 /* the OR of the above */
  36. #define MAKEFWDEDGE(new, old) \
  37. { \
  38. edge_t *newp; \
  39. Agedgeinfo_t *info; \
  40. newp = new; \
  41. info = (Agedgeinfo_t *)newp->base.data; \
  42. *info = *(Agedgeinfo_t *)old->base.data; \
  43. *newp = *old; \
  44. newp->base.data = (Agrec_t *)info; \
  45. AGTAIL(newp) = AGHEAD(old); \
  46. AGHEAD(newp) = AGTAIL(old); \
  47. ED_tail_port(newp) = ED_head_port(old); \
  48. ED_head_port(newp) = ED_tail_port(old); \
  49. ED_edge_type(newp) = VIRTUAL; \
  50. ED_to_orig(newp) = old; \
  51. }
  52. typedef struct {
  53. double LeftBound;
  54. double RightBound;
  55. double Splinesep;
  56. double Multisep;
  57. boxf *Rank_box;
  58. } spline_info_t;
  59. DEFINE_LIST(points, pointf)
  60. static void adjustregularpath(path *, size_t, size_t);
  61. static Agedge_t *bot_bound(Agedge_t *, int);
  62. static bool pathscross(Agnode_t *, Agnode_t *, Agedge_t *, Agedge_t *);
  63. static Agraph_t *cl_bound(graph_t *, Agnode_t *, Agnode_t *);
  64. static bool cl_vninside(Agraph_t *, Agnode_t *);
  65. static void completeregularpath(path *, Agedge_t *, Agedge_t *, pathend_t *,
  66. pathend_t *, const boxes_t *);
  67. static int edgecmp(const void *, const void *);
  68. static void make_flat_edge(graph_t *, spline_info_t *, path *, Agedge_t **,
  69. unsigned, unsigned, int);
  70. static void make_regular_edge(graph_t *g, spline_info_t *, path *, Agedge_t **,
  71. unsigned, unsigned, int);
  72. static boxf makeregularend(boxf, int, double);
  73. static boxf maximal_bbox(graph_t *g, spline_info_t *, Agnode_t *, Agedge_t *,
  74. Agedge_t *);
  75. static Agnode_t *neighbor(graph_t *, Agnode_t *, Agedge_t *, Agedge_t *, int);
  76. static void place_vnlabel(Agnode_t *);
  77. static boxf rank_box(spline_info_t *sp, Agraph_t *, int);
  78. static void recover_slack(Agedge_t *, path *);
  79. static void resize_vn(Agnode_t *, double, double, double);
  80. static void setflags(Agedge_t *, int, int, int);
  81. static int straight_len(Agnode_t *);
  82. static Agedge_t *straight_path(Agedge_t *, int, points_t *);
  83. static Agedge_t *top_bound(Agedge_t *, int);
  84. #define GROWEDGES \
  85. do { \
  86. edges = gv_recalloc(edges, n_edges, n_edges + CHUNK, sizeof(edge_t *)); \
  87. } while (0)
  88. static edge_t *getmainedge(edge_t *e) {
  89. edge_t *le = e;
  90. while (ED_to_virt(le))
  91. le = ED_to_virt(le);
  92. while (ED_to_orig(le))
  93. le = ED_to_orig(le);
  94. return le;
  95. }
  96. static bool spline_merge(node_t *n) {
  97. return ND_node_type(n) == VIRTUAL &&
  98. (ND_in(n).size > 1 || ND_out(n).size > 1);
  99. }
  100. static bool swap_ends_p(edge_t *e) {
  101. while (ED_to_orig(e))
  102. e = ED_to_orig(e);
  103. if (ND_rank(aghead(e)) > ND_rank(agtail(e)))
  104. return false;
  105. if (ND_rank(aghead(e)) < ND_rank(agtail(e)))
  106. return true;
  107. if (ND_order(aghead(e)) >= ND_order(agtail(e)))
  108. return false;
  109. return true;
  110. }
  111. static splineInfo sinfo = {.swapEnds = swap_ends_p,
  112. .splineMerge = spline_merge};
  113. int portcmp(port p0, port p1) {
  114. if (!p1.defined)
  115. return p0.defined ? 1 : 0;
  116. if (!p0.defined)
  117. return -1;
  118. if (p0.p.x < p1.p.x)
  119. return -1;
  120. if (p0.p.x > p1.p.x)
  121. return 1;
  122. if (p0.p.y < p1.p.y)
  123. return -1;
  124. if (p0.p.y > p1.p.y)
  125. return 1;
  126. return 0;
  127. }
  128. static void swap_bezier(bezier *b) {
  129. const size_t sz = b->size;
  130. for (size_t i = 0; i < sz / 2; ++i) { // reverse list of points
  131. pointf tmp = b->list[i];
  132. b->list[i] = b->list[sz - 1 - i];
  133. b->list[sz - 1 - i] = tmp;
  134. }
  135. {
  136. uint32_t tmp = b->sflag;
  137. b->sflag = b->eflag;
  138. b->eflag = tmp;
  139. }
  140. {
  141. pointf tmp = b->sp;
  142. b->sp = b->ep;
  143. b->ep = tmp;
  144. }
  145. }
  146. static void swap_spline(splines *s) {
  147. const size_t sz = s->size;
  148. // reverse list
  149. for (size_t i = 0; i < sz / 2; ++i) {
  150. bezier tmp = s->list[i];
  151. s->list[i] = s->list[sz - 1 - i];
  152. s->list[sz - 1 - i] = tmp;
  153. }
  154. // swap beziers
  155. for (size_t i = 0; i < sz; ++i) {
  156. swap_bezier(&s->list[i]);
  157. }
  158. }
  159. /* edge_normalize:
  160. * Some back edges are reversed during layout and the reversed edge
  161. * is used to compute the spline. We would like to guarantee that
  162. * the order of control points always goes from tail to head, so
  163. * we reverse them if necessary.
  164. */
  165. static void edge_normalize(graph_t *g) {
  166. edge_t *e;
  167. node_t *n;
  168. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  169. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  170. if (sinfo.swapEnds(e) && ED_spl(e))
  171. swap_spline(ED_spl(e));
  172. }
  173. }
  174. }
  175. /* resetRW:
  176. * In position, each node has its rw stored in mval and,
  177. * if a node is part of a loop, rw may be increased to
  178. * reflect the loops and associated labels. We restore
  179. * the original value here.
  180. */
  181. static void resetRW(graph_t *g) {
  182. node_t *n;
  183. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  184. if (ND_other(n).list) {
  185. double tmp = ND_rw(n);
  186. ND_rw(n) = ND_mval(n);
  187. ND_mval(n) = tmp;
  188. }
  189. }
  190. }
  191. /* setEdgeLabelPos:
  192. * Set edge label position information for regular and non-adjacent flat edges.
  193. * Dot has allocated space and position for these labels. This info will be
  194. * used when routing orthogonal edges.
  195. */
  196. static void setEdgeLabelPos(graph_t *g) {
  197. node_t *n;
  198. textlabel_t *l;
  199. /* place regular edge labels */
  200. for (n = GD_nlist(g); n; n = ND_next(n)) {
  201. if (ND_node_type(n) == VIRTUAL) {
  202. if (ND_alg(n)) { // label of non-adjacent flat edge
  203. edge_t *fe = ND_alg(n);
  204. l = ED_label(fe);
  205. assert(l);
  206. l->pos = ND_coord(n);
  207. l->set = true;
  208. } else if ((l = ND_label(n))) { // label of regular edge
  209. place_vnlabel(n);
  210. }
  211. if (l)
  212. updateBB(g, l);
  213. }
  214. }
  215. }
  216. /** Main spline routing code.
  217. * The normalize parameter allows this function to be called by the
  218. * recursive call in make_flat_edge without normalization occurring,
  219. * so that the edge will only be normalized once in the top level call
  220. * of dot_splines.
  221. */
  222. static void dot_splines_(graph_t *g, int normalize) {
  223. int i, j, k, n_nodes;
  224. node_t *n;
  225. Agedgeinfo_t fwdedgeai, fwdedgebi;
  226. Agedgepair_t fwdedgea, fwdedgeb;
  227. edge_t *e, *e0, *e1, *ea, *eb, *le0, *le1, **edges = NULL;
  228. path P = {0};
  229. int et = EDGE_TYPE(g);
  230. fwdedgea.out.base.data = (Agrec_t *)&fwdedgeai;
  231. fwdedgeb.out.base.data = (Agrec_t *)&fwdedgebi;
  232. if (et == EDGETYPE_NONE)
  233. return;
  234. if (et == EDGETYPE_CURVED) {
  235. resetRW(g);
  236. if (GD_has_labels(g->root) & EDGE_LABEL) {
  237. agwarningf("edge labels with splines=curved not supported in dot - use "
  238. "xlabels\n");
  239. }
  240. }
  241. #ifdef ORTHO
  242. if (et == EDGETYPE_ORTHO) {
  243. resetRW(g);
  244. if (GD_has_labels(g->root) & EDGE_LABEL) {
  245. setEdgeLabelPos(g);
  246. orthoEdges(g, true);
  247. } else
  248. orthoEdges(g, false);
  249. goto finish;
  250. }
  251. #else
  252. (void)setEdgeLabelPos;
  253. #endif
  254. mark_lowclusters(g);
  255. if (routesplinesinit())
  256. return;
  257. spline_info_t sd = {.Splinesep = GD_nodesep(g) / 4,
  258. .Multisep = GD_nodesep(g)};
  259. edges = gv_calloc(CHUNK, sizeof(edge_t *));
  260. /* compute boundaries and list of splines */
  261. unsigned n_edges = 0;
  262. n_nodes = 0;
  263. for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
  264. n_nodes += GD_rank(g)[i].n;
  265. if ((n = GD_rank(g)[i].v[0]))
  266. sd.LeftBound = MIN(sd.LeftBound, (ND_coord(n).x - ND_lw(n)));
  267. if (GD_rank(g)[i].n && (n = GD_rank(g)[i].v[GD_rank(g)[i].n - 1]))
  268. sd.RightBound = MAX(sd.RightBound, (ND_coord(n).x + ND_rw(n)));
  269. sd.LeftBound -= MINW;
  270. sd.RightBound += MINW;
  271. for (j = 0; j < GD_rank(g)[i].n; j++) {
  272. n = GD_rank(g)[i].v[j];
  273. /* if n is the label of a flat edge, copy its position to
  274. * the label.
  275. */
  276. if (ND_alg(n)) {
  277. edge_t *fe = ND_alg(n);
  278. assert(ED_label(fe));
  279. ED_label(fe)->pos = ND_coord(n);
  280. ED_label(fe)->set = true;
  281. }
  282. if (ND_node_type(n) != NORMAL && !sinfo.splineMerge(n))
  283. continue;
  284. for (k = 0; (e = ND_out(n).list[k]); k++) {
  285. if (ED_edge_type(e) == FLATORDER || ED_edge_type(e) == IGNORED)
  286. continue;
  287. setflags(e, REGULAREDGE, FWDEDGE, MAINGRAPH);
  288. edges[n_edges++] = e;
  289. if (n_edges % CHUNK == 0)
  290. GROWEDGES;
  291. }
  292. if (ND_flat_out(n).list)
  293. for (k = 0; (e = ND_flat_out(n).list[k]); k++) {
  294. setflags(e, FLATEDGE, 0, AUXGRAPH);
  295. edges[n_edges++] = e;
  296. if (n_edges % CHUNK == 0)
  297. GROWEDGES;
  298. }
  299. if (ND_other(n).list) {
  300. /* In position, each node has its rw stored in mval and,
  301. * if a node is part of a loop, rw may be increased to
  302. * reflect the loops and associated labels. We restore
  303. * the original value here.
  304. */
  305. if (ND_node_type(n) == NORMAL) {
  306. double tmp = ND_rw(n);
  307. ND_rw(n) = ND_mval(n);
  308. ND_mval(n) = tmp;
  309. }
  310. for (k = 0; (e = ND_other(n).list[k]); k++) {
  311. setflags(e, 0, 0, AUXGRAPH);
  312. edges[n_edges++] = e;
  313. if (n_edges % CHUNK == 0)
  314. GROWEDGES;
  315. }
  316. }
  317. }
  318. }
  319. /* Sort so that equivalent edges are contiguous.
  320. * Equivalence should basically mean that 2 edges have the
  321. * same set {(tailnode,tailport),(headnode,headport)}, or
  322. * alternatively, the edges would be routed identically if
  323. * routed separately.
  324. */
  325. qsort(edges, n_edges, sizeof(edges[0]), edgecmp);
  326. /* FIXME: just how many boxes can there be? */
  327. P.boxes = gv_calloc(n_nodes + 20 * 2 * NSUB, sizeof(boxf));
  328. sd.Rank_box = gv_calloc(i, sizeof(boxf));
  329. if (et == EDGETYPE_LINE) {
  330. /* place regular edge labels */
  331. for (n = GD_nlist(g); n; n = ND_next(n)) {
  332. if (ND_node_type(n) == VIRTUAL && ND_label(n)) {
  333. place_vnlabel(n);
  334. }
  335. }
  336. }
  337. for (unsigned l = 0; l < n_edges;) {
  338. const unsigned ind = l;
  339. le0 = getmainedge((e0 = edges[l++]));
  340. if (ED_tail_port(e0).defined || ED_head_port(e0).defined) {
  341. ea = e0;
  342. } else {
  343. ea = le0;
  344. }
  345. if (ED_tree_index(ea) & BWDEDGE) {
  346. MAKEFWDEDGE(&fwdedgea.out, ea);
  347. ea = &fwdedgea.out;
  348. }
  349. unsigned cnt;
  350. for (cnt = 1; l < n_edges; cnt++, l++) {
  351. if (le0 != (le1 = getmainedge((e1 = edges[l]))))
  352. break;
  353. if (ED_adjacent(e0))
  354. continue; /* all flat adjacent edges at once */
  355. if (ED_tail_port(e1).defined || ED_head_port(e1).defined) {
  356. eb = e1;
  357. } else {
  358. eb = le1;
  359. }
  360. if (ED_tree_index(eb) & BWDEDGE) {
  361. MAKEFWDEDGE(&fwdedgeb.out, eb);
  362. eb = &fwdedgeb.out;
  363. }
  364. if (portcmp(ED_tail_port(ea), ED_tail_port(eb)))
  365. break;
  366. if (portcmp(ED_head_port(ea), ED_head_port(eb)))
  367. break;
  368. if ((ED_tree_index(e0) & EDGETYPEMASK) == FLATEDGE &&
  369. ED_label(e0) != ED_label(e1))
  370. break;
  371. if (ED_tree_index(edges[l]) & MAINGRAPH) /* Aha! -C is on */
  372. break;
  373. }
  374. if (et == EDGETYPE_CURVED) {
  375. edge_t **edgelist = gv_calloc(cnt, sizeof(edge_t *));
  376. edgelist[0] = getmainedge((edges + ind)[0]);
  377. for (unsigned ii = 1; ii < cnt; ii++)
  378. edgelist[ii] = (edges + ind)[ii];
  379. makeStraightEdges(g, edgelist, cnt, et, &sinfo);
  380. free(edgelist);
  381. } else if (agtail(e0) == aghead(e0)) {
  382. int r;
  383. double sizey;
  384. n = agtail(e0);
  385. r = ND_rank(n);
  386. if (r == GD_maxrank(g)) {
  387. if (r > 0)
  388. sizey = ND_coord(GD_rank(g)[r - 1].v[0]).y - ND_coord(n).y;
  389. else
  390. sizey = ND_ht(n);
  391. } else if (r == GD_minrank(g)) {
  392. sizey = ND_coord(n).y - ND_coord(GD_rank(g)[r + 1].v[0]).y;
  393. } else {
  394. double upy = ND_coord(GD_rank(g)[r - 1].v[0]).y - ND_coord(n).y;
  395. double dwny = ND_coord(n).y - ND_coord(GD_rank(g)[r + 1].v[0]).y;
  396. sizey = MIN(upy, dwny);
  397. }
  398. makeSelfEdge(edges, ind, cnt, sd.Multisep, sizey / 2, &sinfo);
  399. for (unsigned b = 0; b < cnt; b++) {
  400. e = edges[ind + b];
  401. if (ED_label(e))
  402. updateBB(g, ED_label(e));
  403. }
  404. } else if (ND_rank(agtail(e0)) == ND_rank(aghead(e0))) {
  405. make_flat_edge(g, &sd, &P, edges, ind, cnt, et);
  406. } else
  407. make_regular_edge(g, &sd, &P, edges, ind, cnt, et);
  408. }
  409. /* place regular edge labels */
  410. for (n = GD_nlist(g); n; n = ND_next(n)) {
  411. if (ND_node_type(n) == VIRTUAL && ND_label(n)) {
  412. place_vnlabel(n);
  413. updateBB(g, ND_label(n));
  414. }
  415. }
  416. /* normalize splines so they always go from tail to head */
  417. /* place_portlabel relies on this being done first */
  418. if (normalize)
  419. edge_normalize(g);
  420. #ifdef ORTHO
  421. finish:
  422. #endif
  423. /* place port labels */
  424. /* FIX: head and tail labels are not part of cluster bbox */
  425. if ((E_headlabel || E_taillabel) && (E_labelangle || E_labeldistance)) {
  426. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  427. if (E_headlabel) {
  428. for (e = agfstin(g, n); e; e = agnxtin(g, e))
  429. if (ED_head_label(AGMKOUT(e))) {
  430. place_portlabel(AGMKOUT(e), true);
  431. updateBB(g, ED_head_label(AGMKOUT(e)));
  432. }
  433. }
  434. if (E_taillabel) {
  435. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  436. if (ED_tail_label(e)) {
  437. if (place_portlabel(e, false))
  438. updateBB(g, ED_tail_label(e));
  439. }
  440. }
  441. }
  442. }
  443. }
  444. #ifdef ORTHO
  445. if (et != EDGETYPE_ORTHO && et != EDGETYPE_CURVED) {
  446. #else
  447. if (et != EDGETYPE_CURVED) {
  448. #endif
  449. free(sd.Rank_box);
  450. routesplinesterm();
  451. }
  452. free(edges);
  453. free(P.boxes);
  454. State = GVSPLINES;
  455. EdgeLabelsDone = 1;
  456. }
  457. /* dot_splines:
  458. * If the splines attribute is defined but equal to "", skip edge routing.
  459. */
  460. void dot_splines(graph_t *g) { dot_splines_(g, 1); }
  461. /* place_vnlabel:
  462. * assign position of an edge label from its virtual node
  463. * This is for regular edges only.
  464. */
  465. static void place_vnlabel(node_t *n) {
  466. pointf dimen;
  467. double width;
  468. edge_t *e;
  469. if (ND_in(n).size == 0)
  470. return; /* skip flat edge labels here */
  471. for (e = ND_out(n).list[0]; ED_edge_type(e) != NORMAL; e = ED_to_orig(e))
  472. ;
  473. dimen = ED_label(e)->dimen;
  474. width = GD_flip(agraphof(n)) ? dimen.y : dimen.x;
  475. ED_label(e)->pos.x = ND_coord(n).x + width / 2.0;
  476. ED_label(e)->pos.y = ND_coord(n).y;
  477. ED_label(e)->set = true;
  478. }
  479. static void setflags(edge_t *e, int hint1, int hint2, int f3) {
  480. int f1, f2;
  481. if (hint1 != 0)
  482. f1 = hint1;
  483. else {
  484. if (agtail(e) == aghead(e))
  485. if (ED_tail_port(e).defined || ED_head_port(e).defined)
  486. f1 = SELFWPEDGE;
  487. else
  488. f1 = SELFNPEDGE;
  489. else if (ND_rank(agtail(e)) == ND_rank(aghead(e)))
  490. f1 = FLATEDGE;
  491. else
  492. f1 = REGULAREDGE;
  493. }
  494. if (hint2 != 0)
  495. f2 = hint2;
  496. else {
  497. if (f1 == REGULAREDGE)
  498. f2 = ND_rank(agtail(e)) < ND_rank(aghead(e)) ? FWDEDGE : BWDEDGE;
  499. else if (f1 == FLATEDGE)
  500. f2 = ND_order(agtail(e)) < ND_order(aghead(e)) ? FWDEDGE : BWDEDGE;
  501. else /* f1 == SELF*EDGE */
  502. f2 = FWDEDGE;
  503. }
  504. ED_tree_index(e) = (f1 | f2 | f3);
  505. }
  506. /* edgecmp:
  507. * lexicographically order edges by
  508. * - edge type
  509. * - |rank difference of nodes|
  510. * - |x difference of nodes|
  511. * - id of witness edge for equivalence class
  512. * - port comparison
  513. * - graph type
  514. * - labels if flat edges
  515. * - edge id
  516. */
  517. static int edgecmp(const void *x, const void *y) {
  518. // Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
  519. // as the later usage is const. We need the cast because the macros use
  520. // non-const pointers for genericity.
  521. #ifdef __GNUC__
  522. #pragma GCC diagnostic push
  523. #pragma GCC diagnostic ignored "-Wcast-qual"
  524. #endif
  525. edge_t **ptr0 = (edge_t **)x;
  526. edge_t **ptr1 = (edge_t **)y;
  527. #ifdef __GNUC__
  528. #pragma GCC diagnostic pop
  529. #endif
  530. Agedgeinfo_t fwdedgeai, fwdedgebi;
  531. Agedgepair_t fwdedgea, fwdedgeb;
  532. edge_t *e0, *e1, *ea, *eb, *le0, *le1;
  533. int et0, et1, v0, v1, rv;
  534. double t0, t1;
  535. fwdedgea.out.base.data = (Agrec_t *)&fwdedgeai;
  536. fwdedgeb.out.base.data = (Agrec_t *)&fwdedgebi;
  537. e0 = *ptr0;
  538. e1 = *ptr1;
  539. et0 = ED_tree_index(e0) & EDGETYPEMASK;
  540. et1 = ED_tree_index(e1) & EDGETYPEMASK;
  541. if (et0 < et1) {
  542. return 1;
  543. }
  544. if (et0 > et1) {
  545. return -1;
  546. }
  547. le0 = getmainedge(e0);
  548. le1 = getmainedge(e1);
  549. t0 = ND_rank(agtail(le0)) - ND_rank(aghead(le0));
  550. t1 = ND_rank(agtail(le1)) - ND_rank(aghead(le1));
  551. v0 = abs((int)t0); /* ugly, but explicit as to how we avoid equality tests on
  552. fp numbers */
  553. v1 = abs((int)t1);
  554. if (v0 < v1) {
  555. return -1;
  556. }
  557. if (v0 > v1) {
  558. return 1;
  559. }
  560. t0 = ND_coord(agtail(le0)).x - ND_coord(aghead(le0)).x;
  561. t1 = ND_coord(agtail(le1)).x - ND_coord(aghead(le1)).x;
  562. v0 = abs((int)t0);
  563. v1 = abs((int)t1);
  564. if (v0 < v1) {
  565. return -1;
  566. }
  567. if (v0 > v1) {
  568. return 1;
  569. }
  570. /* This provides a cheap test for edges having the same set of endpoints. */
  571. if (AGSEQ(le0) < AGSEQ(le1)) {
  572. return -1;
  573. }
  574. if (AGSEQ(le0) > AGSEQ(le1)) {
  575. return 1;
  576. }
  577. ea = (ED_tail_port(e0).defined || ED_head_port(e0).defined) ? e0 : le0;
  578. if (ED_tree_index(ea) & BWDEDGE) {
  579. MAKEFWDEDGE(&fwdedgea.out, ea);
  580. ea = &fwdedgea.out;
  581. }
  582. eb = (ED_tail_port(e1).defined || ED_head_port(e1).defined) ? e1 : le1;
  583. if (ED_tree_index(eb) & BWDEDGE) {
  584. MAKEFWDEDGE(&fwdedgeb.out, eb);
  585. eb = &fwdedgeb.out;
  586. }
  587. if ((rv = portcmp(ED_tail_port(ea), ED_tail_port(eb))))
  588. return rv;
  589. if ((rv = portcmp(ED_head_port(ea), ED_head_port(eb))))
  590. return rv;
  591. et0 = ED_tree_index(e0) & GRAPHTYPEMASK;
  592. et1 = ED_tree_index(e1) & GRAPHTYPEMASK;
  593. if (et0 < et1) {
  594. return -1;
  595. }
  596. if (et0 > et1) {
  597. return 1;
  598. }
  599. if (et0 == FLATEDGE) {
  600. if (ED_label(e0) < ED_label(e1)) {
  601. return -1;
  602. }
  603. if (ED_label(e0) > ED_label(e1)) {
  604. return 1;
  605. }
  606. }
  607. if (AGSEQ(e0) < AGSEQ(e1)) {
  608. return -1;
  609. }
  610. if (AGSEQ(e0) > AGSEQ(e1)) {
  611. return 1;
  612. }
  613. return 0;
  614. }
  615. typedef struct {
  616. attrsym_t *E_constr;
  617. attrsym_t *E_dir;
  618. attrsym_t *E_samehead;
  619. attrsym_t *E_sametail;
  620. attrsym_t *E_weight;
  621. attrsym_t *E_minlen;
  622. attrsym_t *E_fontcolor;
  623. attrsym_t *E_fontname;
  624. attrsym_t *E_fontsize;
  625. attrsym_t *E_headclip;
  626. attrsym_t *E_headlabel;
  627. attrsym_t *E_label;
  628. attrsym_t *E_label_float;
  629. attrsym_t *E_labelfontcolor;
  630. attrsym_t *E_labelfontname;
  631. attrsym_t *E_labelfontsize;
  632. attrsym_t *E_tailclip;
  633. attrsym_t *E_taillabel;
  634. attrsym_t *E_xlabel;
  635. attrsym_t *N_height;
  636. attrsym_t *N_width;
  637. attrsym_t *N_shape;
  638. attrsym_t *N_style;
  639. attrsym_t *N_fontsize;
  640. attrsym_t *N_fontname;
  641. attrsym_t *N_fontcolor;
  642. attrsym_t *N_label;
  643. attrsym_t *N_xlabel;
  644. attrsym_t *N_showboxes;
  645. attrsym_t *N_ordering;
  646. attrsym_t *N_sides;
  647. attrsym_t *N_peripheries;
  648. attrsym_t *N_skew;
  649. attrsym_t *N_orientation;
  650. attrsym_t *N_distortion;
  651. attrsym_t *N_fixed;
  652. attrsym_t *N_nojustify;
  653. attrsym_t *N_group;
  654. attrsym_t *G_ordering;
  655. int State;
  656. } attr_state_t;
  657. static void setState(graph_t *auxg, attr_state_t *attr_state) {
  658. /* save state */
  659. attr_state->E_constr = E_constr;
  660. attr_state->E_dir = E_dir;
  661. attr_state->E_samehead = E_samehead;
  662. attr_state->E_sametail = E_sametail;
  663. attr_state->E_weight = E_weight;
  664. attr_state->E_minlen = E_minlen;
  665. attr_state->E_fontcolor = E_fontcolor;
  666. attr_state->E_fontname = E_fontname;
  667. attr_state->E_fontsize = E_fontsize;
  668. attr_state->E_headclip = E_headclip;
  669. attr_state->E_headlabel = E_headlabel;
  670. attr_state->E_label = E_label;
  671. attr_state->E_label_float = E_label_float;
  672. attr_state->E_labelfontcolor = E_labelfontcolor;
  673. attr_state->E_labelfontname = E_labelfontname;
  674. attr_state->E_labelfontsize = E_labelfontsize;
  675. attr_state->E_tailclip = E_tailclip;
  676. attr_state->E_taillabel = E_taillabel;
  677. attr_state->E_xlabel = E_xlabel;
  678. attr_state->N_height = N_height;
  679. attr_state->N_width = N_width;
  680. attr_state->N_shape = N_shape;
  681. attr_state->N_style = N_style;
  682. attr_state->N_fontsize = N_fontsize;
  683. attr_state->N_fontname = N_fontname;
  684. attr_state->N_fontcolor = N_fontcolor;
  685. attr_state->N_label = N_label;
  686. attr_state->N_xlabel = N_xlabel;
  687. attr_state->N_showboxes = N_showboxes;
  688. attr_state->N_ordering = N_ordering;
  689. attr_state->N_sides = N_sides;
  690. attr_state->N_peripheries = N_peripheries;
  691. attr_state->N_skew = N_skew;
  692. attr_state->N_orientation = N_orientation;
  693. attr_state->N_distortion = N_distortion;
  694. attr_state->N_fixed = N_fixed;
  695. attr_state->N_nojustify = N_nojustify;
  696. attr_state->N_group = N_group;
  697. attr_state->State = State;
  698. attr_state->G_ordering = G_ordering;
  699. E_constr = NULL;
  700. E_dir = agattr(auxg, AGEDGE, "dir", NULL);
  701. E_samehead = agattr(auxg, AGEDGE, "samehead", NULL);
  702. E_sametail = agattr(auxg, AGEDGE, "sametail", NULL);
  703. E_weight = agattr(auxg, AGEDGE, "weight", NULL);
  704. if (!E_weight)
  705. E_weight = agattr(auxg, AGEDGE, "weight", "");
  706. E_minlen = NULL;
  707. E_fontcolor = NULL;
  708. E_fontname = agfindedgeattr(auxg, "fontname");
  709. E_fontsize = agfindedgeattr(auxg, "fontsize");
  710. E_headclip = agfindedgeattr(auxg, "headclip");
  711. E_headlabel = NULL;
  712. E_label = agfindedgeattr(auxg, "label");
  713. E_label_float = agfindedgeattr(auxg, "label_float");
  714. E_labelfontcolor = NULL;
  715. E_labelfontname = agfindedgeattr(auxg, "labelfontname");
  716. E_labelfontsize = agfindedgeattr(auxg, "labelfontsize");
  717. E_tailclip = agfindedgeattr(auxg, "tailclip");
  718. E_taillabel = NULL;
  719. E_xlabel = NULL;
  720. N_height = agfindnodeattr(auxg, "height");
  721. N_width = agfindnodeattr(auxg, "width");
  722. N_shape = agfindnodeattr(auxg, "shape");
  723. N_style = NULL;
  724. N_fontsize = agfindnodeattr(auxg, "fontsize");
  725. N_fontname = agfindnodeattr(auxg, "fontname");
  726. N_fontcolor = NULL;
  727. N_label = agfindnodeattr(auxg, "label");
  728. N_xlabel = NULL;
  729. N_showboxes = NULL;
  730. N_ordering = agfindnodeattr(auxg, "ordering");
  731. N_sides = agfindnodeattr(auxg, "sides");
  732. N_peripheries = agfindnodeattr(auxg, "peripheries");
  733. N_skew = agfindnodeattr(auxg, "skew");
  734. N_orientation = agfindnodeattr(auxg, "orientation");
  735. N_distortion = agfindnodeattr(auxg, "distortion");
  736. N_fixed = agfindnodeattr(auxg, "fixed");
  737. N_nojustify = NULL;
  738. N_group = NULL;
  739. G_ordering = agfindgraphattr(auxg, "ordering");
  740. }
  741. /* cloneGraph:
  742. * Create clone graph. It stores the global Agsyms, to be
  743. * restored in cleanupCloneGraph. The graph uses the main
  744. * graph's settings for certain geometry parameters, and
  745. * declares all node and edge attributes used in the original
  746. * graph.
  747. */
  748. static graph_t *cloneGraph(graph_t *g, attr_state_t *attr_state) {
  749. Agsym_t *sym;
  750. graph_t *auxg;
  751. if (agisdirected(g))
  752. auxg = agopen("auxg", Agdirected, NULL);
  753. else
  754. auxg = agopen("auxg", Agundirected, NULL);
  755. agbindrec(auxg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
  756. agattr(auxg, AGRAPH, "rank", "");
  757. GD_drawing(auxg) = gv_alloc(sizeof(layout_t));
  758. GD_drawing(auxg)->quantum = GD_drawing(g)->quantum;
  759. GD_drawing(auxg)->dpi = GD_drawing(g)->dpi;
  760. GD_charset(auxg) = GD_charset(g);
  761. if (GD_flip(g))
  762. SET_RANKDIR(auxg, RANKDIR_TB);
  763. else
  764. SET_RANKDIR(auxg, RANKDIR_LR);
  765. GD_nodesep(auxg) = GD_nodesep(g);
  766. GD_ranksep(auxg) = GD_ranksep(g);
  767. // copy node attrs to auxg
  768. sym = agnxtattr(agroot(g), AGNODE, NULL); // get the first attr.
  769. for (; sym; sym = agnxtattr(agroot(g), AGNODE, sym))
  770. agattr(auxg, AGNODE, sym->name, sym->defval);
  771. // copy edge attributes
  772. sym = agnxtattr(agroot(g), AGEDGE, NULL); // get the first attr.
  773. for (; sym; sym = agnxtattr(agroot(g), AGEDGE, sym))
  774. agattr(auxg, AGEDGE, sym->name, sym->defval);
  775. if (!agattr(auxg, AGEDGE, "headport", NULL))
  776. agattr(auxg, AGEDGE, "headport", "");
  777. if (!agattr(auxg, AGEDGE, "tailport", NULL))
  778. agattr(auxg, AGEDGE, "tailport", "");
  779. setState(auxg, attr_state);
  780. return auxg;
  781. }
  782. static void cleanupCloneGraph(graph_t *g, attr_state_t *attr_state) {
  783. /* restore main graph syms */
  784. E_constr = attr_state->E_constr;
  785. E_dir = attr_state->E_dir;
  786. E_samehead = attr_state->E_samehead;
  787. E_sametail = attr_state->E_sametail;
  788. E_weight = attr_state->E_weight;
  789. E_minlen = attr_state->E_minlen;
  790. E_fontcolor = attr_state->E_fontcolor;
  791. E_fontname = attr_state->E_fontname;
  792. E_fontsize = attr_state->E_fontsize;
  793. E_headclip = attr_state->E_headclip;
  794. E_headlabel = attr_state->E_headlabel;
  795. E_label = attr_state->E_label;
  796. E_label_float = attr_state->E_label_float;
  797. E_labelfontcolor = attr_state->E_labelfontcolor;
  798. E_labelfontname = attr_state->E_labelfontname;
  799. E_labelfontsize = attr_state->E_labelfontsize;
  800. E_tailclip = attr_state->E_tailclip;
  801. E_taillabel = attr_state->E_taillabel;
  802. E_xlabel = attr_state->E_xlabel;
  803. N_height = attr_state->N_height;
  804. N_width = attr_state->N_width;
  805. N_shape = attr_state->N_shape;
  806. N_style = attr_state->N_style;
  807. N_fontsize = attr_state->N_fontsize;
  808. N_fontname = attr_state->N_fontname;
  809. N_fontcolor = attr_state->N_fontcolor;
  810. N_label = attr_state->N_label;
  811. N_xlabel = attr_state->N_xlabel;
  812. N_showboxes = attr_state->N_showboxes;
  813. N_ordering = attr_state->N_ordering;
  814. N_sides = attr_state->N_sides;
  815. N_peripheries = attr_state->N_peripheries;
  816. N_skew = attr_state->N_skew;
  817. N_orientation = attr_state->N_orientation;
  818. N_distortion = attr_state->N_distortion;
  819. N_fixed = attr_state->N_fixed;
  820. N_nojustify = attr_state->N_nojustify;
  821. N_group = attr_state->N_group;
  822. G_ordering = attr_state->G_ordering;
  823. State = attr_state->State;
  824. dot_cleanup(g);
  825. agclose(g);
  826. }
  827. /* cloneNode:
  828. * If original graph has rankdir=LR or RL, records change shape,
  829. * so we wrap a record node's label in "{...}" to prevent this.
  830. */
  831. static node_t *cloneNode(graph_t *g, node_t *orign) {
  832. node_t *n = agnode(g, agnameof(orign), 1);
  833. agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true);
  834. agcopyattr(orign, n);
  835. if (shapeOf(orign) == SH_RECORD) {
  836. agxbuf buf = {0};
  837. agxbprint(&buf, "{%s}", ND_label(orign)->text);
  838. agset(n, "label", agxbuse(&buf));
  839. agxbfree(&buf);
  840. }
  841. return n;
  842. }
  843. static edge_t *cloneEdge(graph_t *g, node_t *tn, node_t *hn, edge_t *orig) {
  844. edge_t *e = agedge(g, tn, hn, NULL, 1);
  845. agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true);
  846. agcopyattr(orig, e);
  847. return e;
  848. }
  849. /* transformf:
  850. * Rotate, if necessary, then translate points.
  851. */
  852. static pointf transformf(pointf p, pointf del, int flip) {
  853. if (flip) {
  854. double i = p.x;
  855. p.x = p.y;
  856. p.y = -i;
  857. }
  858. return add_pointf(p, del);
  859. }
  860. /* edgelblcmpfn:
  861. * lexicographically order edges by
  862. * - has label
  863. * - label is wider
  864. * - label is higher
  865. */
  866. static int edgelblcmpfn(const void *x, const void *y) {
  867. // Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
  868. // as the later usage is const. We need the cast because the macros use
  869. // non-const pointers for genericity.
  870. #ifdef __GNUC__
  871. #pragma GCC diagnostic push
  872. #pragma GCC diagnostic ignored "-Wcast-qual"
  873. #endif
  874. edge_t **ptr0 = (edge_t **)x;
  875. edge_t **ptr1 = (edge_t **)y;
  876. #ifdef __GNUC__
  877. #pragma GCC diagnostic pop
  878. #endif
  879. pointf sz0, sz1;
  880. edge_t *e0 = *ptr0;
  881. edge_t *e1 = *ptr1;
  882. if (ED_label(e0)) {
  883. if (ED_label(e1)) {
  884. sz0 = ED_label(e0)->dimen;
  885. sz1 = ED_label(e1)->dimen;
  886. if (sz0.x > sz1.x)
  887. return -1;
  888. if (sz0.x < sz1.x)
  889. return 1;
  890. if (sz0.y > sz1.y)
  891. return -1;
  892. if (sz0.y < sz1.y)
  893. return 1;
  894. return 0;
  895. }
  896. return -1;
  897. }
  898. if (ED_label(e1)) {
  899. return 1;
  900. }
  901. return 0;
  902. }
  903. #define LBL_SPACE 6 /* space between labels, in points */
  904. /* makeSimpleFlatLabels:
  905. * This handles the second simplest case for flat edges between
  906. * two adjacent nodes. We still invoke a dot on a rotated problem
  907. * to handle edges with ports. This usually works, but fails for
  908. * records because of their weird nature.
  909. */
  910. static void makeSimpleFlatLabels(node_t *tn, node_t *hn, edge_t **edges,
  911. unsigned ind, unsigned cnt, int et,
  912. unsigned n_lbls) {
  913. Ppoly_t poly;
  914. edge_t *e = edges[ind];
  915. pointf points[10], tp, hp;
  916. double leftend, rightend, ctrx, ctry, miny, maxy;
  917. double uminx, umaxx;
  918. double lminx = 0.0, lmaxx = 0.0;
  919. edge_t **earray = gv_calloc(cnt, sizeof(edge_t *));
  920. for (unsigned i = 0; i < cnt; i++) {
  921. earray[i] = edges[ind + i];
  922. }
  923. qsort(earray, cnt, sizeof(edge_t *), edgelblcmpfn);
  924. tp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
  925. hp = add_pointf(ND_coord(hn), ED_head_port(e).p);
  926. leftend = tp.x + ND_rw(tn);
  927. rightend = hp.x - ND_lw(hn);
  928. ctrx = (leftend + rightend) / 2.0;
  929. /* do first edge */
  930. e = earray[0];
  931. size_t pointn = 0;
  932. points[pointn++] = tp;
  933. points[pointn++] = tp;
  934. points[pointn++] = hp;
  935. points[pointn++] = hp;
  936. clip_and_install(e, aghead(e), points, pointn, &sinfo);
  937. ED_label(e)->pos.x = ctrx;
  938. ED_label(e)->pos.y = tp.y + (ED_label(e)->dimen.y + LBL_SPACE) / 2.0;
  939. ED_label(e)->set = true;
  940. miny = tp.y + LBL_SPACE / 2.0;
  941. maxy = miny + ED_label(e)->dimen.y;
  942. uminx = ctrx - ED_label(e)->dimen.x / 2.0;
  943. umaxx = ctrx + ED_label(e)->dimen.x / 2.0;
  944. unsigned i;
  945. for (i = 1; i < n_lbls; i++) {
  946. e = earray[i];
  947. if (i % 2) { /* down */
  948. if (i == 1) {
  949. lminx = ctrx - ED_label(e)->dimen.x / 2.0;
  950. lmaxx = ctrx + ED_label(e)->dimen.x / 2.0;
  951. }
  952. miny -= LBL_SPACE + ED_label(e)->dimen.y;
  953. points[0] = tp;
  954. points[1].x = tp.x;
  955. points[1].y = miny - LBL_SPACE;
  956. points[2].x = hp.x;
  957. points[2].y = points[1].y;
  958. points[3] = hp;
  959. points[4].x = lmaxx;
  960. points[4].y = hp.y;
  961. points[5].x = lmaxx;
  962. points[5].y = miny;
  963. points[6].x = lminx;
  964. points[6].y = miny;
  965. points[7].x = lminx;
  966. points[7].y = tp.y;
  967. ctry = miny + ED_label(e)->dimen.y / 2.0;
  968. } else { /* up */
  969. points[0] = tp;
  970. points[1].x = uminx;
  971. points[1].y = tp.y;
  972. points[2].x = uminx;
  973. points[2].y = maxy;
  974. points[3].x = umaxx;
  975. points[3].y = maxy;
  976. points[4].x = umaxx;
  977. points[4].y = hp.y;
  978. points[5].x = hp.x;
  979. points[5].y = hp.y;
  980. points[6].x = hp.x;
  981. points[6].y = maxy + LBL_SPACE;
  982. points[7].x = tp.x;
  983. points[7].y = maxy + LBL_SPACE;
  984. ctry = maxy + ED_label(e)->dimen.y / 2.0 + LBL_SPACE;
  985. maxy += ED_label(e)->dimen.y + LBL_SPACE;
  986. }
  987. poly.pn = 8;
  988. poly.ps = (Ppoint_t *)points;
  989. size_t pn;
  990. pointf *ps = simpleSplineRoute(tp, hp, poly, &pn, et == EDGETYPE_PLINE);
  991. if (ps == NULL || pn == 0) {
  992. free(ps);
  993. free(earray);
  994. return;
  995. }
  996. ED_label(e)->pos.x = ctrx;
  997. ED_label(e)->pos.y = ctry;
  998. ED_label(e)->set = true;
  999. clip_and_install(e, aghead(e), ps, pn, &sinfo);
  1000. free(ps);
  1001. }
  1002. /* edges with no labels */
  1003. for (; i < cnt; i++) {
  1004. e = earray[i];
  1005. if (i % 2) { /* down */
  1006. if (i == 1) {
  1007. lminx = (2 * leftend + rightend) / 3.0;
  1008. lmaxx = (leftend + 2 * rightend) / 3.0;
  1009. }
  1010. miny -= LBL_SPACE;
  1011. points[0] = tp;
  1012. points[1].x = tp.x;
  1013. points[1].y = miny - LBL_SPACE;
  1014. points[2].x = hp.x;
  1015. points[2].y = points[1].y;
  1016. points[3] = hp;
  1017. points[4].x = lmaxx;
  1018. points[4].y = hp.y;
  1019. points[5].x = lmaxx;
  1020. points[5].y = miny;
  1021. points[6].x = lminx;
  1022. points[6].y = miny;
  1023. points[7].x = lminx;
  1024. points[7].y = tp.y;
  1025. } else { /* up */
  1026. points[0] = tp;
  1027. points[1].x = uminx;
  1028. points[1].y = tp.y;
  1029. points[2].x = uminx;
  1030. points[2].y = maxy;
  1031. points[3].x = umaxx;
  1032. points[3].y = maxy;
  1033. points[4].x = umaxx;
  1034. points[4].y = hp.y;
  1035. points[5].x = hp.x;
  1036. points[5].y = hp.y;
  1037. points[6].x = hp.x;
  1038. points[6].y = maxy + LBL_SPACE;
  1039. points[7].x = tp.x;
  1040. points[7].y = maxy + LBL_SPACE;
  1041. maxy += +LBL_SPACE;
  1042. }
  1043. poly.pn = 8;
  1044. poly.ps = (Ppoint_t *)points;
  1045. size_t pn;
  1046. pointf *ps = simpleSplineRoute(tp, hp, poly, &pn, et == EDGETYPE_PLINE);
  1047. if (ps == NULL || pn == 0) {
  1048. free(ps);
  1049. free(earray);
  1050. return;
  1051. }
  1052. clip_and_install(e, aghead(e), ps, pn, &sinfo);
  1053. free(ps);
  1054. }
  1055. free(earray);
  1056. }
  1057. static void makeSimpleFlat(node_t *tn, node_t *hn, edge_t **edges, unsigned ind,
  1058. unsigned cnt, int et) {
  1059. edge_t *e = edges[ind];
  1060. pointf points[10], tp, hp;
  1061. double stepy, dy;
  1062. tp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
  1063. hp = add_pointf(ND_coord(hn), ED_head_port(e).p);
  1064. stepy = cnt > 1 ? ND_ht(tn) / (double)(cnt - 1) : 0.;
  1065. dy = tp.y - (cnt > 1 ? ND_ht(tn) / 2. : 0.);
  1066. for (unsigned i = 0; i < cnt; i++) {
  1067. e = edges[ind + i];
  1068. size_t pointn = 0;
  1069. if (et == EDGETYPE_SPLINE || et == EDGETYPE_LINE) {
  1070. points[pointn++] = tp;
  1071. points[pointn++] = (pointf){(2 * tp.x + hp.x) / 3, dy};
  1072. points[pointn++] = (pointf){(2 * hp.x + tp.x) / 3, dy};
  1073. points[pointn++] = hp;
  1074. } else { /* EDGETYPE_PLINE */
  1075. points[pointn++] = tp;
  1076. points[pointn++] = tp;
  1077. points[pointn++] = (pointf){(2 * tp.x + hp.x) / 3, dy};
  1078. points[pointn++] = (pointf){(2 * tp.x + hp.x) / 3, dy};
  1079. points[pointn++] = (pointf){(2 * tp.x + hp.x) / 3, dy};
  1080. points[pointn++] = (pointf){(2 * hp.x + tp.x) / 3, dy};
  1081. points[pointn++] = (pointf){(2 * hp.x + tp.x) / 3, dy};
  1082. points[pointn++] = (pointf){(2 * hp.x + tp.x) / 3, dy};
  1083. points[pointn++] = hp;
  1084. points[pointn++] = hp;
  1085. }
  1086. dy += stepy;
  1087. clip_and_install(e, aghead(e), points, pointn, &sinfo);
  1088. }
  1089. }
  1090. /* make_flat_adj_edges:
  1091. * In the simple case, with no labels or ports, this creates a simple
  1092. * spindle of splines.
  1093. * If there are only labels, cobble something together.
  1094. * Otherwise, we run dot recursively on the 2 nodes and the edges,
  1095. * essentially using rankdir=LR, to get the needed spline info.
  1096. * This is probably to cute and fragile, and should be rewritten in a
  1097. * more straightforward and laborious fashion.
  1098. */
  1099. static void make_flat_adj_edges(graph_t *g, edge_t **edges, unsigned ind,
  1100. unsigned cnt, edge_t *e0, int et) {
  1101. node_t *n;
  1102. node_t *tn, *hn;
  1103. edge_t *e;
  1104. graph_t *auxg;
  1105. graph_t *subg;
  1106. node_t *auxt, *auxh;
  1107. edge_t *auxe;
  1108. double midx, midy, leftx, rightx;
  1109. pointf del;
  1110. edge_t *hvye = NULL;
  1111. static bool warned = false;
  1112. tn = agtail(e0), hn = aghead(e0);
  1113. if (shapeOf(tn) == SH_RECORD || shapeOf(hn) == SH_RECORD) {
  1114. if (!warned) {
  1115. warned = true;
  1116. agwarningf("flat edge between adjacent nodes one of which has a record "
  1117. "shape - replace records with HTML-like labels\n");
  1118. agerr(AGPREV, " Edge %s %s %s\n", agnameof(tn),
  1119. agisdirected(g) ? "->" : "--", agnameof(hn));
  1120. }
  1121. return;
  1122. }
  1123. unsigned labels = 0;
  1124. bool ports = false;
  1125. for (unsigned i = 0; i < cnt; i++) {
  1126. e = edges[ind + i];
  1127. if (ED_label(e))
  1128. labels++;
  1129. if (ED_tail_port(e).defined || ED_head_port(e).defined)
  1130. ports = true;
  1131. }
  1132. if (!ports) {
  1133. /* flat edges without ports and labels can go straight left to right */
  1134. if (labels == 0) {
  1135. makeSimpleFlat(tn, hn, edges, ind, cnt, et);
  1136. }
  1137. /* flat edges without ports but with labels take more work */
  1138. else {
  1139. makeSimpleFlatLabels(tn, hn, edges, ind, cnt, et, labels);
  1140. }
  1141. return;
  1142. }
  1143. attr_state_t attrs = {0};
  1144. auxg = cloneGraph(g, &attrs);
  1145. subg = agsubg(auxg, "xxx", 1);
  1146. agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
  1147. agset(subg, "rank", "source");
  1148. rightx = ND_coord(hn).x;
  1149. leftx = ND_coord(tn).x;
  1150. if (GD_flip(g)) {
  1151. node_t *tmp = tn;
  1152. tn = hn;
  1153. hn = tmp;
  1154. }
  1155. auxt = cloneNode(subg, tn);
  1156. auxh = cloneNode(auxg, hn);
  1157. for (unsigned i = 0; i < cnt; i++) {
  1158. e = edges[ind + i];
  1159. for (; ED_edge_type(e) != NORMAL; e = ED_to_orig(e))
  1160. ;
  1161. if (agtail(e) == tn)
  1162. auxe = cloneEdge(auxg, auxt, auxh, e);
  1163. else
  1164. auxe = cloneEdge(auxg, auxh, auxt, e);
  1165. ED_alg(e) = auxe;
  1166. if (!hvye && !ED_tail_port(e).defined && !ED_head_port(e).defined) {
  1167. hvye = auxe;
  1168. ED_alg(hvye) = e;
  1169. }
  1170. }
  1171. if (!hvye) {
  1172. hvye = agedge(auxg, auxt, auxh, NULL, 1);
  1173. }
  1174. agxset(hvye, E_weight, "10000");
  1175. GD_gvc(auxg) = GD_gvc(g);
  1176. GD_dotroot(auxg) = auxg;
  1177. setEdgeType(auxg, et);
  1178. dot_init_node_edge(auxg);
  1179. dot_rank(auxg);
  1180. dot_mincross(auxg);
  1181. dot_position(auxg);
  1182. /* reposition */
  1183. midx = (ND_coord(tn).x - ND_rw(tn) + ND_coord(hn).x + ND_lw(hn)) / 2;
  1184. midy = (ND_coord(auxt).x + ND_coord(auxh).x) / 2;
  1185. for (n = GD_nlist(auxg); n; n = ND_next(n)) {
  1186. if (n == auxt) {
  1187. ND_coord(n).y = rightx;
  1188. ND_coord(n).x = midy;
  1189. } else if (n == auxh) {
  1190. ND_coord(n).y = leftx;
  1191. ND_coord(n).x = midy;
  1192. } else
  1193. ND_coord(n).y = midx;
  1194. }
  1195. dot_sameports(auxg);
  1196. dot_splines_(auxg, 0);
  1197. dotneato_postprocess(auxg);
  1198. /* copy splines */
  1199. if (GD_flip(g)) {
  1200. del.x = ND_coord(tn).x - ND_coord(auxt).y;
  1201. del.y = ND_coord(tn).y + ND_coord(auxt).x;
  1202. } else {
  1203. del.x = ND_coord(tn).x - ND_coord(auxt).x;
  1204. del.y = ND_coord(tn).y - ND_coord(auxt).y;
  1205. }
  1206. for (unsigned i = 0; i < cnt; i++) {
  1207. bezier *auxbz;
  1208. bezier *bz;
  1209. e = edges[ind + i];
  1210. for (; ED_edge_type(e) != NORMAL; e = ED_to_orig(e))
  1211. ;
  1212. auxe = ED_alg(e);
  1213. if ((auxe == hvye) & !ED_alg(auxe))
  1214. continue; /* pseudo-edge */
  1215. auxbz = ED_spl(auxe)->list;
  1216. bz = new_spline(e, auxbz->size);
  1217. bz->sflag = auxbz->sflag;
  1218. bz->sp = transformf(auxbz->sp, del, GD_flip(g));
  1219. bz->eflag = auxbz->eflag;
  1220. bz->ep = transformf(auxbz->ep, del, GD_flip(g));
  1221. for (size_t j = 0; j < auxbz->size;) {
  1222. pointf cp[4];
  1223. cp[0] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g));
  1224. j++;
  1225. if (j >= auxbz->size)
  1226. break;
  1227. cp[1] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g));
  1228. j++;
  1229. cp[2] = bz->list[j] = transformf(auxbz->list[j], del, GD_flip(g));
  1230. j++;
  1231. cp[3] = transformf(auxbz->list[j], del, GD_flip(g));
  1232. update_bb_bz(&GD_bb(g), cp);
  1233. }
  1234. if (ED_label(e)) {
  1235. ED_label(e)->pos = transformf(ED_label(auxe)->pos, del, GD_flip(g));
  1236. ED_label(e)->set = true;
  1237. updateBB(g, ED_label(e));
  1238. }
  1239. }
  1240. cleanupCloneGraph(auxg, &attrs);
  1241. }
  1242. static void makeFlatEnd(graph_t *g, spline_info_t *sp, path *P, node_t *n,
  1243. edge_t *e, pathend_t *endp, bool isBegin) {
  1244. boxf b;
  1245. b = endp->nb = maximal_bbox(g, sp, n, NULL, e);
  1246. endp->sidemask = TOP;
  1247. if (isBegin)
  1248. beginpath(P, e, FLATEDGE, endp, false);
  1249. else
  1250. endpath(P, e, FLATEDGE, endp, false);
  1251. b.UR.y = endp->boxes[endp->boxn - 1].UR.y;
  1252. b.LL.y = endp->boxes[endp->boxn - 1].LL.y;
  1253. b = makeregularend(b, TOP, ND_coord(n).y + GD_rank(g)[ND_rank(n)].ht2);
  1254. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1255. endp->boxes[endp->boxn++] = b;
  1256. }
  1257. static void makeBottomFlatEnd(graph_t *g, spline_info_t *sp, path *P, node_t *n,
  1258. edge_t *e, pathend_t *endp, bool isBegin) {
  1259. boxf b;
  1260. b = endp->nb = maximal_bbox(g, sp, n, NULL, e);
  1261. endp->sidemask = BOTTOM;
  1262. if (isBegin)
  1263. beginpath(P, e, FLATEDGE, endp, false);
  1264. else
  1265. endpath(P, e, FLATEDGE, endp, false);
  1266. b.UR.y = endp->boxes[endp->boxn - 1].UR.y;
  1267. b.LL.y = endp->boxes[endp->boxn - 1].LL.y;
  1268. b = makeregularend(b, BOTTOM, ND_coord(n).y - GD_rank(g)[ND_rank(n)].ht2);
  1269. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1270. endp->boxes[endp->boxn++] = b;
  1271. }
  1272. static void make_flat_labeled_edge(graph_t *g, spline_info_t *sp, path *P,
  1273. edge_t *e, int et) {
  1274. node_t *tn, *hn, *ln;
  1275. pointf *ps;
  1276. bool ps_needs_free = false;
  1277. pathend_t tend, hend;
  1278. boxf lb;
  1279. int i;
  1280. edge_t *f;
  1281. pointf points[7];
  1282. tn = agtail(e);
  1283. hn = aghead(e);
  1284. for (f = ED_to_virt(e); ED_to_virt(f); f = ED_to_virt(f))
  1285. ;
  1286. ln = agtail(f);
  1287. ED_label(e)->pos = ND_coord(ln);
  1288. ED_label(e)->set = true;
  1289. size_t pn;
  1290. if (et == EDGETYPE_LINE) {
  1291. pointf startp, endp, lp;
  1292. startp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
  1293. endp = add_pointf(ND_coord(hn), ED_head_port(e).p);
  1294. lp = ED_label(e)->pos;
  1295. lp.y -= ED_label(e)->dimen.y / 2.0;
  1296. points[1] = points[0] = startp;
  1297. points[2] = points[3] = points[4] = lp;
  1298. points[5] = points[6] = endp;
  1299. ps = points;
  1300. pn = 7;
  1301. } else {
  1302. lb.LL.x = ND_coord(ln).x - ND_lw(ln);
  1303. lb.UR.x = ND_coord(ln).x + ND_rw(ln);
  1304. lb.UR.y = ND_coord(ln).y + ND_ht(ln) / 2;
  1305. double ydelta = ND_coord(ln).y - GD_rank(g)[ND_rank(tn)].ht1 -
  1306. ND_coord(tn).y + GD_rank(g)[ND_rank(tn)].ht2;
  1307. ydelta /= 6;
  1308. lb.LL.y = lb.UR.y - MAX(5, ydelta);
  1309. makeFlatEnd(g, sp, P, tn, e, &tend, true);
  1310. makeFlatEnd(g, sp, P, hn, e, &hend, false);
  1311. boxf boxes[] = {
  1312. {
  1313. .LL =
  1314. {
  1315. .x = tend.boxes[tend.boxn - 1].LL.x,
  1316. .y = tend.boxes[tend.boxn - 1].UR.y,
  1317. },
  1318. .UR = lb.LL,
  1319. },
  1320. {
  1321. .LL =
  1322. {
  1323. .x = tend.boxes[tend.boxn - 1].LL.x,
  1324. .y = lb.LL.y,
  1325. },
  1326. .UR =
  1327. {
  1328. .x = hend.boxes[hend.boxn - 1].UR.x,
  1329. .y = lb.UR.y,
  1330. },
  1331. },
  1332. {
  1333. .LL =
  1334. {
  1335. .x = lb.UR.x,
  1336. .y = hend.boxes[hend.boxn - 1].UR.y,
  1337. },
  1338. .UR =
  1339. {
  1340. .x = hend.boxes[hend.boxn - 1].UR.x,
  1341. .y = lb.LL.y,
  1342. },
  1343. },
  1344. };
  1345. const size_t boxn = sizeof(boxes) / sizeof(boxes[0]);
  1346. for (i = 0; i < tend.boxn; i++)
  1347. add_box(P, tend.boxes[i]);
  1348. for (size_t j = 0; j < boxn; j++)
  1349. add_box(P, boxes[j]);
  1350. for (i = hend.boxn - 1; i >= 0; i--)
  1351. add_box(P, hend.boxes[i]);
  1352. ps_needs_free = true;
  1353. if (et == EDGETYPE_SPLINE)
  1354. ps = routesplines(P, &pn);
  1355. else
  1356. ps = routepolylines(P, &pn);
  1357. if (pn == 0) {
  1358. free(ps);
  1359. return;
  1360. }
  1361. }
  1362. clip_and_install(e, aghead(e), ps, pn, &sinfo);
  1363. if (ps_needs_free)
  1364. free(ps);
  1365. }
  1366. static void make_flat_bottom_edges(graph_t *g, spline_info_t *sp, path *P,
  1367. edge_t **edges, unsigned ind, unsigned cnt,
  1368. edge_t *e, bool use_splines) {
  1369. node_t *tn, *hn;
  1370. int j, r;
  1371. double stepx, stepy, vspace;
  1372. rank_t *nextr;
  1373. pathend_t tend, hend;
  1374. tn = agtail(e);
  1375. hn = aghead(e);
  1376. r = ND_rank(tn);
  1377. if (r < GD_maxrank(g)) {
  1378. nextr = GD_rank(g) + (r + 1);
  1379. vspace = ND_coord(tn).y - GD_rank(g)[r].pht1 -
  1380. (ND_coord(nextr->v[0]).y + nextr->pht2);
  1381. } else {
  1382. vspace = GD_ranksep(g);
  1383. }
  1384. stepx = sp->Multisep / (cnt + 1);
  1385. stepy = vspace / (cnt + 1);
  1386. makeBottomFlatEnd(g, sp, P, tn, e, &tend, true);
  1387. makeBottomFlatEnd(g, sp, P, hn, e, &hend, false);
  1388. for (unsigned i = 0; i < cnt; i++) {
  1389. boxf b;
  1390. e = edges[ind + i];
  1391. size_t boxn = 0;
  1392. boxf boxes[3];
  1393. b = tend.boxes[tend.boxn - 1];
  1394. boxes[boxn].LL.x = b.LL.x;
  1395. boxes[boxn].UR.y = b.LL.y;
  1396. boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx;
  1397. boxes[boxn].LL.y = b.LL.y - (i + 1) * stepy;
  1398. boxn++;
  1399. boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
  1400. boxes[boxn].UR.y = boxes[boxn - 1].LL.y;
  1401. boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
  1402. boxes[boxn].LL.y = boxes[boxn].UR.y - stepy;
  1403. boxn++;
  1404. b = hend.boxes[hend.boxn - 1];
  1405. boxes[boxn].UR.x = b.UR.x;
  1406. boxes[boxn].UR.y = b.LL.y;
  1407. boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx;
  1408. boxes[boxn].LL.y = boxes[boxn - 1].UR.y;
  1409. boxn++;
  1410. assert(boxn == sizeof(boxes) / sizeof(boxes[0]));
  1411. for (j = 0; j < tend.boxn; j++)
  1412. add_box(P, tend.boxes[j]);
  1413. for (size_t k = 0; k < boxn; k++)
  1414. add_box(P, boxes[k]);
  1415. for (j = hend.boxn - 1; j >= 0; j--)
  1416. add_box(P, hend.boxes[j]);
  1417. pointf *ps = NULL;
  1418. size_t pn = 0;
  1419. if (use_splines)
  1420. ps = routesplines(P, &pn);
  1421. else
  1422. ps = routepolylines(P, &pn);
  1423. if (pn == 0) {
  1424. free(ps);
  1425. return;
  1426. }
  1427. clip_and_install(e, aghead(e), ps, pn, &sinfo);
  1428. free(ps);
  1429. P->nbox = 0;
  1430. }
  1431. }
  1432. /* make_flat_edge:
  1433. * Construct flat edges edges[ind...ind+cnt-1]
  1434. * There are 4 main cases:
  1435. * - all edges between a and b where a and b are adjacent
  1436. * - one labeled edge
  1437. * - all non-labeled edges with identical ports between non-adjacent a and b
  1438. * = connecting bottom to bottom/left/right - route along bottom
  1439. * = the rest - route along top
  1440. */
  1441. static void make_flat_edge(graph_t *g, spline_info_t *sp, path *P,
  1442. edge_t **edges, unsigned ind, unsigned cnt, int et) {
  1443. node_t *tn, *hn;
  1444. Agedgeinfo_t fwdedgei;
  1445. Agedgepair_t fwdedge;
  1446. edge_t *e;
  1447. int j, r;
  1448. double stepx, stepy, vspace;
  1449. int tside, hside;
  1450. pathend_t tend, hend;
  1451. fwdedge.out.base.data = (Agrec_t *)&fwdedgei;
  1452. /* Get sample edge; normalize to go from left to right */
  1453. e = edges[ind];
  1454. bool isAdjacent = ED_adjacent(e) != 0;
  1455. if (ED_tree_index(e) & BWDEDGE) {
  1456. MAKEFWDEDGE(&fwdedge.out, e);
  1457. e = &fwdedge.out;
  1458. }
  1459. for (unsigned i = 1; i < cnt; i++) {
  1460. if (ED_adjacent(edges[ind + i])) {
  1461. isAdjacent = true;
  1462. break;
  1463. }
  1464. }
  1465. /* The lead edge edges[ind] might not have been marked earlier as adjacent,
  1466. * so check them all.
  1467. */
  1468. if (isAdjacent) {
  1469. make_flat_adj_edges(g, edges, ind, cnt, e, et);
  1470. return;
  1471. }
  1472. if (ED_label(e)) { /* edges with labels aren't multi-edges */
  1473. make_flat_labeled_edge(g, sp, P, e, et);
  1474. return;
  1475. }
  1476. if (et == EDGETYPE_LINE) {
  1477. makeSimpleFlat(agtail(e), aghead(e), edges, ind, cnt, et);
  1478. return;
  1479. }
  1480. tside = ED_tail_port(e).side;
  1481. hside = ED_head_port(e).side;
  1482. if ((tside == BOTTOM && hside != TOP) || (hside == BOTTOM && tside != TOP)) {
  1483. make_flat_bottom_edges(g, sp, P, edges, ind, cnt, e, et == EDGETYPE_SPLINE);
  1484. return;
  1485. }
  1486. tn = agtail(e);
  1487. hn = aghead(e);
  1488. r = ND_rank(tn);
  1489. if (r > 0) {
  1490. rank_t *prevr;
  1491. if (GD_has_labels(g->root) & EDGE_LABEL)
  1492. prevr = GD_rank(g) + (r - 2);
  1493. else
  1494. prevr = GD_rank(g) + (r - 1);
  1495. vspace = ND_coord(prevr->v[0]).y - prevr->ht1 - ND_coord(tn).y -
  1496. GD_rank(g)[r].ht2;
  1497. } else {
  1498. vspace = GD_ranksep(g);
  1499. }
  1500. stepx = sp->Multisep / (cnt + 1);
  1501. stepy = vspace / (cnt + 1);
  1502. makeFlatEnd(g, sp, P, tn, e, &tend, true);
  1503. makeFlatEnd(g, sp, P, hn, e, &hend, false);
  1504. for (unsigned i = 0; i < cnt; i++) {
  1505. boxf b;
  1506. e = edges[ind + i];
  1507. size_t boxn = 0;
  1508. boxf boxes[3];
  1509. b = tend.boxes[tend.boxn - 1];
  1510. boxes[boxn].LL.x = b.LL.x;
  1511. boxes[boxn].LL.y = b.UR.y;
  1512. boxes[boxn].UR.x = b.UR.x + (i + 1) * stepx;
  1513. boxes[boxn].UR.y = b.UR.y + (i + 1) * stepy;
  1514. boxn++;
  1515. boxes[boxn].LL.x = tend.boxes[tend.boxn - 1].LL.x;
  1516. boxes[boxn].LL.y = boxes[boxn - 1].UR.y;
  1517. boxes[boxn].UR.x = hend.boxes[hend.boxn - 1].UR.x;
  1518. boxes[boxn].UR.y = boxes[boxn].LL.y + stepy;
  1519. boxn++;
  1520. b = hend.boxes[hend.boxn - 1];
  1521. boxes[boxn].UR.x = b.UR.x;
  1522. boxes[boxn].LL.y = b.UR.y;
  1523. boxes[boxn].LL.x = b.LL.x - (i + 1) * stepx;
  1524. boxes[boxn].UR.y = boxes[boxn - 1].LL.y;
  1525. boxn++;
  1526. assert(boxn == sizeof(boxes) / sizeof(boxes[0]));
  1527. for (j = 0; j < tend.boxn; j++)
  1528. add_box(P, tend.boxes[j]);
  1529. for (size_t k = 0; k < boxn; k++)
  1530. add_box(P, boxes[k]);
  1531. for (j = hend.boxn - 1; j >= 0; j--)
  1532. add_box(P, hend.boxes[j]);
  1533. pointf *ps = NULL;
  1534. size_t pn = 0;
  1535. if (et == EDGETYPE_SPLINE)
  1536. ps = routesplines(P, &pn);
  1537. else
  1538. ps = routepolylines(P, &pn);
  1539. if (pn == 0) {
  1540. free(ps);
  1541. return;
  1542. }
  1543. clip_and_install(e, aghead(e), ps, pn, &sinfo);
  1544. free(ps);
  1545. P->nbox = 0;
  1546. }
  1547. }
  1548. /// Return true if p3 is to left of ray p1->p2
  1549. static bool leftOf(pointf p1, pointf p2, pointf p3) {
  1550. return (p1.y - p2.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p1.x - p2.x) > 0;
  1551. }
  1552. /* makeLineEdge:
  1553. * Create an edge as line segment. We guarantee that the points
  1554. * are always drawn downwards. This means that for flipped edges,
  1555. * we draw from the head to the tail. The routine returns the
  1556. * end node of the edge in *hp. The points are stored in the
  1557. * given array of points, and the number of points is returned.
  1558. *
  1559. * If the edge has a label, the edge is draw as two segments, with
  1560. * the bend near the label.
  1561. *
  1562. * If the endpoints are on adjacent ranks, revert to usual code by
  1563. * returning 0.
  1564. * This is done because the usual code handles the interaction of
  1565. * multiple edges better.
  1566. */
  1567. static int makeLineEdge(graph_t *g, edge_t *fe, points_t *points, node_t **hp) {
  1568. int delr, pn;
  1569. node_t *hn;
  1570. node_t *tn;
  1571. edge_t *e = fe;
  1572. pointf startp, endp, lp;
  1573. pointf dimen;
  1574. double width, height;
  1575. while (ED_edge_type(e) != NORMAL)
  1576. e = ED_to_orig(e);
  1577. hn = aghead(e);
  1578. tn = agtail(e);
  1579. delr = abs(ND_rank(hn) - ND_rank(tn));
  1580. if (delr == 1 || (delr == 2 && (GD_has_labels(g->root) & EDGE_LABEL)))
  1581. return 0;
  1582. if (agtail(fe) == agtail(e)) {
  1583. *hp = hn;
  1584. startp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
  1585. endp = add_pointf(ND_coord(hn), ED_head_port(e).p);
  1586. } else {
  1587. *hp = tn;
  1588. startp = add_pointf(ND_coord(hn), ED_head_port(e).p);
  1589. endp = add_pointf(ND_coord(tn), ED_tail_port(e).p);
  1590. }
  1591. if (ED_label(e)) {
  1592. dimen = ED_label(e)->dimen;
  1593. if (GD_flip(agraphof(hn))) {
  1594. width = dimen.y;
  1595. height = dimen.x;
  1596. } else {
  1597. width = dimen.x;
  1598. height = dimen.y;
  1599. }
  1600. lp = ED_label(e)->pos;
  1601. if (leftOf(endp, startp, lp)) {
  1602. lp.x += width / 2.0;
  1603. lp.y -= height / 2.0;
  1604. } else {
  1605. lp.x -= width / 2.0;
  1606. lp.y += height / 2.0;
  1607. }
  1608. points_append(points, startp);
  1609. points_append(points, startp);
  1610. points_append(points, lp);
  1611. points_append(points, lp);
  1612. points_append(points, lp);
  1613. points_append(points, endp);
  1614. points_append(points, endp);
  1615. pn = 7;
  1616. } else {
  1617. points_append(points, startp);
  1618. points_append(points, startp);
  1619. points_append(points, endp);
  1620. points_append(points, endp);
  1621. pn = 4;
  1622. }
  1623. return pn;
  1624. }
  1625. static void make_regular_edge(graph_t *g, spline_info_t *sp, path *P,
  1626. edge_t **edges, unsigned ind, unsigned cnt,
  1627. int et) {
  1628. node_t *tn, *hn;
  1629. Agedgeinfo_t fwdedgeai, fwdedgebi, fwdedgei;
  1630. Agedgepair_t fwdedgea, fwdedgeb, fwdedge;
  1631. edge_t *e, *fe, *le, *segfirst;
  1632. pathend_t tend, hend;
  1633. boxf b;
  1634. int sl, si;
  1635. points_t pointfs = {0};
  1636. points_t pointfs2 = {0};
  1637. fwdedgea.out.base.data = (Agrec_t *)&fwdedgeai;
  1638. fwdedgeb.out.base.data = (Agrec_t *)&fwdedgebi;
  1639. fwdedge.out.base.data = (Agrec_t *)&fwdedgei;
  1640. sl = 0;
  1641. e = edges[ind];
  1642. bool hackflag = false;
  1643. if (abs(ND_rank(agtail(e)) - ND_rank(aghead(e))) > 1) {
  1644. fwdedgeai = *(Agedgeinfo_t *)e->base.data;
  1645. fwdedgea.out = *e;
  1646. fwdedgea.in = *AGOUT2IN(e);
  1647. fwdedgea.out.base.data = (Agrec_t *)&fwdedgeai;
  1648. if (ED_tree_index(e) & BWDEDGE) {
  1649. MAKEFWDEDGE(&fwdedgeb.out, e);
  1650. agtail(&fwdedgea.out) = aghead(e);
  1651. ED_tail_port(&fwdedgea.out) = ED_head_port(e);
  1652. } else {
  1653. fwdedgebi = *(Agedgeinfo_t *)e->base.data;
  1654. fwdedgeb.out = *e;
  1655. fwdedgeb.out.base.data = (Agrec_t *)&fwdedgebi;
  1656. agtail(&fwdedgea.out) = agtail(e);
  1657. fwdedgeb.in = *AGOUT2IN(e);
  1658. }
  1659. le = getmainedge(e);
  1660. while (ED_to_virt(le))
  1661. le = ED_to_virt(le);
  1662. aghead(&fwdedgea.out) = aghead(le);
  1663. ED_head_port(&fwdedgea.out).defined = false;
  1664. ED_edge_type(&fwdedgea.out) = VIRTUAL;
  1665. ED_head_port(&fwdedgea.out).p.x = ED_head_port(&fwdedgea.out).p.y = 0;
  1666. ED_to_orig(&fwdedgea.out) = e;
  1667. e = &fwdedgea.out;
  1668. hackflag = true;
  1669. } else {
  1670. if (ED_tree_index(e) & BWDEDGE) {
  1671. MAKEFWDEDGE(&fwdedgea.out, e);
  1672. e = &fwdedgea.out;
  1673. }
  1674. }
  1675. fe = e;
  1676. /* compute the spline points for the edge */
  1677. if (et == EDGETYPE_LINE && makeLineEdge(g, fe, &pointfs, &hn)) {
  1678. } else {
  1679. bool is_spline = et == EDGETYPE_SPLINE;
  1680. boxes_t boxes = {0};
  1681. segfirst = e;
  1682. tn = agtail(e);
  1683. hn = aghead(e);
  1684. b = tend.nb = maximal_bbox(g, sp, tn, NULL, e);
  1685. beginpath(P, e, REGULAREDGE, &tend, spline_merge(tn));
  1686. b.UR.y = tend.boxes[tend.boxn - 1].UR.y;
  1687. b.LL.y = tend.boxes[tend.boxn - 1].LL.y;
  1688. b = makeregularend(b, BOTTOM, ND_coord(tn).y - GD_rank(g)[ND_rank(tn)].ht1);
  1689. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1690. tend.boxes[tend.boxn++] = b;
  1691. bool smode = false;
  1692. si = -1;
  1693. while (ND_node_type(hn) == VIRTUAL && !sinfo.splineMerge(hn)) {
  1694. boxes_append(&boxes, rank_box(sp, g, ND_rank(tn)));
  1695. if (!smode && ((sl = straight_len(hn)) >=
  1696. ((GD_has_labels(g->root) & EDGE_LABEL) ? 4 + 1 : 2 + 1))) {
  1697. smode = true;
  1698. si = 1, sl -= 2;
  1699. }
  1700. if (!smode || si > 0) {
  1701. si--;
  1702. boxes_append(&boxes, maximal_bbox(g, sp, hn, e, ND_out(hn).list[0]));
  1703. e = ND_out(hn).list[0];
  1704. tn = agtail(e);
  1705. hn = aghead(e);
  1706. continue;
  1707. }
  1708. hend.nb = maximal_bbox(g, sp, hn, e, ND_out(hn).list[0]);
  1709. endpath(P, e, REGULAREDGE, &hend, spline_merge(aghead(e)));
  1710. b = makeregularend(hend.boxes[hend.boxn - 1], TOP,
  1711. ND_coord(hn).y + GD_rank(g)[ND_rank(hn)].ht2);
  1712. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1713. hend.boxes[hend.boxn++] = b;
  1714. P->end.theta = M_PI / 2, P->end.constrained = true;
  1715. completeregularpath(P, segfirst, e, &tend, &hend, &boxes);
  1716. pointf *ps = NULL;
  1717. size_t pn = 0;
  1718. if (is_spline)
  1719. ps = routesplines(P, &pn);
  1720. else {
  1721. ps = routepolylines(P, &pn);
  1722. if (et == EDGETYPE_LINE && pn > 4) {
  1723. ps[1] = ps[0];
  1724. ps[3] = ps[2] = ps[pn - 1];
  1725. pn = 4;
  1726. }
  1727. }
  1728. if (pn == 0) {
  1729. free(ps);
  1730. boxes_free(&boxes);
  1731. points_free(&pointfs);
  1732. points_free(&pointfs2);
  1733. return;
  1734. }
  1735. for (size_t i = 0; i < pn; i++) {
  1736. points_append(&pointfs, ps[i]);
  1737. }
  1738. free(ps);
  1739. e = straight_path(ND_out(hn).list[0], sl, &pointfs);
  1740. recover_slack(segfirst, P);
  1741. segfirst = e;
  1742. tn = agtail(e);
  1743. hn = aghead(e);
  1744. boxes_clear(&boxes);
  1745. tend.nb = maximal_bbox(g, sp, tn, ND_in(tn).list[0], e);
  1746. beginpath(P, e, REGULAREDGE, &tend, spline_merge(tn));
  1747. b = makeregularend(tend.boxes[tend.boxn - 1], BOTTOM,
  1748. ND_coord(tn).y - GD_rank(g)[ND_rank(tn)].ht1);
  1749. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1750. tend.boxes[tend.boxn++] = b;
  1751. P->start.theta = -M_PI / 2, P->start.constrained = true;
  1752. smode = false;
  1753. }
  1754. boxes_append(&boxes, rank_box(sp, g, ND_rank(tn)));
  1755. b = hend.nb = maximal_bbox(g, sp, hn, e, NULL);
  1756. endpath(P, hackflag ? &fwdedgeb.out : e, REGULAREDGE, &hend,
  1757. spline_merge(aghead(e)));
  1758. b.UR.y = hend.boxes[hend.boxn - 1].UR.y;
  1759. b.LL.y = hend.boxes[hend.boxn - 1].LL.y;
  1760. b = makeregularend(b, TOP, ND_coord(hn).y + GD_rank(g)[ND_rank(hn)].ht2);
  1761. if (b.LL.x < b.UR.x && b.LL.y < b.UR.y)
  1762. hend.boxes[hend.boxn++] = b;
  1763. completeregularpath(P, segfirst, e, &tend, &hend, &boxes);
  1764. boxes_free(&boxes);
  1765. pointf *ps = NULL;
  1766. size_t pn = 0;
  1767. if (is_spline)
  1768. ps = routesplines(P, &pn);
  1769. else
  1770. ps = routepolylines(P, &pn);
  1771. if (et == EDGETYPE_LINE && pn > 4) {
  1772. /* Here we have used the polyline case to handle
  1773. * an edge between two nodes on adjacent ranks. If the
  1774. * results really is a polyline, straighten it.
  1775. */
  1776. ps[1] = ps[0];
  1777. ps[3] = ps[2] = ps[pn - 1];
  1778. pn = 4;
  1779. }
  1780. if (pn == 0) {
  1781. free(ps);
  1782. points_free(&pointfs);
  1783. points_free(&pointfs2);
  1784. return;
  1785. }
  1786. for (size_t i = 0; i < pn; i++) {
  1787. points_append(&pointfs, ps[i]);
  1788. }
  1789. free(ps);
  1790. recover_slack(segfirst, P);
  1791. hn = hackflag ? aghead(&fwdedgeb.out) : aghead(e);
  1792. }
  1793. /* make copies of the spline points, one per multi-edge */
  1794. if (cnt == 1) {
  1795. points_sync(&pointfs);
  1796. clip_and_install(fe, hn, points_front(&pointfs), points_size(&pointfs),
  1797. &sinfo);
  1798. points_free(&pointfs);
  1799. points_free(&pointfs2);
  1800. return;
  1801. }
  1802. const double dx = sp->Multisep * (cnt - 1) / 2;
  1803. for (size_t k = 1; k + 1 < points_size(&pointfs); k++)
  1804. points_at(&pointfs, k)->x -= dx;
  1805. for (size_t k = 0; k < points_size(&pointfs); k++)
  1806. points_append(&pointfs2, points_get(&pointfs, k));
  1807. points_sync(&pointfs2);
  1808. clip_and_install(fe, hn, points_front(&pointfs2), points_size(&pointfs2),
  1809. &sinfo);
  1810. for (unsigned j = 1; j < cnt; j++) {
  1811. e = edges[ind + j];
  1812. if (ED_tree_index(e) & BWDEDGE) {
  1813. MAKEFWDEDGE(&fwdedge.out, e);
  1814. e = &fwdedge.out;
  1815. }
  1816. for (size_t k = 1; k + 1 < points_size(&pointfs); k++)
  1817. points_at(&pointfs, k)->x += sp->Multisep;
  1818. points_clear(&pointfs2);
  1819. for (size_t k = 0; k < points_size(&pointfs); k++)
  1820. points_append(&pointfs2, points_get(&pointfs, k));
  1821. points_sync(&pointfs2);
  1822. clip_and_install(e, aghead(e), points_front(&pointfs2),
  1823. points_size(&pointfs2), &sinfo);
  1824. }
  1825. points_free(&pointfs);
  1826. points_free(&pointfs2);
  1827. }
  1828. /* regular edges */
  1829. static void completeregularpath(path *P, edge_t *first, edge_t *last,
  1830. pathend_t *tendp, pathend_t *hendp,
  1831. const boxes_t *boxes) {
  1832. edge_t *uleft, *uright, *lleft, *lright;
  1833. uleft = uright = NULL;
  1834. uleft = top_bound(first, -1), uright = top_bound(first, 1);
  1835. if (uleft) {
  1836. if (getsplinepoints(uleft) == NULL)
  1837. return;
  1838. }
  1839. if (uright) {
  1840. if (getsplinepoints(uright) == NULL)
  1841. return;
  1842. }
  1843. lleft = lright = NULL;
  1844. lleft = bot_bound(last, -1), lright = bot_bound(last, 1);
  1845. if (lleft) {
  1846. if (getsplinepoints(lleft) == NULL)
  1847. return;
  1848. }
  1849. if (lright) {
  1850. if (getsplinepoints(lright) == NULL)
  1851. return;
  1852. }
  1853. for (int i = 0; i < tendp->boxn; i++)
  1854. add_box(P, tendp->boxes[i]);
  1855. const size_t fb = P->nbox + 1;
  1856. const size_t lb = fb + boxes_size(boxes) - 3;
  1857. for (size_t i = 0; i < boxes_size(boxes); i++)
  1858. add_box(P, boxes_get(boxes, i));
  1859. for (int i = hendp->boxn - 1; i >= 0; i--)
  1860. add_box(P, hendp->boxes[i]);
  1861. adjustregularpath(P, fb, lb);
  1862. }
  1863. /* makeregularend:
  1864. * Add box to fill between node and interrank space. Needed because
  1865. * nodes in a given rank can differ in height.
  1866. * for now, regular edges always go from top to bottom
  1867. */
  1868. static boxf makeregularend(boxf b, int side, double y) {
  1869. assert(side == BOTTOM || side == TOP);
  1870. if (side == BOTTOM) {
  1871. return (boxf){{b.LL.x, y}, {b.UR.x, b.LL.y}};
  1872. }
  1873. return (boxf){{b.LL.x, b.UR.y}, {b.UR.x, y}};
  1874. }
  1875. /* adjustregularpath:
  1876. * make sure the path is wide enough.
  1877. * the % 2 was so that in rank boxes would only be grown if
  1878. * they were == 0 while inter-rank boxes could be stretched to a min
  1879. * width.
  1880. * The list of boxes has three parts: tail boxes, path boxes, and head
  1881. * boxes. (Note that because of back edges, the tail boxes might actually
  1882. * belong to the head node, and vice versa.) fb is the index of the
  1883. * first interrank path box and lb is the last interrank path box.
  1884. * If fb > lb, there are none.
  1885. *
  1886. * The second for loop was added by ek long ago, and apparently is intended
  1887. * to guarantee an overlap between adjacent boxes of at least MINW.
  1888. * It doesn't do this.
  1889. */
  1890. static void adjustregularpath(path *P, size_t fb, size_t lb) {
  1891. boxf *bp1, *bp2;
  1892. for (size_t i = fb - 1; i < lb + 1; i++) {
  1893. bp1 = &P->boxes[i];
  1894. if ((i - fb) % 2 == 0) {
  1895. if (bp1->LL.x >= bp1->UR.x) {
  1896. double x = (bp1->LL.x + bp1->UR.x) / 2;
  1897. bp1->LL.x = x - HALFMINW;
  1898. bp1->UR.x = x + HALFMINW;
  1899. }
  1900. } else {
  1901. if (bp1->LL.x + MINW > bp1->UR.x) {
  1902. double x = (bp1->LL.x + bp1->UR.x) / 2;
  1903. bp1->LL.x = x - HALFMINW;
  1904. bp1->UR.x = x + HALFMINW;
  1905. }
  1906. }
  1907. }
  1908. for (size_t i = 0; i + 1 < P->nbox; i++) {
  1909. bp1 = &P->boxes[i], bp2 = &P->boxes[i + 1];
  1910. if (i >= fb && i <= lb && (i - fb) % 2 == 0) {
  1911. if (bp1->LL.x + MINW > bp2->UR.x)
  1912. bp2->UR.x = bp1->LL.x + MINW;
  1913. if (bp1->UR.x - MINW < bp2->LL.x)
  1914. bp2->LL.x = bp1->UR.x - MINW;
  1915. } else if (i + 1 >= fb && i < lb && (i + 1 - fb) % 2 == 0) {
  1916. if (bp1->LL.x + MINW > bp2->UR.x)
  1917. bp1->LL.x = bp2->UR.x - MINW;
  1918. if (bp1->UR.x - MINW < bp2->LL.x)
  1919. bp1->UR.x = bp2->LL.x + MINW;
  1920. }
  1921. }
  1922. }
  1923. static boxf rank_box(spline_info_t *sp, graph_t *g, int r) {
  1924. boxf b;
  1925. node_t *left0, *left1;
  1926. b = sp->Rank_box[r];
  1927. if (b.LL.x == b.UR.x) {
  1928. left0 = GD_rank(g)[r].v[0];
  1929. left1 = GD_rank(g)[r + 1].v[0];
  1930. b.LL.x = sp->LeftBound;
  1931. b.LL.y = ND_coord(left1).y + GD_rank(g)[r + 1].ht2;
  1932. b.UR.x = sp->RightBound;
  1933. b.UR.y = ND_coord(left0).y - GD_rank(g)[r].ht1;
  1934. sp->Rank_box[r] = b;
  1935. }
  1936. return b;
  1937. }
  1938. /* returns count of vertically aligned edges starting at n */
  1939. static int straight_len(node_t *n) {
  1940. int cnt = 0;
  1941. node_t *v;
  1942. v = n;
  1943. while (1) {
  1944. v = aghead(ND_out(v).list[0]);
  1945. if (ND_node_type(v) != VIRTUAL)
  1946. break;
  1947. if (ND_out(v).size != 1 || ND_in(v).size != 1)
  1948. break;
  1949. if (ND_coord(v).x != ND_coord(n).x)
  1950. break;
  1951. cnt++;
  1952. }
  1953. return cnt;
  1954. }
  1955. static edge_t *straight_path(edge_t *e, int cnt, points_t *plist) {
  1956. edge_t *f = e;
  1957. while (cnt--)
  1958. f = ND_out(aghead(f)).list[0];
  1959. assert(!points_is_empty(plist));
  1960. points_append(plist, points_get(plist, points_size(plist) - 1));
  1961. points_append(plist, points_get(plist, points_size(plist) - 1));
  1962. return f;
  1963. }
  1964. static void recover_slack(edge_t *e, path *p) {
  1965. node_t *vn;
  1966. size_t b = 0; // skip first rank box
  1967. for (vn = aghead(e); ND_node_type(vn) == VIRTUAL && !sinfo.splineMerge(vn);
  1968. vn = aghead(ND_out(vn).list[0])) {
  1969. while (b < p->nbox && p->boxes[b].LL.y > ND_coord(vn).y)
  1970. b++;
  1971. if (b >= p->nbox)
  1972. break;
  1973. if (p->boxes[b].UR.y < ND_coord(vn).y)
  1974. continue;
  1975. if (ND_label(vn))
  1976. resize_vn(vn, p->boxes[b].LL.x, p->boxes[b].UR.x,
  1977. p->boxes[b].UR.x + ND_rw(vn));
  1978. else
  1979. resize_vn(vn, p->boxes[b].LL.x, (p->boxes[b].LL.x + p->boxes[b].UR.x) / 2,
  1980. p->boxes[b].UR.x);
  1981. }
  1982. }
  1983. static void resize_vn(node_t *vn, double lx, double cx, double rx) {
  1984. ND_coord(vn).x = cx;
  1985. ND_lw(vn) = cx - lx, ND_rw(vn) = rx - cx;
  1986. }
  1987. /* side > 0 means right. side < 0 means left */
  1988. static edge_t *top_bound(edge_t *e, int side) {
  1989. edge_t *f, *ans = NULL;
  1990. int i;
  1991. for (i = 0; (f = ND_out(agtail(e)).list[i]); i++) {
  1992. if (side * (ND_order(aghead(f)) - ND_order(aghead(e))) <= 0)
  1993. continue;
  1994. if (ED_spl(f) == NULL &&
  1995. (ED_to_orig(f) == NULL || ED_spl(ED_to_orig(f)) == NULL))
  1996. continue;
  1997. if (ans == NULL || side * (ND_order(aghead(ans)) - ND_order(aghead(f))) > 0)
  1998. ans = f;
  1999. }
  2000. return ans;
  2001. }
  2002. static edge_t *bot_bound(edge_t *e, int side) {
  2003. edge_t *f, *ans = NULL;
  2004. int i;
  2005. for (i = 0; (f = ND_in(aghead(e)).list[i]); i++) {
  2006. if (side * (ND_order(agtail(f)) - ND_order(agtail(e))) <= 0)
  2007. continue;
  2008. if (ED_spl(f) == NULL &&
  2009. (ED_to_orig(f) == NULL || ED_spl(ED_to_orig(f)) == NULL))
  2010. continue;
  2011. if (ans == NULL || side * (ND_order(agtail(ans)) - ND_order(agtail(f))) > 0)
  2012. ans = f;
  2013. }
  2014. return ans;
  2015. }
  2016. /* common routines */
  2017. static bool cl_vninside(graph_t *cl, node_t *n) {
  2018. return BETWEEN(GD_bb(cl).LL.x, ND_coord(n).x, GD_bb(cl).UR.x) &&
  2019. BETWEEN(GD_bb(cl).LL.y, ND_coord(n).y, GD_bb(cl).UR.y);
  2020. }
  2021. /* All nodes belong to some cluster, which may be the root graph.
  2022. * For the following, we only want a cluster if it is a real cluster
  2023. * It is not clear this will handle all potential problems. It seems one
  2024. * could have hcl and tcl contained in cl, which would also cause problems.
  2025. */
  2026. #define REAL_CLUSTER(n) (ND_clust(n) == g ? NULL : ND_clust(n))
  2027. /* returns the cluster of (adj) that interferes with n,
  2028. */
  2029. static Agraph_t *cl_bound(graph_t *g, node_t *n, node_t *adj) {
  2030. graph_t *rv, *cl, *tcl, *hcl;
  2031. edge_t *orig;
  2032. rv = NULL;
  2033. if (ND_node_type(n) == NORMAL)
  2034. tcl = hcl = ND_clust(n);
  2035. else {
  2036. orig = ED_to_orig(ND_out(n).list[0]);
  2037. tcl = ND_clust(agtail(orig));
  2038. hcl = ND_clust(aghead(orig));
  2039. }
  2040. if (ND_node_type(adj) == NORMAL) {
  2041. cl = REAL_CLUSTER(adj);
  2042. if (cl && cl != tcl && cl != hcl)
  2043. rv = cl;
  2044. } else {
  2045. orig = ED_to_orig(ND_out(adj).list[0]);
  2046. cl = REAL_CLUSTER(agtail(orig));
  2047. if (cl && cl != tcl && cl != hcl && cl_vninside(cl, adj))
  2048. rv = cl;
  2049. else {
  2050. cl = REAL_CLUSTER(aghead(orig));
  2051. if (cl && cl != tcl && cl != hcl && cl_vninside(cl, adj))
  2052. rv = cl;
  2053. }
  2054. }
  2055. return rv;
  2056. }
  2057. /* maximal_bbox:
  2058. * Return an initial bounding box to be used for building the
  2059. * beginning or ending of the path of boxes.
  2060. * Height reflects height of tallest node on rank.
  2061. * The extra space provided by FUDGE allows begin/endpath to create a box
  2062. * FUDGE-2 away from the node, so the routing can avoid the node and the
  2063. * box is at least 2 wide.
  2064. */
  2065. #define FUDGE 4
  2066. static boxf maximal_bbox(graph_t *g, spline_info_t *sp, node_t *vn, edge_t *ie,
  2067. edge_t *oe) {
  2068. double b, nb;
  2069. graph_t *left_cl, *right_cl;
  2070. node_t *left, *right;
  2071. boxf rv;
  2072. left_cl = right_cl = NULL;
  2073. /* give this node all the available space up to its neighbors */
  2074. b = (double)(ND_coord(vn).x - ND_lw(vn) - FUDGE);
  2075. if ((left = neighbor(g, vn, ie, oe, -1))) {
  2076. if ((left_cl = cl_bound(g, vn, left)))
  2077. nb = GD_bb(left_cl).UR.x + sp->Splinesep;
  2078. else {
  2079. nb = (double)(ND_coord(left).x + ND_mval(left));
  2080. if (ND_node_type(left) == NORMAL)
  2081. nb += GD_nodesep(g) / 2.;
  2082. else
  2083. nb += sp->Splinesep;
  2084. }
  2085. if (nb < b)
  2086. b = nb;
  2087. rv.LL.x = round(b);
  2088. } else
  2089. rv.LL.x = fmin(round(b), sp->LeftBound);
  2090. /* we have to leave room for our own label! */
  2091. if (ND_node_type(vn) == VIRTUAL && ND_label(vn))
  2092. b = (double)(ND_coord(vn).x + 10);
  2093. else
  2094. b = (double)(ND_coord(vn).x + ND_rw(vn) + FUDGE);
  2095. if ((right = neighbor(g, vn, ie, oe, 1))) {
  2096. if ((right_cl = cl_bound(g, vn, right)))
  2097. nb = GD_bb(right_cl).LL.x - sp->Splinesep;
  2098. else {
  2099. nb = ND_coord(right).x - ND_lw(right);
  2100. if (ND_node_type(right) == NORMAL)
  2101. nb -= GD_nodesep(g) / 2.;
  2102. else
  2103. nb -= sp->Splinesep;
  2104. }
  2105. if (nb > b)
  2106. b = nb;
  2107. rv.UR.x = round(b);
  2108. } else
  2109. rv.UR.x = fmax(round(b), sp->RightBound);
  2110. if (ND_node_type(vn) == VIRTUAL && ND_label(vn)) {
  2111. rv.UR.x -= ND_rw(vn);
  2112. if (rv.UR.x < rv.LL.x)
  2113. rv.UR.x = ND_coord(vn).x;
  2114. }
  2115. rv.LL.y = ND_coord(vn).y - GD_rank(g)[ND_rank(vn)].ht1;
  2116. rv.UR.y = ND_coord(vn).y + GD_rank(g)[ND_rank(vn)].ht2;
  2117. return rv;
  2118. }
  2119. static node_t *neighbor(graph_t *g, node_t *vn, edge_t *ie, edge_t *oe,
  2120. int dir) {
  2121. int i;
  2122. node_t *n, *rv = NULL;
  2123. rank_t *rank = &(GD_rank(g)[ND_rank(vn)]);
  2124. for (i = ND_order(vn) + dir; i >= 0 && i < rank->n; i += dir) {
  2125. n = rank->v[i];
  2126. if (ND_node_type(n) == VIRTUAL && ND_label(n)) {
  2127. rv = n;
  2128. break;
  2129. }
  2130. if (ND_node_type(n) == NORMAL) {
  2131. rv = n;
  2132. break;
  2133. }
  2134. if (!pathscross(n, vn, ie, oe)) {
  2135. rv = n;
  2136. break;
  2137. }
  2138. }
  2139. return rv;
  2140. }
  2141. static bool pathscross(node_t *n0, node_t *n1, edge_t *ie1, edge_t *oe1) {
  2142. edge_t *e0, *e1;
  2143. node_t *na, *nb;
  2144. int order, cnt;
  2145. order = ND_order(n0) > ND_order(n1);
  2146. if (ND_out(n0).size != 1 && ND_out(n1).size != 1)
  2147. return false;
  2148. e1 = oe1;
  2149. if (ND_out(n0).size == 1 && e1) {
  2150. e0 = ND_out(n0).list[0];
  2151. for (cnt = 0; cnt < 2; cnt++) {
  2152. if ((na = aghead(e0)) == (nb = aghead(e1)))
  2153. break;
  2154. if (order != (ND_order(na) > ND_order(nb)))
  2155. return true;
  2156. if (ND_out(na).size != 1 || ND_node_type(na) == NORMAL)
  2157. break;
  2158. e0 = ND_out(na).list[0];
  2159. if (ND_out(nb).size != 1 || ND_node_type(nb) == NORMAL)
  2160. break;
  2161. e1 = ND_out(nb).list[0];
  2162. }
  2163. }
  2164. e1 = ie1;
  2165. if (ND_in(n0).size == 1 && e1) {
  2166. e0 = ND_in(n0).list[0];
  2167. for (cnt = 0; cnt < 2; cnt++) {
  2168. if ((na = agtail(e0)) == (nb = agtail(e1)))
  2169. break;
  2170. if (order != (ND_order(na) > ND_order(nb)))
  2171. return true;
  2172. if (ND_in(na).size != 1 || ND_node_type(na) == NORMAL)
  2173. break;
  2174. e0 = ND_in(na).list[0];
  2175. if (ND_in(nb).size != 1 || ND_node_type(nb) == NORMAL)
  2176. break;
  2177. e1 = ND_in(nb).list[0];
  2178. }
  2179. }
  2180. return false;
  2181. }
  2182. #ifdef DEBUG
  2183. void showpath(path *p) {
  2184. pointf LL, UR;
  2185. fprintf(stderr, "%%!PS\n");
  2186. for (size_t i = 0; i < p->nbox; i++) {
  2187. LL = p->boxes[i].LL;
  2188. UR = p->boxes[i].UR;
  2189. fprintf(stderr,
  2190. "newpath %.04f %.04f moveto %.04f %.04f lineto %.04f %.04f lineto "
  2191. "%.04f %.04f lineto closepath stroke\n",
  2192. LL.x, LL.y, UR.x, LL.y, UR.x, UR.y, LL.x, UR.y);
  2193. }
  2194. fprintf(stderr, "showpage\n");
  2195. }
  2196. #endif