neatosplines.c 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  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. #include <assert.h>
  11. #include "config.h"
  12. #include <limits.h>
  13. #include <math.h>
  14. #include <neatogen/neato.h>
  15. #include <neatogen/adjust.h>
  16. #include <pathplan/pathplan.h>
  17. #include <pathplan/vispath.h>
  18. #include <neatogen/multispline.h>
  19. #include <stdbool.h>
  20. #include <stddef.h>
  21. #include <util/alloc.h>
  22. #include <util/unreachable.h>
  23. #ifdef ORTHO
  24. #include <ortho/ortho.h>
  25. #endif
  26. static bool spline_merge(node_t * n)
  27. {
  28. (void)n;
  29. return false;
  30. }
  31. static bool swap_ends_p(edge_t * e)
  32. {
  33. (void)e;
  34. return false;
  35. }
  36. static splineInfo sinfo = {.swapEnds = swap_ends_p,
  37. .splineMerge = spline_merge};
  38. static void make_barriers(Ppoly_t **poly, int npoly, int pp, int qp,
  39. Pedge_t **barriers, size_t *n_barriers) {
  40. int i, j, k;
  41. size_t n = 0;
  42. for (i = 0; i < npoly; i++) {
  43. if (i == pp)
  44. continue;
  45. if (i == qp)
  46. continue;
  47. n += poly[i]->pn;
  48. }
  49. Pedge_t *bar = gv_calloc(n, sizeof(Pedge_t));
  50. size_t b = 0;
  51. for (i = 0; i < npoly; i++) {
  52. if (i == pp)
  53. continue;
  54. if (i == qp)
  55. continue;
  56. for (j = 0; j < (int)poly[i]->pn; j++) {
  57. k = j + 1;
  58. if (k >= (int)poly[i]->pn)
  59. k = 0;
  60. bar[b].a = poly[i]->ps[j];
  61. bar[b].b = poly[i]->ps[k];
  62. b++;
  63. }
  64. }
  65. assert(b == n);
  66. *barriers = bar;
  67. *n_barriers = n;
  68. }
  69. static Ppoint_t genPt(double x, double y, pointf c)
  70. {
  71. Ppoint_t p;
  72. p.x = x + c.x;
  73. p.y = y + c.y;
  74. return p;
  75. }
  76. static Ppoint_t recPt(double x, double y, pointf c, expand_t* m)
  77. {
  78. Ppoint_t p;
  79. p.x = x * m->x + c.x;
  80. p.y = y * m->y + c.y;
  81. return p;
  82. }
  83. typedef struct {
  84. node_t *n1;
  85. pointf p1;
  86. node_t *n2;
  87. pointf p2;
  88. } edgeinfo;
  89. typedef struct {
  90. Dtlink_t link;
  91. edgeinfo id;
  92. edge_t *e;
  93. } edgeitem;
  94. static void *newitem(void *p, Dtdisc_t *disc) {
  95. edgeitem *obj = p;
  96. edgeitem *newp;
  97. (void)disc;
  98. newp = gv_alloc(sizeof(edgeitem));
  99. newp->id = obj->id;
  100. newp->e = obj->e;
  101. ED_count(newp->e) = 1;
  102. return newp;
  103. }
  104. static int cmpitems(void *k1, void *k2) {
  105. const edgeinfo *key1 = k1;
  106. const edgeinfo *key2 = k2;
  107. if (key1->n1 > key2->n1)
  108. return 1;
  109. if (key1->n1 < key2->n1)
  110. return -1;
  111. if (key1->n2 > key2->n2)
  112. return 1;
  113. if (key1->n2 < key2->n2)
  114. return -1;
  115. if (key1->p1.x > key2->p1.x)
  116. return 1;
  117. if (key1->p1.x < key2->p1.x)
  118. return -1;
  119. if (key1->p1.y > key2->p1.y)
  120. return 1;
  121. if (key1->p1.y < key2->p1.y)
  122. return -1;
  123. if (key1->p2.x > key2->p2.x)
  124. return 1;
  125. if (key1->p2.x < key2->p2.x)
  126. return -1;
  127. if (key1->p2.y > key2->p2.y)
  128. return 1;
  129. if (key1->p2.y < key2->p2.y)
  130. return -1;
  131. return 0;
  132. }
  133. Dtdisc_t edgeItemDisc = {
  134. offsetof(edgeitem, id),
  135. sizeof(edgeinfo),
  136. offsetof(edgeitem, link),
  137. newitem,
  138. free,
  139. cmpitems,
  140. };
  141. /* equivEdge:
  142. * See if we have already encountered an edge between the same
  143. * node:port pairs. If so, return the earlier edge. If not,
  144. * this edge is added to map and returned.
  145. * We first have to canonicalize the key fields using a lexicographic
  146. * ordering.
  147. */
  148. static edge_t *equivEdge(Dt_t * map, edge_t * e)
  149. {
  150. edgeinfo test;
  151. edgeitem dummy;
  152. edgeitem *ip;
  153. if (agtail(e) < aghead(e)) {
  154. test.n1 = agtail(e);
  155. test.p1 = ED_tail_port(e).p;
  156. test.n2 = aghead(e);
  157. test.p2 = ED_head_port(e).p;
  158. } else if (agtail(e) > aghead(e)) {
  159. test.n2 = agtail(e);
  160. test.p2 = ED_tail_port(e).p;
  161. test.n1 = aghead(e);
  162. test.p1 = ED_head_port(e).p;
  163. } else {
  164. pointf hp = ED_head_port(e).p;
  165. pointf tp = ED_tail_port(e).p;
  166. if (tp.x < hp.x) {
  167. test.p1 = tp;
  168. test.p2 = hp;
  169. } else if (tp.x > hp.x) {
  170. test.p1 = hp;
  171. test.p2 = tp;
  172. } else if (tp.y < hp.y) {
  173. test.p1 = tp;
  174. test.p2 = hp;
  175. } else if (tp.y > hp.y) {
  176. test.p1 = hp;
  177. test.p2 = tp;
  178. } else {
  179. test.p1 = test.p2 = tp;
  180. }
  181. test.n2 = test.n1 = agtail(e);
  182. }
  183. dummy.id = test;
  184. dummy.e = e;
  185. ip = dtinsert(map, &dummy);
  186. return ip->e;
  187. }
  188. /* makeSelfArcs:
  189. * Generate loops. We use the library routine makeSelfEdge
  190. * which also places the labels.
  191. * We have to handle port labels here.
  192. * as well as update the bbox from edge labels.
  193. */
  194. void makeSelfArcs(edge_t * e, int stepx)
  195. {
  196. assert(ED_count(e) >= 0);
  197. const size_t cnt = (size_t)ED_count(e);
  198. if (cnt == 1 || Concentrate) {
  199. edge_t *edges1[1];
  200. edges1[0] = e;
  201. makeSelfEdge(edges1, 0, 1, stepx, stepx, &sinfo);
  202. if (ED_label(e))
  203. updateBB(agraphof(agtail(e)), ED_label(e));
  204. makePortLabels(e);
  205. } else if (cnt > 1) {
  206. edge_t **edges = gv_calloc(cnt, sizeof(edge_t*));
  207. for (size_t i = 0; i < cnt; i++) {
  208. edges[i] = e;
  209. e = ED_to_virt(e);
  210. }
  211. makeSelfEdge(edges, 0, cnt, stepx, stepx, &sinfo);
  212. for (size_t i = 0; i < cnt; i++) {
  213. e = edges[i];
  214. if (ED_label(e))
  215. updateBB(agraphof(agtail(e)), ED_label(e));
  216. makePortLabels(e);
  217. }
  218. free(edges);
  219. }
  220. }
  221. /** calculate the slope of the tangent of an ellipse
  222. *
  223. * The equation for the slope `m` of the tangent of an ellipse as a function of
  224. * `x` * is given by:
  225. *
  226. * bx
  227. * m = ± ――――――――――
  228. * _______
  229. * a √ a²- x²
  230. *
  231. * or
  232. *
  233. * m = ± (b * x) / (a * sqrt(a * a - x * x))
  234. *
  235. * We know that the slope is negative in the first and third quadrant, i.e.,
  236. * when the signs of x and y are the same, so we use that to select the correct
  237. * slope.
  238. *
  239. * @param a Half the width of the ellipse, i.e., the maximum x value
  240. * @param b Half the height of the ellipse, i.e., the maximum y value
  241. * @param p A point on the ellipse periphery in which to calculate the slope of
  242. * the tangent
  243. * @return The slope of the tangent in point `p`
  244. */
  245. static double ellipse_tangent_slope(double a, double b, pointf p) {
  246. assert(p.x != a &&
  247. "cannot handle ellipse tangent slope in horizontal extreme point");
  248. const double sign_y = p.y >= 0 ? 1 : -1;
  249. const double m = -sign_y * (b * p.x) / (a * sqrt(a * a - p.x * p.x));
  250. assert(isfinite(m) && "ellipse tangent slope is infinite");
  251. return m;
  252. }
  253. /** calculate the intersection of two lines
  254. *
  255. * @param l0 First line
  256. * @param l1 Second line
  257. * @return Intersection of the two lines
  258. */
  259. static pointf line_intersection(linef l0, linef l1) {
  260. const double x =
  261. (l0.m * l0.p.x - l0.p.y - l1.m * l1.p.x + l1.p.y) / (l0.m - l1.m);
  262. const double y = l0.p.y + l0.m * (x - l0.p.x);
  263. return (pointf){x, y};
  264. }
  265. /** calculate a corner of a polygon circumscribed about an ellipse
  266. *
  267. * @param a Half the width of the ellipse, i.e., the maximum x value
  268. * @param b Half the height of the ellipse, i.e., the maximum y value
  269. * @param i Index of the polygon corner
  270. * @param nsides Number of sides of the polygon
  271. * @return Polygon corner at index `i`
  272. */
  273. static pointf circumscribed_polygon_corner_about_ellipse(double a, double b,
  274. size_t i,
  275. size_t nsides) {
  276. const double angle0 = 2.0 * M_PI * ((double)i - 0.5) / (double)nsides;
  277. const double angle1 = 2.0 * M_PI * ((double)i + 0.5) / (double)nsides;
  278. const pointf p0 = {a * cos(angle0), b * sin(angle0)};
  279. const pointf p1 = {a * cos(angle1), b * sin(angle1)};
  280. const double m0 = ellipse_tangent_slope(a, b, p0);
  281. const double m1 = ellipse_tangent_slope(a, b, p1);
  282. const linef line0 = {{p0.x, p0.y}, m0};
  283. const linef line1 = {{p1.x, p1.y}, m1};
  284. return line_intersection(line0, line1);
  285. }
  286. /* makeObstacle:
  287. * Given a node, return an obstacle reflecting the
  288. * node's geometry. pmargin specifies how much space to allow
  289. * around the polygon.
  290. * Returns the constructed polygon on success, NULL on failure.
  291. * Failure means the node shape is not supported.
  292. *
  293. * If isOrtho is true, we have to use the bounding box of each node.
  294. *
  295. * The polygon has its vertices in CW order.
  296. *
  297. */
  298. Ppoly_t *makeObstacle(node_t * n, expand_t* pmargin, bool isOrtho)
  299. {
  300. Ppoly_t *obs;
  301. polygon_t *poly;
  302. size_t sides;
  303. pointf polyp;
  304. boxf b;
  305. pointf pt;
  306. field_t *fld;
  307. bool isPoly;
  308. pointf* verts = NULL;
  309. pointf vs[4];
  310. pointf p;
  311. pointf margin = {0};
  312. switch (shapeOf(n)) {
  313. case SH_POLY:
  314. case SH_POINT:
  315. obs = gv_alloc(sizeof(Ppoly_t));
  316. poly = ND_shape_info(n);
  317. if (isOrtho) {
  318. isPoly = true;
  319. sides = 4;
  320. verts = vs;
  321. /* For fixedshape, we can't use the width and height, as this includes
  322. * the label. We only want to use the actual node shape.
  323. */
  324. if (poly->option.fixedshape) {
  325. b = polyBB (poly);
  326. vs[0] = b.LL;
  327. vs[1].x = b.UR.x;
  328. vs[1].y = b.LL.y;
  329. vs[2] = b.UR;
  330. vs[3].x = b.LL.x;
  331. vs[3].y = b.UR.y;
  332. } else {
  333. const double width = ND_lw(n) + ND_rw(n);
  334. const double outline_width = INCH2PS(ND_outline_width(n));
  335. // scale lw and rw proportionally to sum to outline width
  336. const double outline_lw = ND_lw(n) * outline_width / width;
  337. const double outline_ht = INCH2PS(ND_outline_height(n));
  338. p.x = -outline_lw;
  339. p.y = -outline_ht / 2.0;
  340. vs[0] = p;
  341. p.x = outline_lw;
  342. vs[1] = p;
  343. p.y = outline_ht / 2.0;
  344. vs[2] = p;
  345. p.x = -outline_lw;
  346. vs[3] = p;
  347. }
  348. }
  349. else if (poly->sides >= 3) {
  350. isPoly = true;
  351. sides = poly->sides;
  352. const double penwidth = late_double(n, N_penwidth, 1.0, 0.0);
  353. // possibly use extra vertices representing the outline, i.e., the
  354. // outermost periphery with penwidth taken into account
  355. const size_t extra_peripheries = poly->peripheries >= 1 && penwidth > 0.0 ? 1 : 0;
  356. const size_t outline_periphery = poly->peripheries + extra_peripheries;
  357. const size_t vertices_offset = outline_periphery >= 1 ? (outline_periphery - 1) * sides : 0;
  358. verts = poly->vertices + vertices_offset;
  359. margin.x = pmargin->x;
  360. margin.y = pmargin->y;
  361. } else { /* ellipse */
  362. isPoly = false;
  363. sides = 8;
  364. }
  365. obs->pn = sides;
  366. obs->ps = gv_calloc(sides, sizeof(Ppoint_t));
  367. /* assuming polys are in CCW order, and pathplan needs CW */
  368. for (size_t j = 0; j < sides; j++) {
  369. double xmargin = 0.0, ymargin = 0.0;
  370. if (isPoly) {
  371. if (pmargin->doAdd) {
  372. if (sides == 4) {
  373. switch (j) {
  374. case 0 :
  375. xmargin = margin.x;
  376. ymargin = margin.y;
  377. break;
  378. case 1 :
  379. xmargin = -margin.x;
  380. ymargin = margin.y;
  381. break;
  382. case 2 :
  383. xmargin = -margin.x;
  384. ymargin = -margin.y;
  385. break;
  386. case 3 :
  387. xmargin = margin.x;
  388. ymargin = -margin.y;
  389. break;
  390. default:
  391. UNREACHABLE();
  392. }
  393. polyp.x = verts[j].x + xmargin;
  394. polyp.y = verts[j].y + ymargin;
  395. }
  396. else {
  397. const double h = hypot(verts[j].x, verts[j].y);
  398. polyp.x = verts[j].x * (1.0 + margin.x/h);
  399. polyp.y = verts[j].y * (1.0 + margin.y/h);
  400. }
  401. }
  402. else {
  403. polyp.x = verts[j].x * margin.x;
  404. polyp.y = verts[j].y * margin.y;
  405. }
  406. } else {
  407. const double width = INCH2PS(ND_outline_width(n));
  408. const double height = INCH2PS(ND_outline_height(n));
  409. margin = pmargin->doAdd ? (pointf) {pmargin->x, pmargin->y} : (pointf) {0.0, 0.0};
  410. const double ellipse_a = (width + margin.x) / 2.0;
  411. const double ellipse_b = (height + margin.y) / 2.0;
  412. polyp = circumscribed_polygon_corner_about_ellipse(ellipse_a, ellipse_b, j, sides);
  413. }
  414. obs->ps[sides - j - 1].x = polyp.x + ND_coord(n).x;
  415. obs->ps[sides - j - 1].y = polyp.y + ND_coord(n).y;
  416. }
  417. break;
  418. case SH_RECORD:
  419. fld = ND_shape_info(n);
  420. b = fld->b;
  421. obs = gv_alloc(sizeof(Ppoly_t));
  422. obs->pn = 4;
  423. obs->ps = gv_calloc(4, sizeof(Ppoint_t));
  424. /* CW order */
  425. pt = ND_coord(n);
  426. if (pmargin->doAdd) {
  427. obs->ps[0] = genPt(b.LL.x-pmargin->x, b.LL.y-pmargin->y, pt);
  428. obs->ps[1] = genPt(b.LL.x-pmargin->x, b.UR.y+pmargin->y, pt);
  429. obs->ps[2] = genPt(b.UR.x+pmargin->x, b.UR.y+pmargin->y, pt);
  430. obs->ps[3] = genPt(b.UR.x+pmargin->x, b.LL.y-pmargin->y, pt);
  431. }
  432. else {
  433. obs->ps[0] = recPt(b.LL.x, b.LL.y, pt, pmargin);
  434. obs->ps[1] = recPt(b.LL.x, b.UR.y, pt, pmargin);
  435. obs->ps[2] = recPt(b.UR.x, b.UR.y, pt, pmargin);
  436. obs->ps[3] = recPt(b.UR.x, b.LL.y, pt, pmargin);
  437. }
  438. break;
  439. case SH_EPSF:
  440. obs = gv_alloc(sizeof(Ppoly_t));
  441. obs->pn = 4;
  442. obs->ps = gv_calloc(4, sizeof(Ppoint_t));
  443. /* CW order */
  444. pt = ND_coord(n);
  445. if (pmargin->doAdd) {
  446. obs->ps[0] = genPt(-ND_lw(n)-pmargin->x, -ND_ht(n)-pmargin->y,pt);
  447. obs->ps[1] = genPt(-ND_lw(n)-pmargin->x, ND_ht(n)+pmargin->y,pt);
  448. obs->ps[2] = genPt(ND_rw(n)+pmargin->x, ND_ht(n)+pmargin->y,pt);
  449. obs->ps[3] = genPt(ND_rw(n)+pmargin->x, -ND_ht(n)-pmargin->y,pt);
  450. }
  451. else {
  452. obs->ps[0] = recPt(-ND_lw(n), -ND_ht(n), pt, pmargin);
  453. obs->ps[1] = recPt(-ND_lw(n), ND_ht(n), pt, pmargin);
  454. obs->ps[2] = recPt(ND_rw(n), ND_ht(n), pt, pmargin);
  455. obs->ps[3] = recPt(ND_rw(n), -ND_ht(n), pt, pmargin);
  456. }
  457. break;
  458. default:
  459. obs = NULL;
  460. break;
  461. }
  462. return obs;
  463. }
  464. /* getPath
  465. * Construct the shortest path from one endpoint of e to the other.
  466. * vconfig is a precomputed data structure to help in the computation.
  467. * If chkPts is true, the function finds the polygons, if any, containing
  468. * the endpoints and tells the shortest path computation to ignore them.
  469. * Assumes this info is set in ND_lim, usually from _spline_edges.
  470. * Returns the shortest path.
  471. */
  472. Ppolyline_t getPath(edge_t *e, vconfig_t *vconfig, bool chkPts) {
  473. Ppolyline_t line;
  474. int pp, qp;
  475. Ppoint_t p, q;
  476. p = add_pointf(ND_coord(agtail(e)), ED_tail_port(e).p);
  477. q = add_pointf(ND_coord(aghead(e)), ED_head_port(e).p);
  478. /* determine the polygons (if any) that contain the endpoints */
  479. pp = qp = POLYID_NONE;
  480. if (chkPts) {
  481. pp = ND_lim(agtail(e));
  482. qp = ND_lim(aghead(e));
  483. }
  484. Pobspath(vconfig, p, pp, q, qp, &line);
  485. return line;
  486. }
  487. static void makePolyline(edge_t * e) {
  488. Ppolyline_t spl, line = ED_path(e);
  489. make_polyline (line, &spl);
  490. if (Verbose > 1)
  491. fprintf(stderr, "polyline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
  492. clip_and_install(e, aghead(e), spl.ps, spl.pn, &sinfo);
  493. addEdgeLabels(e);
  494. }
  495. /* makeSpline:
  496. * Construct a spline connecting the endpoints of e, avoiding the npoly
  497. * obstacles obs.
  498. * The resultant spline is attached to the edge, the positions of any
  499. * edge labels are computed, and the graph's bounding box is recomputed.
  500. *
  501. * If chkPts is true, the function checks if one or both of the endpoints
  502. * is on or inside one of the obstacles and, if so, tells the shortest path
  503. * computation to ignore them.
  504. */
  505. void makeSpline(edge_t *e, Ppoly_t **obs, int npoly, bool chkPts) {
  506. Ppolyline_t line, spline;
  507. Pvector_t slopes[2];
  508. int i;
  509. int pp, qp;
  510. Ppoint_t p, q;
  511. Pedge_t *barriers;
  512. line = ED_path(e);
  513. p = line.ps[0];
  514. q = line.ps[line.pn - 1];
  515. /* determine the polygons (if any) that contain the endpoints */
  516. pp = qp = POLYID_NONE;
  517. if (chkPts)
  518. for (i = 0; i < npoly; i++) {
  519. if (pp == POLYID_NONE && in_poly(*obs[i], p))
  520. pp = i;
  521. if (qp == POLYID_NONE && in_poly(*obs[i], q))
  522. qp = i;
  523. }
  524. size_t n_barriers;
  525. make_barriers(obs, npoly, pp, qp, &barriers, &n_barriers);
  526. slopes[0].x = slopes[0].y = 0.0;
  527. slopes[1].x = slopes[1].y = 0.0;
  528. if (Proutespline(barriers, n_barriers, line, slopes, &spline) < 0) {
  529. agerrorf("makeSpline: failed to make spline edge (%s,%s)\n", agnameof(agtail(e)), agnameof(aghead(e)));
  530. return;
  531. }
  532. /* north why did you ever use int coords */
  533. if (Verbose > 1)
  534. fprintf(stderr, "spline %s %s\n", agnameof(agtail(e)), agnameof(aghead(e)));
  535. clip_and_install(e, aghead(e), spline.ps, spline.pn, &sinfo);
  536. free(barriers);
  537. addEdgeLabels(e);
  538. }
  539. /* True if either head or tail has a port on its boundary */
  540. #define BOUNDARY_PORT(e) ((ED_tail_port(e).side)||(ED_head_port(e).side))
  541. /* Basic default routine for creating edges.
  542. * If splines are requested, we construct the obstacles.
  543. * If not, or nodes overlap, the function reverts to line segments.
  544. * NOTE: intra-cluster edges are not constrained to
  545. * remain in the cluster's bounding box and, conversely, a cluster's box
  546. * is not altered to reflect intra-cluster edges.
  547. * If Nop > 1 and the spline exists, it is just copied.
  548. * NOTE: if edgetype = EDGETYPE_NONE, we shouldn't be here.
  549. */
  550. static int spline_edges_(graph_t *g, expand_t *pmargin, int edgetype) {
  551. node_t *n;
  552. edge_t *e;
  553. edge_t *e0;
  554. Ppoly_t **obs = 0;
  555. Ppoly_t *obp;
  556. int cnt, i = 0, npoly;
  557. vconfig_t *vconfig = 0;
  558. int useEdges = Nop > 1;
  559. int legal = 0;
  560. #ifdef HAVE_GTS
  561. router_t* rtr = 0;
  562. #endif
  563. /* build configuration */
  564. if (edgetype >= EDGETYPE_PLINE) {
  565. obs = gv_calloc(agnnodes(g), sizeof(Ppoly_t*));
  566. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  567. obp = makeObstacle(n, pmargin, edgetype == EDGETYPE_ORTHO);
  568. if (obp) {
  569. ND_lim(n) = i;
  570. obs[i++] = obp;
  571. }
  572. else
  573. ND_lim(n) = POLYID_NONE;
  574. }
  575. } else {
  576. obs = 0;
  577. }
  578. npoly = i;
  579. if (obs) {
  580. if ((legal = Plegal_arrangement(obs, npoly))) {
  581. if (edgetype != EDGETYPE_ORTHO) vconfig = Pobsopen(obs, npoly);
  582. }
  583. else {
  584. if (edgetype == EDGETYPE_ORTHO)
  585. agwarningf("the bounding boxes of some nodes touch - falling back to straight line edges\n");
  586. else
  587. agwarningf("some nodes with margin (%.02f,%.02f) touch - falling back to straight line edges\n", pmargin->x, pmargin->y);
  588. }
  589. }
  590. /* route edges */
  591. if (Verbose)
  592. fprintf(stderr, "Creating edges using %s\n",
  593. (legal && edgetype == EDGETYPE_ORTHO) ? "orthogonal lines" :
  594. (vconfig ? (edgetype == EDGETYPE_SPLINE ? "splines" : "polylines") :
  595. "line segments"));
  596. if (vconfig) {
  597. /* path-finding pass */
  598. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  599. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  600. ED_path(e) = getPath(e, vconfig, true);
  601. }
  602. }
  603. }
  604. #ifdef ORTHO
  605. else if (legal && edgetype == EDGETYPE_ORTHO) {
  606. orthoEdges(g, false);
  607. useEdges = 1;
  608. }
  609. #endif
  610. /* spline-drawing pass */
  611. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  612. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  613. /* fprintf (stderr, "%s -- %s %d\n", agnameof(agtail(e)), agnameof(aghead(e)), ED_count(e)); */
  614. node_t *head = aghead(e);
  615. if (useEdges && ED_spl(e)) {
  616. add_pointf(ND_coord(n), ED_tail_port(e).p);
  617. add_pointf(ND_coord(head), ED_head_port(e).p);
  618. addEdgeLabels(e);
  619. }
  620. else if (ED_count(e) == 0) continue; /* only do representative */
  621. else if (n == head) { /* self arc */
  622. makeSelfArcs(e, GD_nodesep(g->root));
  623. } else if (vconfig) { /* EDGETYPE_SPLINE or EDGETYPE_PLINE */
  624. #ifdef HAVE_GTS
  625. if (ED_count(e) > 1 || BOUNDARY_PORT(e)) {
  626. int fail = 0;
  627. if (ED_path(e).pn == 2 && !BOUNDARY_PORT(e))
  628. /* if a straight line can connect the ends */
  629. makeStraightEdge(g, e, edgetype, &sinfo);
  630. else {
  631. if (!rtr) rtr = mkRouter (obs, npoly);
  632. fail = makeMultiSpline(e, rtr, edgetype == EDGETYPE_PLINE);
  633. }
  634. if (!fail) continue;
  635. }
  636. /* We can probably remove this branch and just use
  637. * makeMultiSpline. It can also catch the makeStraightEdge
  638. * case. We could then eliminate all of the vconfig stuff.
  639. */
  640. #endif
  641. cnt = ED_count(e);
  642. if (Concentrate) cnt = 1; /* only do representative */
  643. e0 = e;
  644. for (i = 0; i < cnt; i++) {
  645. if (edgetype == EDGETYPE_SPLINE)
  646. makeSpline(e0, obs, npoly, true);
  647. else
  648. makePolyline(e0);
  649. e0 = ED_to_virt(e0);
  650. }
  651. } else {
  652. makeStraightEdge(g, e, edgetype, &sinfo);
  653. }
  654. }
  655. }
  656. #ifdef HAVE_GTS
  657. if (rtr)
  658. freeRouter (rtr);
  659. #endif
  660. if (vconfig)
  661. Pobsclose (vconfig);
  662. if (obs) {
  663. for (i=0; i < npoly; i++) {
  664. free (obs[i]->ps);
  665. free (obs[i]);
  666. }
  667. free (obs);
  668. }
  669. return 0;
  670. }
  671. /* splineEdges:
  672. * Main wrapper code for generating edges.
  673. * Sets desired separation.
  674. * Coalesces equivalent edges (edges * with the same endpoints).
  675. * It then calls the edge generating function, and marks the
  676. * spline phase complete.
  677. * Returns 0 on success.
  678. *
  679. * The edge function is given the graph, the separation to be added
  680. * around obstacles, and the type of edge. It must guarantee
  681. * that all bounding boxes are current; in particular, the bounding box of
  682. * g must reflect the addition of the edges.
  683. */
  684. int
  685. splineEdges(graph_t * g, int (*edgefn) (graph_t *, expand_t*, int),
  686. int edgetype)
  687. {
  688. node_t *n;
  689. edge_t *e;
  690. expand_t margin;
  691. Dt_t *map;
  692. margin = esepFactor (g);
  693. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  694. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  695. resolvePorts (e);
  696. }
  697. }
  698. /* find equivalent edges */
  699. map = dtopen(&edgeItemDisc, Dtoset);
  700. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  701. for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
  702. if (Nop > 1 && ED_spl(e)) {
  703. /* If Nop > 1 (use given edges) and e has a spline, it
  704. * should have its own equivalence class.
  705. */
  706. ED_count(e)++;
  707. } else {
  708. edge_t *leader = equivEdge(map, e);
  709. if (leader != e) {
  710. ED_count(leader)++;
  711. ED_to_virt(e) = ED_to_virt(leader);
  712. ED_to_virt(leader) = e;
  713. }
  714. }
  715. }
  716. }
  717. dtclose(map);
  718. if (edgefn(g, &margin, edgetype))
  719. return 1;
  720. State = GVSPLINES;
  721. return 0;
  722. }
  723. /* spline_edges1:
  724. * Construct edges using default algorithm and given splines value.
  725. * Return 0 on success.
  726. */
  727. int spline_edges1(graph_t * g, int edgetype)
  728. {
  729. return splineEdges(g, spline_edges_, edgetype);
  730. }
  731. /* spline_edges0:
  732. * Sets the graph's aspect ratio.
  733. * Check splines attribute and construct edges using default algorithm.
  734. * If the splines attribute is defined but equal to "", skip edge routing.
  735. *
  736. * Assumes u.bb for has been computed for g and all clusters
  737. * (not just top-level clusters), and that GD_bb(g).LL is at the origin.
  738. *
  739. * This last criterion is, I believe, mainly to simplify the code
  740. * in neato_set_aspect. It would be good to remove this constraint,
  741. * as this would allow nodes pinned on input to have the same coordinates
  742. * when output in dot or plain format.
  743. *
  744. */
  745. void spline_edges0(graph_t *g, bool set_aspect) {
  746. int et = EDGE_TYPE (g);
  747. if (set_aspect) neato_set_aspect(g);
  748. if (et == EDGETYPE_NONE) return;
  749. #ifndef ORTHO
  750. if (et == EDGETYPE_ORTHO) {
  751. agwarningf("Orthogonal edges not yet supported\n");
  752. et = EDGETYPE_PLINE;
  753. GD_flags(g->root) &= ~EDGETYPE_ORTHO;
  754. GD_flags(g->root) |= EDGETYPE_PLINE;
  755. }
  756. #endif
  757. spline_edges1(g, et);
  758. }
  759. static void
  760. shiftClusters (graph_t * g, pointf offset)
  761. {
  762. int i;
  763. for (i = 1; i <= GD_n_cluster(g); i++) {
  764. shiftClusters (GD_clust(g)[i], offset);
  765. }
  766. GD_bb(g).UR.x -= offset.x;
  767. GD_bb(g).UR.y -= offset.y;
  768. GD_bb(g).LL.x -= offset.x;
  769. GD_bb(g).LL.y -= offset.y;
  770. }
  771. /* spline_edges:
  772. * Compute bounding box, translate graph to origin,
  773. * then construct all edges.
  774. */
  775. void spline_edges(graph_t * g)
  776. {
  777. node_t *n;
  778. pointf offset;
  779. compute_bb(g);
  780. offset.x = PS2INCH(GD_bb(g).LL.x);
  781. offset.y = PS2INCH(GD_bb(g).LL.y);
  782. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  783. ND_pos(n)[0] -= offset.x;
  784. ND_pos(n)[1] -= offset.y;
  785. }
  786. shiftClusters (g, GD_bb(g).LL);
  787. spline_edges0(g, true);
  788. }
  789. /* scaleEdge:
  790. * Scale edge by given factor.
  791. * Assume ED_spl != NULL.
  792. */
  793. static void scaleEdge(edge_t * e, double xf, double yf)
  794. {
  795. pointf *pt;
  796. bezier *bez;
  797. pointf delh, delt;
  798. delh.x = POINTS_PER_INCH * (ND_pos(aghead(e))[0] * (xf - 1.0));
  799. delh.y = POINTS_PER_INCH * (ND_pos(aghead(e))[1] * (yf - 1.0));
  800. delt.x = POINTS_PER_INCH * (ND_pos(agtail(e))[0] * (xf - 1.0));
  801. delt.y = POINTS_PER_INCH * (ND_pos(agtail(e))[1] * (yf - 1.0));
  802. bez = ED_spl(e)->list;
  803. for (size_t i = 0; i < ED_spl(e)->size; i++) {
  804. pt = bez->list;
  805. for (size_t j = 0; j < bez->size; j++) {
  806. if (i == 0 && j == 0) {
  807. pt->x += delt.x;
  808. pt->y += delt.y;
  809. }
  810. else if (i == ED_spl(e)->size-1 && j == bez->size-1) {
  811. pt->x += delh.x;
  812. pt->y += delh.y;
  813. }
  814. else {
  815. pt->x *= xf;
  816. pt->y *= yf;
  817. }
  818. pt++;
  819. }
  820. if (bez->sflag) {
  821. bez->sp.x += delt.x;
  822. bez->sp.y += delt.y;
  823. }
  824. if (bez->eflag) {
  825. bez->ep.x += delh.x;
  826. bez->ep.y += delh.y;
  827. }
  828. bez++;
  829. }
  830. if (ED_label(e) && ED_label(e)->set) {
  831. ED_label(e)->pos.x *= xf;
  832. ED_label(e)->pos.y *= yf;
  833. }
  834. if (ED_head_label(e) && ED_head_label(e)->set) {
  835. ED_head_label(e)->pos.x += delh.x;
  836. ED_head_label(e)->pos.y += delh.y;
  837. }
  838. if (ED_tail_label(e) && ED_tail_label(e)->set) {
  839. ED_tail_label(e)->pos.x += delt.x;
  840. ED_tail_label(e)->pos.y += delt.y;
  841. }
  842. }
  843. /* scaleBB:
  844. * Scale bounding box of clusters of g by given factors.
  845. */
  846. static void scaleBB(graph_t * g, double xf, double yf)
  847. {
  848. int i;
  849. GD_bb(g).UR.x *= xf;
  850. GD_bb(g).UR.y *= yf;
  851. GD_bb(g).LL.x *= xf;
  852. GD_bb(g).LL.y *= yf;
  853. if (GD_label(g) && GD_label(g)->set) {
  854. GD_label(g)->pos.x *= xf;
  855. GD_label(g)->pos.y *= yf;
  856. }
  857. for (i = 1; i <= GD_n_cluster(g); i++)
  858. scaleBB(GD_clust(g)[i], xf, yf);
  859. }
  860. /* translateE:
  861. * Translate edge by offset.
  862. * Assume ED_spl(e) != NULL
  863. */
  864. static void translateE(edge_t * e, pointf offset)
  865. {
  866. pointf *pt;
  867. bezier *bez;
  868. bez = ED_spl(e)->list;
  869. for (size_t i = 0; i < ED_spl(e)->size; i++) {
  870. pt = bez->list;
  871. for (size_t j = 0; j < bez->size; j++) {
  872. pt->x -= offset.x;
  873. pt->y -= offset.y;
  874. pt++;
  875. }
  876. if (bez->sflag) {
  877. bez->sp.x -= offset.x;
  878. bez->sp.y -= offset.y;
  879. }
  880. if (bez->eflag) {
  881. bez->ep.x -= offset.x;
  882. bez->ep.y -= offset.y;
  883. }
  884. bez++;
  885. }
  886. if (ED_label(e) && ED_label(e)->set) {
  887. ED_label(e)->pos.x -= offset.x;
  888. ED_label(e)->pos.y -= offset.y;
  889. }
  890. if (ED_xlabel(e) && ED_xlabel(e)->set) {
  891. ED_xlabel(e)->pos.x -= offset.x;
  892. ED_xlabel(e)->pos.y -= offset.y;
  893. }
  894. if (ED_head_label(e) && ED_head_label(e)->set) {
  895. ED_head_label(e)->pos.x -= offset.x;
  896. ED_head_label(e)->pos.y -= offset.y;
  897. }
  898. if (ED_tail_label(e) && ED_tail_label(e)->set) {
  899. ED_tail_label(e)->pos.x -= offset.x;
  900. ED_tail_label(e)->pos.y -= offset.y;
  901. }
  902. }
  903. static void translateG(Agraph_t * g, pointf offset)
  904. {
  905. int i;
  906. GD_bb(g).UR.x -= offset.x;
  907. GD_bb(g).UR.y -= offset.y;
  908. GD_bb(g).LL.x -= offset.x;
  909. GD_bb(g).LL.y -= offset.y;
  910. if (GD_label(g) && GD_label(g)->set) {
  911. GD_label(g)->pos.x -= offset.x;
  912. GD_label(g)->pos.y -= offset.y;
  913. }
  914. for (i = 1; i <= GD_n_cluster(g); i++)
  915. translateG(GD_clust(g)[i], offset);
  916. }
  917. void neato_translate(Agraph_t * g)
  918. {
  919. node_t *n;
  920. edge_t *e;
  921. pointf offset;
  922. pointf ll;
  923. ll = GD_bb(g).LL;
  924. offset.x = PS2INCH(ll.x);
  925. offset.y = PS2INCH(ll.y);
  926. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  927. ND_pos(n)[0] -= offset.x;
  928. ND_pos(n)[1] -= offset.y;
  929. if (ND_xlabel(n) && ND_xlabel(n)->set) {
  930. ND_xlabel(n)->pos.x -= ll.x;
  931. ND_xlabel(n)->pos.y -= ll.y;
  932. }
  933. }
  934. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  935. for (e = agfstout(g, n); e; e = agnxtout(g, e))
  936. if (ED_spl(e))
  937. translateE(e, ll);
  938. }
  939. translateG(g, ll);
  940. }
  941. /* _neato_set_aspect;
  942. * Assume all bounding boxes are correct.
  943. * Return false if no transform is performed. This includes
  944. * the possibility that a translation was done.
  945. */
  946. static bool _neato_set_aspect(graph_t * g)
  947. {
  948. double xf, yf, actual, desired;
  949. node_t *n;
  950. bool translated = false;
  951. if (g->root != g)
  952. return false;
  953. if (GD_drawing(g)->ratio_kind) {
  954. if (GD_bb(g).LL.x || GD_bb(g).LL.y) {
  955. translated = true;
  956. neato_translate (g);
  957. }
  958. /* normalize */
  959. if (GD_flip(g)) {
  960. GD_bb(g).UR = exch_xyf(GD_bb(g).UR);
  961. }
  962. if (GD_drawing(g)->ratio_kind == R_FILL) {
  963. /* fill is weird because both X and Y can stretch */
  964. if (GD_drawing(g)->size.x <= 0)
  965. return translated;
  966. xf = GD_drawing(g)->size.x / GD_bb(g).UR.x;
  967. yf = GD_drawing(g)->size.y / GD_bb(g).UR.y;
  968. /* handle case where one or more dimensions is too big */
  969. if (xf < 1.0 || yf < 1.0) {
  970. if (xf < yf) {
  971. yf /= xf;
  972. xf = 1.0;
  973. } else {
  974. xf /= yf;
  975. yf = 1.0;
  976. }
  977. }
  978. } else if (GD_drawing(g)->ratio_kind == R_EXPAND) {
  979. if (GD_drawing(g)->size.x <= 0)
  980. return translated;
  981. xf = GD_drawing(g)->size.x / GD_bb(g).UR.x;
  982. yf = GD_drawing(g)->size.y / GD_bb(g).UR.y;
  983. if (xf > 1.0 && yf > 1.0) {
  984. double scale = fmin(xf, yf);
  985. xf = yf = scale;
  986. } else
  987. return translated;
  988. } else if (GD_drawing(g)->ratio_kind == R_VALUE) {
  989. desired = GD_drawing(g)->ratio;
  990. actual = GD_bb(g).UR.y / GD_bb(g).UR.x;
  991. if (actual < desired) {
  992. yf = desired / actual;
  993. xf = 1.0;
  994. } else {
  995. xf = actual / desired;
  996. yf = 1.0;
  997. }
  998. } else
  999. return translated;
  1000. if (GD_flip(g)) {
  1001. double t = xf;
  1002. xf = yf;
  1003. yf = t;
  1004. }
  1005. if (Nop > 1) {
  1006. edge_t *e;
  1007. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  1008. for (e = agfstout(g, n); e; e = agnxtout(g, e))
  1009. if (ED_spl(e))
  1010. scaleEdge(e, xf, yf);
  1011. }
  1012. }
  1013. /* Not relying on neato_nlist here allows us not to have to
  1014. * allocate it in the root graph and the connected components.
  1015. */
  1016. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  1017. ND_pos(n)[0] *= xf;
  1018. ND_pos(n)[1] *= yf;
  1019. }
  1020. scaleBB(g, xf, yf);
  1021. return true;
  1022. }
  1023. else
  1024. return false;
  1025. }
  1026. /* neato_set_aspect:
  1027. * Sets aspect ratio if necessary; real work done in _neato_set_aspect;
  1028. * This also copies the internal layout coordinates (ND_pos) to the
  1029. * external ones (ND_coord).
  1030. *
  1031. * Return true if some node moved.
  1032. */
  1033. bool neato_set_aspect(graph_t * g)
  1034. {
  1035. node_t *n;
  1036. bool moved = false;
  1037. /* setting aspect ratio only makes sense on root graph */
  1038. moved = _neato_set_aspect(g);
  1039. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  1040. ND_coord(n).x = POINTS_PER_INCH * ND_pos(n)[0];
  1041. ND_coord(n).y = POINTS_PER_INCH * ND_pos(n)[1];
  1042. }
  1043. return moved;
  1044. }