maze.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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 "config.h"
  11. #define DEBUG
  12. #include <float.h>
  13. #include <math.h>
  14. #include <stdbool.h>
  15. #include <stddef.h>
  16. #include <ortho/maze.h>
  17. #include <ortho/partition.h>
  18. #include <ortho/trap.h>
  19. #include <common/arith.h>
  20. #include <util/alloc.h>
  21. #define MARGIN 36;
  22. #ifdef DEBUG
  23. char* pre = "%!PS-Adobe-2.0\n\
  24. /node {\n\
  25. /Y exch def\n\
  26. /X exch def\n\
  27. /y exch def\n\
  28. /x exch def\n\
  29. newpath\n\
  30. x y moveto\n\
  31. x Y lineto\n\
  32. X Y lineto\n\
  33. X y lineto\n\
  34. closepath fill\n\
  35. } def\n\
  36. /cell {\n\
  37. /Y exch def\n\
  38. /X exch def\n\
  39. /y exch def\n\
  40. /x exch def\n\
  41. newpath\n\
  42. x y moveto\n\
  43. x Y lineto\n\
  44. X Y lineto\n\
  45. X y lineto\n\
  46. closepath stroke\n\
  47. } def\n";
  48. char* post = "showpage\n";
  49. /// @brief dumps @ref maze::gcells and @ref maze::cells via rects to PostScript
  50. static void
  51. psdump(cell *gcells, int n_gcells, boxf BB, boxf *rects, size_t nrect) {
  52. boxf bb;
  53. boxf absbb = {.LL = {.y = 10.0, .x = 10.0}};
  54. absbb.UR.x = absbb.LL.x + BB.UR.x - BB.LL.x;
  55. absbb.UR.y = absbb.LL.y + BB.UR.y - BB.LL.y;
  56. fputs (pre, stderr);
  57. fprintf(stderr, "%%%%Page: 1 1\n%%%%PageBoundingBox: %.0f %.0f %.0f %.0f\n",
  58. absbb.LL.x, absbb.LL.y, absbb.UR.x, absbb.UR.y);
  59. fprintf (stderr, "%f %f translate\n", 10-BB.LL.x, 10-BB.LL.y);
  60. fputs ("0 0 1 setrgbcolor\n", stderr);
  61. for (int i = 0; i < n_gcells; i++) {
  62. bb = gcells[i].bb;
  63. fprintf (stderr, "%f %f %f %f node\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
  64. }
  65. fputs ("0 0 0 setrgbcolor\n", stderr);
  66. for (size_t i = 0; i < nrect; i++) {
  67. bb = rects[i];
  68. fprintf (stderr, "%f %f %f %f cell\n", bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
  69. }
  70. fputs ("1 0 0 setrgbcolor\n", stderr);
  71. fprintf (stderr, "%f %f %f %f cell\n", BB.LL.x, BB.LL.y, BB.UR.x, BB.UR.y);
  72. fputs (post, stderr);
  73. }
  74. #endif
  75. /// compares points by X and then by Y
  76. static int vcmpid(void *k1, void *k2) {
  77. const pointf *key1 = k1;
  78. const pointf *key2 = k2;
  79. int dx = dfp_cmp(key1->x, key2->x);
  80. if (dx != 0)
  81. return dx;
  82. return dfp_cmp(key1->y, key2->y);
  83. }
  84. /// compares points by Y and then by X
  85. static int hcmpid(void *k1, void *k2) {
  86. const pointf *key1 = k1;
  87. const pointf *key2 = k2;
  88. int dy = dfp_cmp(key1->y, key2->y);
  89. if (dy != 0)
  90. return dy;
  91. return dfp_cmp(key1->x, key2->x);
  92. }
  93. typedef struct {
  94. snode* np;
  95. pointf p;
  96. Dtlink_t link;
  97. } snodeitem;
  98. static Dtdisc_t vdictDisc = {
  99. offsetof(snodeitem,p),
  100. sizeof(pointf),
  101. offsetof(snodeitem,link),
  102. 0,
  103. 0,
  104. vcmpid,
  105. };
  106. static Dtdisc_t hdictDisc = {
  107. offsetof(snodeitem,p),
  108. sizeof(pointf),
  109. offsetof(snodeitem,link),
  110. 0,
  111. 0,
  112. hcmpid,
  113. };
  114. #define delta 1 /* weight of length */
  115. #define mu 500 /* weight of bends */
  116. #define BEND(g,e) ((g->nodes + e->v1)->isVert != (g->nodes + e->v2)->isVert)
  117. #define HORZ(g,e) ((g->nodes + e->v1)->isVert)
  118. #define BIG 16384
  119. #define CHANSZ(w) (((w)-3)/2)
  120. #define IS_SMALL(v) (CHANSZ(v) < 2)
  121. /**
  122. * @brief updates single @ref sedge::weight
  123. *
  124. * At present, we use a step function. When a bound is reached, the weight
  125. * becomes huge. We might consider bumping up the weight more gradually, the
  126. * thinner the channel, the faster the weight rises.
  127. */
  128. static void updateWt(sedge *ep, double sz) {
  129. ep->cnt++;
  130. if (ep->cnt > sz) {
  131. ep->cnt = 0;
  132. ep->weight += BIG;
  133. }
  134. }
  135. /**
  136. * @brief updates @ref sedge::weight of cell edges
  137. *
  138. * Iterate over edges in a cell, adjust weights as necessary.
  139. * It always updates the bent edges belonging to a cell.
  140. * A horizontal/vertical edge is updated only if the edge traversed
  141. * is bent, or if it is the traversed edge.
  142. */
  143. void
  144. updateWts (sgraph* g, cell* cp, sedge* ep)
  145. {
  146. int i;
  147. sedge* e;
  148. int isBend = BEND(g,ep);
  149. const double hsz = CHANSZ(cp->bb.UR.y - cp->bb.LL.y);
  150. const double vsz = CHANSZ(cp->bb.UR.x - cp->bb.LL.x);
  151. const double minsz = fmin(hsz, vsz);
  152. /* Bend edges are added first */
  153. for (i = 0; i < cp->nedges; i++) {
  154. e = cp->edges[i];
  155. if (!BEND(g,e)) break;
  156. updateWt (e, minsz);
  157. }
  158. for (; i < cp->nedges; i++) {
  159. e = cp->edges[i];
  160. if (isBend || e == ep) updateWt (e, HORZ(g,e)?hsz:vsz);
  161. }
  162. }
  163. /**
  164. * cp corresponds to a real node. If it is small, its associated cells should
  165. * be marked as usable.
  166. */
  167. static void
  168. markSmall (cell* cp)
  169. {
  170. int i;
  171. snode* onp;
  172. cell* ocp;
  173. if (IS_SMALL(cp->bb.UR.y-cp->bb.LL.y)) {
  174. for (i = 0; i < cp->nsides; i++) {
  175. onp = cp->sides[i];
  176. if (!onp->isVert) continue;
  177. if (onp->cells[0] == cp) { /* onp on the right of cp */
  178. ocp = onp->cells[1];
  179. ocp->flags |= MZ_SMALLV;
  180. while ((onp = ocp->sides[M_RIGHT]) && !IsNode(onp->cells[1])) {
  181. ocp = onp->cells[1];
  182. ocp->flags |= MZ_SMALLV;
  183. }
  184. }
  185. else { /* onp on the left of cp */
  186. ocp = onp->cells[0];
  187. ocp->flags |= MZ_SMALLV;
  188. while ((onp = ocp->sides[M_LEFT]) && !IsNode(onp->cells[0])) {
  189. ocp = onp->cells[0];
  190. ocp->flags |= MZ_SMALLV;
  191. }
  192. }
  193. }
  194. }
  195. if (IS_SMALL(cp->bb.UR.x-cp->bb.LL.x)) {
  196. for (i = 0; i < cp->nsides; i++) {
  197. onp = cp->sides[i];
  198. if (onp->isVert) continue;
  199. if (onp->cells[0] == cp) { /* onp on the top of cp */
  200. ocp = onp->cells[1];
  201. ocp->flags |= MZ_SMALLH;
  202. while ((onp = ocp->sides[M_TOP]) && !IsNode(onp->cells[1])) {
  203. ocp = onp->cells[1];
  204. ocp->flags |= MZ_SMALLH;
  205. }
  206. }
  207. else { /* onp on the bottom of cp */
  208. ocp = onp->cells[0];
  209. ocp->flags |= MZ_SMALLH;
  210. while ((onp = ocp->sides[M_BOTTOM]) && !IsNode(onp->cells[0])) {
  211. ocp = onp->cells[0];
  212. ocp->flags |= MZ_SMALLH;
  213. }
  214. }
  215. }
  216. }
  217. }
  218. /// fills @ref cell::sides and @ref sgraph::edges
  219. static void
  220. createSEdges (cell* cp, sgraph* g)
  221. {
  222. boxf bb = cp->bb;
  223. double hwt = delta*(bb.UR.x-bb.LL.x);
  224. double vwt = delta*(bb.UR.y-bb.LL.y);
  225. double wt = (hwt + vwt)/2.0 + mu;
  226. /* We automatically make small channels have high cost to guide routes to
  227. * more spacious channels.
  228. */
  229. if (IS_SMALL(bb.UR.y-bb.LL.y) && !IsSmallV(cp)) {
  230. hwt = BIG;
  231. wt = BIG;
  232. }
  233. if (IS_SMALL(bb.UR.x-bb.LL.x) && !IsSmallH(cp)) {
  234. vwt = BIG;
  235. wt = BIG;
  236. }
  237. if (cp->sides[M_LEFT] && cp->sides[M_TOP])
  238. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_LEFT], cp->sides[M_TOP], wt);
  239. if (cp->sides[M_TOP] && cp->sides[M_RIGHT])
  240. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_TOP], cp->sides[M_RIGHT], wt);
  241. if (cp->sides[M_LEFT] && cp->sides[M_BOTTOM])
  242. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_LEFT], cp->sides[M_BOTTOM], wt);
  243. if (cp->sides[M_BOTTOM] && cp->sides[M_RIGHT])
  244. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_BOTTOM], cp->sides[M_RIGHT], wt);
  245. if (cp->sides[M_TOP] && cp->sides[M_BOTTOM])
  246. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_TOP], cp->sides[M_BOTTOM], vwt);
  247. if (cp->sides[M_LEFT] && cp->sides[M_RIGHT])
  248. cp->edges[cp->nedges++] = createSEdge (g, cp->sides[M_LEFT], cp->sides[M_RIGHT], hwt);
  249. }
  250. /// finds a @ref snode by point or creates it
  251. static snode*
  252. findSVert (sgraph* g, Dt_t* cdt, pointf p, snodeitem* ditems, bool isVert)
  253. {
  254. snodeitem* n = dtmatch (cdt, &p);
  255. if (!n) {
  256. snode* np = createSNode (g);
  257. assert(ditems);
  258. n = ditems + np->index;
  259. n->p = p;
  260. n->np = np;
  261. np->isVert = isVert;
  262. dtinsert (cdt, n);
  263. }
  264. return n->np;
  265. }
  266. static void
  267. chkSgraph (sgraph* g)
  268. {
  269. int i;
  270. snode* np;
  271. for (i = 0; i < g->nnodes; i++) {
  272. np = g->nodes+i;
  273. if (!np->cells[0]) fprintf (stderr, "failed at node %d[0]\n", i);
  274. assert (np->cells[0]);
  275. if (!np->cells[1]) fprintf (stderr, "failed at node %d[1]\n", i);
  276. assert (np->cells[1]);
  277. }
  278. }
  279. /**
  280. * @brief creates and fills @ref sgraph for @ref maze
  281. *
  282. * Subroutines: @ref createSGraph, @ref findSVert with @ref createSNode,
  283. * @ref initSEdges and @ref chkSgraph
  284. */
  285. static sgraph*
  286. mkMazeGraph (maze* mp, boxf bb)
  287. {
  288. int nsides, i, maxdeg;
  289. int bound = 4*mp->ncells;
  290. sgraph* g = createSGraph (bound + 2);
  291. Dt_t* vdict = dtopen(&vdictDisc,Dtoset);
  292. Dt_t* hdict = dtopen(&hdictDisc,Dtoset);
  293. snodeitem* ditems = gv_calloc(bound, sizeof(snodeitem));
  294. snode** sides;
  295. /* For each cell, create if necessary and attach a node in search
  296. * corresponding to each internal face. The node also gets
  297. * a pointer to the cell.
  298. */
  299. sides = gv_calloc(4 * mp->ncells, sizeof(snode*));
  300. for (i = 0; i < mp->ncells; i++) {
  301. cell* cp = mp->cells+i;
  302. snode* np;
  303. pointf pt;
  304. cp->nsides = 4;
  305. cp->sides = sides + 4*i;
  306. if (cp->bb.UR.x < bb.UR.x) {
  307. pt.x = cp->bb.UR.x;
  308. pt.y = cp->bb.LL.y;
  309. np = findSVert(g, vdict, pt, ditems, true);
  310. np->cells[0] = cp;
  311. cp->sides[M_RIGHT] = np;
  312. }
  313. if (cp->bb.UR.y < bb.UR.y) {
  314. pt.x = cp->bb.LL.x;
  315. pt.y = cp->bb.UR.y;
  316. np = findSVert(g, hdict, pt, ditems, false);
  317. np->cells[0] = cp;
  318. cp->sides[M_TOP] = np;
  319. }
  320. if (cp->bb.LL.x > bb.LL.x) {
  321. np = findSVert(g, vdict, cp->bb.LL, ditems, true);
  322. np->cells[1] = cp;
  323. cp->sides[M_LEFT] = np;
  324. }
  325. if (cp->bb.LL.y > bb.LL.y) {
  326. np = findSVert(g, hdict, cp->bb.LL, ditems, false);
  327. np->cells[1] = cp;
  328. cp->sides[M_BOTTOM] = np;
  329. }
  330. }
  331. /* For each gcell, corresponding to a node in the input graph,
  332. * connect it to its corresponding search nodes.
  333. */
  334. maxdeg = 0;
  335. sides = gv_calloc(g->nnodes, sizeof(snode*));
  336. nsides = 0;
  337. for (i = 0; i < mp->ngcells; i++) {
  338. cell* cp = mp->gcells+i;
  339. pointf pt;
  340. snodeitem* np;
  341. cp->sides = sides+nsides;
  342. pt = cp->bb.LL;
  343. np = dtmatch (hdict, &pt);
  344. for (; np && np->p.x < cp->bb.UR.x; np = dtnext (hdict, np)) {
  345. cp->sides[cp->nsides++] = np->np;
  346. np->np->cells[1] = cp;
  347. }
  348. np = dtmatch (vdict, &pt);
  349. for (; np && np->p.y < cp->bb.UR.y; np = dtnext (vdict, np)) {
  350. cp->sides[cp->nsides++] = np->np;
  351. np->np->cells[1] = cp;
  352. }
  353. pt.y = cp->bb.UR.y;
  354. np = dtmatch (hdict, &pt);
  355. for (; np && np->p.x < cp->bb.UR.x; np = dtnext (hdict, np)) {
  356. cp->sides[cp->nsides++] = np->np;
  357. np->np->cells[0] = cp;
  358. }
  359. pt.x = cp->bb.UR.x;
  360. pt.y = cp->bb.LL.y;
  361. np = dtmatch (vdict, &pt);
  362. for (; np && np->p.y < cp->bb.UR.y; np = dtnext (vdict, np)) {
  363. cp->sides[cp->nsides++] = np->np;
  364. np->np->cells[0] = cp;
  365. }
  366. nsides += cp->nsides;
  367. if (cp->nsides > maxdeg) maxdeg = cp->nsides;
  368. }
  369. /* Mark cells that are small because of a small node, not because of the close
  370. * alignment of two rectangles.
  371. */
  372. for (i = 0; i < mp->ngcells; i++) {
  373. cell* cp = mp->gcells+i;
  374. markSmall (cp);
  375. }
  376. /* Set index of two dummy nodes used for real nodes */
  377. g->nodes[g->nnodes].index = g->nnodes;
  378. g->nodes[g->nnodes+1].index = g->nnodes+1;
  379. /* create edges
  380. * For each ordinary cell, there can be at most 6 edges.
  381. * At most 2 gcells will be used at a time, and each of these
  382. * can have at most degree maxdeg.
  383. */
  384. initSEdges (g, maxdeg);
  385. for (i = 0; i < mp->ncells; i++) {
  386. cell* cp = mp->cells+i;
  387. createSEdges (cp, g);
  388. }
  389. /* tidy up memory */
  390. dtclose (vdict);
  391. dtclose (hdict);
  392. free (ditems);
  393. chkSgraph (g);
  394. /* save core graph state */
  395. gsave(g);
  396. return g;
  397. }
  398. /// creates @ref maze and fills @ref maze::gcells and @ref maze::cells. A subroutine of @ref orthoEdges.
  399. maze *mkMaze(graph_t *g) {
  400. node_t* n;
  401. maze* mp = gv_alloc(sizeof(maze));
  402. boxf* rects;
  403. cell* cp;
  404. double w2, h2;
  405. boxf bb;
  406. mp->ngcells = agnnodes(g);
  407. cp = mp->gcells = gv_calloc(mp->ngcells, sizeof(cell));
  408. boxf BB = {.LL = {.x = DBL_MAX, .y = DBL_MAX},
  409. .UR = {.x = -DBL_MAX, .y = -DBL_MAX}};
  410. for (n = agfstnode (g); n; n = agnxtnode(g,n)) {
  411. w2 = fmax(1, ND_xsize(n) / 2.0);
  412. h2 = fmax(1, ND_ysize(n) / 2.0);
  413. bb.LL.x = ND_coord(n).x - w2;
  414. bb.UR.x = ND_coord(n).x + w2;
  415. bb.LL.y = ND_coord(n).y - h2;
  416. bb.UR.y = ND_coord(n).y + h2;
  417. BB.LL.x = fmin(BB.LL.x, bb.LL.x);
  418. BB.LL.y = fmin(BB.LL.y, bb.LL.y);
  419. BB.UR.x = fmax(BB.UR.x, bb.UR.x);
  420. BB.UR.y = fmax(BB.UR.y, bb.UR.y);
  421. cp->bb = bb;
  422. cp->flags |= MZ_ISNODE;
  423. ND_alg(n) = cp;
  424. cp++;
  425. }
  426. BB.LL.x -= MARGIN;
  427. BB.LL.y -= MARGIN;
  428. BB.UR.x += MARGIN;
  429. BB.UR.y += MARGIN;
  430. size_t nrect;
  431. rects = partition (mp->gcells, mp->ngcells, &nrect, BB);
  432. #ifdef DEBUG
  433. if (odb_flags & ODB_MAZE) psdump (mp->gcells, mp->ngcells, BB, rects, nrect);
  434. #endif
  435. mp->cells = gv_calloc(nrect, sizeof(cell));
  436. mp->ncells = nrect;
  437. for (size_t i = 0; i < nrect; i++) {
  438. mp->cells[i].bb = rects[i];
  439. }
  440. free (rects);
  441. mp->sg = mkMazeGraph (mp, BB);
  442. return mp;
  443. }
  444. void freeMaze (maze* mp)
  445. {
  446. free (mp->cells[0].sides);
  447. free (mp->gcells[0].sides);
  448. free (mp->cells);
  449. free (mp->gcells);
  450. freeSGraph (mp->sg);
  451. dtclose (mp->hchans);
  452. dtclose (mp->vchans);
  453. free (mp);
  454. }