penrose.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. /*
  2. * Generate Penrose tilings via combinatorial coordinates.
  3. *
  4. * For general explanation of the algorithm:
  5. * https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/aperiodic-tilings/
  6. *
  7. * I use exactly the same indexing system here that's described in the
  8. * article. For the P2 tiling, acute isosceles triangles (half-kites)
  9. * are assigned letters A,B, and obtuse ones (half-darts) U,V; for P3,
  10. * acute triangles (half of a thin rhomb) are C,D and obtuse ones
  11. * (half a thick rhomb) are X,Y. Edges of all triangles are indexed
  12. * anticlockwise around the triangle, with 0 being the base and 1,2
  13. * being the two equal legs.
  14. */
  15. #include <assert.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18. #include "puzzles.h"
  19. #include "penrose.h"
  20. #include "penrose-internal.h"
  21. #include "tree234.h"
  22. bool penrose_valid_letter(char c, int which)
  23. {
  24. switch (c) {
  25. case 'A': case 'B': case 'U': case 'V':
  26. return which == PENROSE_P2;
  27. case 'C': case 'D': case 'X': case 'Y':
  28. return which == PENROSE_P3;
  29. default:
  30. return false;
  31. }
  32. }
  33. /*
  34. * Result of attempting a transition within the coordinate system.
  35. * INTERNAL means we've moved to a different child of the same parent,
  36. * so the 'internal' substructure gives the type of the new triangle
  37. * and which edge of it we came in through; EXTERNAL means we've moved
  38. * out of the parent entirely, and the 'external' substructure tells
  39. * us which edge of the parent triangle we left by, and if it's
  40. * divided in two, which end of that edge (-1 for the left end or +1
  41. * for the right end). If the parent edge is undivided, end == 0.
  42. *
  43. * The type FAIL _shouldn't_ ever come up! It occurs if you try to
  44. * compute an incoming transition with an illegal value of 'end' (i.e.
  45. * having the wrong idea of whether the edge is divided), or if you
  46. * refer to a child triangle type that doesn't exist in that parent.
  47. * If it ever happens in the production code then an assertion will
  48. * fail. But it might be useful to other users of the same code.
  49. */
  50. typedef struct TransitionResult {
  51. enum { INTERNAL, EXTERNAL, FAIL } type;
  52. union {
  53. struct {
  54. char new_child;
  55. unsigned char new_edge;
  56. } internal;
  57. struct {
  58. unsigned char parent_edge;
  59. signed char end;
  60. } external;
  61. } u;
  62. } TransitionResult;
  63. /* Construction function to make an INTERNAL-type TransitionResult */
  64. static inline TransitionResult internal(char new_child, unsigned new_edge)
  65. {
  66. TransitionResult tr;
  67. tr.type = INTERNAL;
  68. tr.u.internal.new_child = new_child;
  69. tr.u.internal.new_edge = new_edge;
  70. return tr;
  71. }
  72. /* Construction function to make an EXTERNAL-type TransitionResult */
  73. static inline TransitionResult external(unsigned parent_edge, int end)
  74. {
  75. TransitionResult tr;
  76. tr.type = EXTERNAL;
  77. tr.u.external.parent_edge = parent_edge;
  78. tr.u.external.end = end;
  79. return tr;
  80. }
  81. /* Construction function to make a FAIL-type TransitionResult */
  82. static inline TransitionResult fail(void)
  83. {
  84. TransitionResult tr;
  85. tr.type = FAIL;
  86. return tr;
  87. }
  88. /*
  89. * Compute a transition out of a triangle. Can return either INTERNAL
  90. * or EXTERNAL types (or FAIL if it gets invalid data).
  91. */
  92. static TransitionResult transition(char parent, char child, unsigned edge)
  93. {
  94. switch (parent) {
  95. case 'A':
  96. switch (child) {
  97. case 'A':
  98. switch (edge) {
  99. case 0: return external(2, -1);
  100. case 1: return external(0, 0);
  101. case 2: return internal('B', 1);
  102. }
  103. case 'B':
  104. switch (edge) {
  105. case 0: return internal('U', 1);
  106. case 1: return internal('A', 2);
  107. case 2: return external(1, +1);
  108. }
  109. case 'U':
  110. switch (edge) {
  111. case 0: return external(2, +1);
  112. case 1: return internal('B', 0);
  113. case 2: return external(1, -1);
  114. }
  115. default:
  116. return fail();
  117. }
  118. case 'B':
  119. switch (child) {
  120. case 'A':
  121. switch (edge) {
  122. case 0: return internal('V', 2);
  123. case 1: return external(2, -1);
  124. case 2: return internal('B', 1);
  125. }
  126. case 'B':
  127. switch (edge) {
  128. case 0: return external(1, +1);
  129. case 1: return internal('A', 2);
  130. case 2: return external(0, 0);
  131. }
  132. case 'V':
  133. switch (edge) {
  134. case 0: return external(1, -1);
  135. case 1: return external(2, +1);
  136. case 2: return internal('A', 0);
  137. }
  138. default:
  139. return fail();
  140. }
  141. case 'U':
  142. switch (child) {
  143. case 'B':
  144. switch (edge) {
  145. case 0: return internal('U', 1);
  146. case 1: return external(2, 0);
  147. case 2: return external(0, +1);
  148. }
  149. case 'U':
  150. switch (edge) {
  151. case 0: return external(1, 0);
  152. case 1: return internal('B', 0);
  153. case 2: return external(0, -1);
  154. }
  155. default:
  156. return fail();
  157. }
  158. case 'V':
  159. switch (child) {
  160. case 'A':
  161. switch (edge) {
  162. case 0: return internal('V', 2);
  163. case 1: return external(0, -1);
  164. case 2: return external(1, 0);
  165. }
  166. case 'V':
  167. switch (edge) {
  168. case 0: return external(2, 0);
  169. case 1: return external(0, +1);
  170. case 2: return internal('A', 0);
  171. }
  172. default:
  173. return fail();
  174. }
  175. case 'C':
  176. switch (child) {
  177. case 'C':
  178. switch (edge) {
  179. case 0: return external(1, +1);
  180. case 1: return internal('Y', 1);
  181. case 2: return external(0, 0);
  182. }
  183. case 'Y':
  184. switch (edge) {
  185. case 0: return external(2, 0);
  186. case 1: return internal('C', 1);
  187. case 2: return external(1, -1);
  188. }
  189. default:
  190. return fail();
  191. }
  192. case 'D':
  193. switch (child) {
  194. case 'D':
  195. switch (edge) {
  196. case 0: return external(2, -1);
  197. case 1: return external(0, 0);
  198. case 2: return internal('X', 2);
  199. }
  200. case 'X':
  201. switch (edge) {
  202. case 0: return external(1, 0);
  203. case 1: return external(2, +1);
  204. case 2: return internal('D', 2);
  205. }
  206. default:
  207. return fail();
  208. }
  209. case 'X':
  210. switch (child) {
  211. case 'C':
  212. switch (edge) {
  213. case 0: return external(2, +1);
  214. case 1: return internal('Y', 1);
  215. case 2: return internal('X', 1);
  216. }
  217. case 'X':
  218. switch (edge) {
  219. case 0: return external(1, 0);
  220. case 1: return internal('C', 2);
  221. case 2: return external(0, -1);
  222. }
  223. case 'Y':
  224. switch (edge) {
  225. case 0: return external(0, +1);
  226. case 1: return internal('C', 1);
  227. case 2: return external(2, -1);
  228. }
  229. default:
  230. return fail();
  231. }
  232. case 'Y':
  233. switch (child) {
  234. case 'D':
  235. switch (edge) {
  236. case 0: return external(1, -1);
  237. case 1: return internal('Y', 2);
  238. case 2: return internal('X', 2);
  239. }
  240. case 'X':
  241. switch (edge) {
  242. case 0: return external(0, -1);
  243. case 1: return external(1, +1);
  244. case 2: return internal('D', 2);
  245. }
  246. case 'Y':
  247. switch (edge) {
  248. case 0: return external(2, 0);
  249. case 1: return external(0, +1);
  250. case 2: return internal('D', 1);
  251. }
  252. default:
  253. return fail();
  254. }
  255. default:
  256. return fail();
  257. }
  258. }
  259. /*
  260. * Compute a transition into a parent triangle, after the above
  261. * function reported an EXTERNAL transition out of a neighbouring
  262. * parent and we had to recurse. Because we're coming inwards, this
  263. * should always return an INTERNAL TransitionResult (or FAIL if it
  264. * gets invalid data).
  265. */
  266. static TransitionResult transition_in(char parent, unsigned edge, int end)
  267. {
  268. #define EDGEEND(edge, end) (3 * (edge) + 1 + (end))
  269. switch (parent) {
  270. case 'A':
  271. switch (EDGEEND(edge, end)) {
  272. case EDGEEND(0, 0): return internal('A', 1);
  273. case EDGEEND(1, -1): return internal('B', 2);
  274. case EDGEEND(1, +1): return internal('U', 2);
  275. case EDGEEND(2, -1): return internal('U', 0);
  276. case EDGEEND(2, +1): return internal('A', 0);
  277. default:
  278. return fail();
  279. }
  280. case 'B':
  281. switch (EDGEEND(edge, end)) {
  282. case EDGEEND(0, 0): return internal('B', 2);
  283. case EDGEEND(1, -1): return internal('B', 0);
  284. case EDGEEND(1, +1): return internal('V', 0);
  285. case EDGEEND(2, -1): return internal('V', 1);
  286. case EDGEEND(2, +1): return internal('A', 1);
  287. default:
  288. return fail();
  289. }
  290. case 'U':
  291. switch (EDGEEND(edge, end)) {
  292. case EDGEEND(0, -1): return internal('B', 2);
  293. case EDGEEND(0, +1): return internal('U', 2);
  294. case EDGEEND(1, 0): return internal('U', 0);
  295. case EDGEEND(2, 0): return internal('B', 1);
  296. default:
  297. return fail();
  298. }
  299. case 'V':
  300. switch (EDGEEND(edge, end)) {
  301. case EDGEEND(0, -1): return internal('V', 1);
  302. case EDGEEND(0, +1): return internal('A', 1);
  303. case EDGEEND(1, 0): return internal('A', 2);
  304. case EDGEEND(2, 0): return internal('V', 0);
  305. default:
  306. return fail();
  307. }
  308. case 'C':
  309. switch (EDGEEND(edge, end)) {
  310. case EDGEEND(0, 0): return internal('C', 2);
  311. case EDGEEND(1, -1): return internal('C', 0);
  312. case EDGEEND(1, +1): return internal('Y', 2);
  313. case EDGEEND(2, 0): return internal('Y', 0);
  314. default:
  315. return fail();
  316. }
  317. case 'D':
  318. switch (EDGEEND(edge, end)) {
  319. case EDGEEND(0, 0): return internal('D', 1);
  320. case EDGEEND(1, 0): return internal('X', 0);
  321. case EDGEEND(2, -1): return internal('X', 1);
  322. case EDGEEND(2, +1): return internal('D', 0);
  323. default:
  324. return fail();
  325. }
  326. case 'X':
  327. switch (EDGEEND(edge, end)) {
  328. case EDGEEND(0, -1): return internal('Y', 0);
  329. case EDGEEND(0, +1): return internal('X', 2);
  330. case EDGEEND(1, 0): return internal('X', 0);
  331. case EDGEEND(2, -1): return internal('C', 0);
  332. case EDGEEND(2, +1): return internal('Y', 2);
  333. default:
  334. return fail();
  335. }
  336. case 'Y':
  337. switch (EDGEEND(edge, end)) {
  338. case EDGEEND(0, +1): return internal('X', 0);
  339. case EDGEEND(0, -1): return internal('Y', 1);
  340. case EDGEEND(1, -1): return internal('X', 1);
  341. case EDGEEND(1, +1): return internal('D', 0);
  342. case EDGEEND(2, 0): return internal('Y', 0);
  343. default:
  344. return fail();
  345. }
  346. default:
  347. return fail();
  348. }
  349. #undef EDGEEND
  350. }
  351. PenroseCoords *penrose_coords_new(void)
  352. {
  353. PenroseCoords *pc = snew(PenroseCoords);
  354. pc->nc = pc->csize = 0;
  355. pc->c = NULL;
  356. return pc;
  357. }
  358. void penrose_coords_free(PenroseCoords *pc)
  359. {
  360. if (pc) {
  361. sfree(pc->c);
  362. sfree(pc);
  363. }
  364. }
  365. void penrose_coords_make_space(PenroseCoords *pc, size_t size)
  366. {
  367. if (pc->csize < size) {
  368. pc->csize = pc->csize * 5 / 4 + 16;
  369. if (pc->csize < size)
  370. pc->csize = size;
  371. pc->c = sresize(pc->c, pc->csize, char);
  372. }
  373. }
  374. PenroseCoords *penrose_coords_copy(PenroseCoords *pc_in)
  375. {
  376. PenroseCoords *pc_out = penrose_coords_new();
  377. penrose_coords_make_space(pc_out, pc_in->nc);
  378. memcpy(pc_out->c, pc_in->c, pc_in->nc * sizeof(*pc_out->c));
  379. pc_out->nc = pc_in->nc;
  380. return pc_out;
  381. }
  382. /*
  383. * The main recursive function for computing the next triangle's
  384. * combinatorial coordinates.
  385. */
  386. static void penrosectx_step_recurse(
  387. PenroseContext *ctx, PenroseCoords *pc, size_t depth,
  388. unsigned edge, unsigned *outedge)
  389. {
  390. TransitionResult tr;
  391. penrosectx_extend_coords(ctx, pc, depth+2);
  392. /* Look up the transition out of the starting triangle */
  393. tr = transition(pc->c[depth+1], pc->c[depth], edge);
  394. /* If we've left the parent triangle, recurse to find out what new
  395. * triangle we've landed in at the next size up, and then call
  396. * transition_in to find out which child of that parent we're
  397. * going to */
  398. if (tr.type == EXTERNAL) {
  399. unsigned parent_outedge;
  400. penrosectx_step_recurse(
  401. ctx, pc, depth+1, tr.u.external.parent_edge, &parent_outedge);
  402. tr = transition_in(pc->c[depth+1], parent_outedge, tr.u.external.end);
  403. }
  404. /* Now we should definitely have ended up in a child of the
  405. * (perhaps rewritten) parent triangle */
  406. assert(tr.type == INTERNAL);
  407. pc->c[depth] = tr.u.internal.new_child;
  408. *outedge = tr.u.internal.new_edge;
  409. }
  410. void penrosectx_step(PenroseContext *ctx, PenroseCoords *pc,
  411. unsigned edge, unsigned *outedge)
  412. {
  413. /* Allow outedge to be NULL harmlessly, just in case */
  414. unsigned dummy_outedge;
  415. if (!outedge)
  416. outedge = &dummy_outedge;
  417. penrosectx_step_recurse(ctx, pc, 0, edge, outedge);
  418. }
  419. static Point penrose_triangle_post_edge(char c, unsigned edge)
  420. {
  421. static const Point acute_post_edge[3] = {
  422. {{-1, 1, 0, 1}}, /* phi * t^3 */
  423. {{-1, 1, -1, 1}}, /* t^4 */
  424. {{-1, 1, 0, 0}}, /* 1/phi * t^3 */
  425. };
  426. static const Point obtuse_post_edge[3] = {
  427. {{0, -1, 1, 0}}, /* 1/phi * t^4 */
  428. {{0, 0, 1, 0}}, /* t^2 */
  429. {{-1, 0, 0, 1}}, /* phi * t^4 */
  430. };
  431. switch (c) {
  432. case 'A': case 'B': case 'C': case 'D':
  433. return acute_post_edge[edge];
  434. default: /* case 'U': case 'V': case 'X': case 'Y': */
  435. return obtuse_post_edge[edge];
  436. }
  437. }
  438. void penrose_place(PenroseTriangle *tri, Point u, Point v, int index_of_u)
  439. {
  440. unsigned i;
  441. Point here = u, delta = point_sub(v, u);
  442. for (i = 0; i < 3; i++) {
  443. unsigned edge = (index_of_u + i) % 3;
  444. tri->vertices[edge] = here;
  445. here = point_add(here, delta);
  446. delta = point_mul(delta, penrose_triangle_post_edge(
  447. tri->pc->c[0], edge));
  448. }
  449. }
  450. void penrose_free(PenroseTriangle *tri)
  451. {
  452. penrose_coords_free(tri->pc);
  453. sfree(tri);
  454. }
  455. static bool penrose_relative_probability(char c)
  456. {
  457. /* Penrose tile probability ratios are always phi, so we can
  458. * approximate that very well using two consecutive Fibonacci
  459. * numbers */
  460. switch (c) {
  461. case 'A': case 'B': case 'X': case 'Y':
  462. return 165580141;
  463. case 'C': case 'D': case 'U': case 'V':
  464. return 102334155;
  465. default:
  466. return 0;
  467. }
  468. }
  469. static char penrose_choose_random(const char *possibilities, random_state *rs)
  470. {
  471. const char *p;
  472. unsigned long value, limit = 0;
  473. for (p = possibilities; *p; p++)
  474. limit += penrose_relative_probability(*p);
  475. value = random_upto(rs, limit);
  476. for (p = possibilities; *p; p++) {
  477. unsigned long curr = penrose_relative_probability(*p);
  478. if (value < curr)
  479. return *p;
  480. value -= curr;
  481. }
  482. assert(false && "Probability overflow!");
  483. return possibilities[0];
  484. }
  485. static const char *penrose_starting_tiles(int which)
  486. {
  487. return which == PENROSE_P2 ? "ABUV" : "CDXY";
  488. }
  489. static const char *penrose_valid_parents(char tile)
  490. {
  491. switch (tile) {
  492. case 'A': return "ABV";
  493. case 'B': return "ABU";
  494. case 'U': return "AU";
  495. case 'V': return "BV";
  496. case 'C': return "CX";
  497. case 'D': return "DY";
  498. case 'X': return "DXY";
  499. case 'Y': return "CXY";
  500. default: return NULL;
  501. }
  502. }
  503. void penrosectx_init_random(PenroseContext *ctx, random_state *rs, int which)
  504. {
  505. ctx->rs = rs;
  506. ctx->must_free_rs = false;
  507. ctx->prototype = penrose_coords_new();
  508. penrose_coords_make_space(ctx->prototype, 1);
  509. ctx->prototype->c[0] = penrose_choose_random(
  510. penrose_starting_tiles(which), rs);
  511. ctx->prototype->nc = 1;
  512. ctx->start_vertex = random_upto(rs, 3);
  513. ctx->orientation = random_upto(rs, 10);
  514. }
  515. void penrosectx_init_from_params(
  516. PenroseContext *ctx, const struct PenrosePatchParams *ps)
  517. {
  518. size_t i;
  519. ctx->rs = NULL;
  520. ctx->must_free_rs = false;
  521. ctx->prototype = penrose_coords_new();
  522. penrose_coords_make_space(ctx->prototype, ps->ncoords);
  523. for (i = 0; i < ps->ncoords; i++)
  524. ctx->prototype->c[i] = ps->coords[i];
  525. ctx->prototype->nc = ps->ncoords;
  526. ctx->start_vertex = ps->start_vertex;
  527. ctx->orientation = ps->orientation;
  528. }
  529. void penrosectx_cleanup(PenroseContext *ctx)
  530. {
  531. if (ctx->must_free_rs)
  532. random_free(ctx->rs);
  533. penrose_coords_free(ctx->prototype);
  534. }
  535. PenroseCoords *penrosectx_initial_coords(PenroseContext *ctx)
  536. {
  537. return penrose_coords_copy(ctx->prototype);
  538. }
  539. void penrosectx_extend_coords(PenroseContext *ctx, PenroseCoords *pc,
  540. size_t n)
  541. {
  542. if (ctx->prototype->nc < n) {
  543. penrose_coords_make_space(ctx->prototype, n);
  544. while (ctx->prototype->nc < n) {
  545. if (!ctx->rs) {
  546. /*
  547. * For safety, similarly to spectre.c, we respond to a
  548. * lack of available random_state by making a
  549. * deterministic one.
  550. */
  551. ctx->rs = random_new("dummy", 5);
  552. ctx->must_free_rs = true;
  553. }
  554. ctx->prototype->c[ctx->prototype->nc] = penrose_choose_random(
  555. penrose_valid_parents(ctx->prototype->c[ctx->prototype->nc-1]),
  556. ctx->rs);
  557. ctx->prototype->nc++;
  558. }
  559. }
  560. penrose_coords_make_space(pc, n);
  561. while (pc->nc < n) {
  562. pc->c[pc->nc] = ctx->prototype->c[pc->nc];
  563. pc->nc++;
  564. }
  565. }
  566. static Point penrose_triangle_edge_0_length(char c)
  567. {
  568. static const Point one = {{ 1, 0, 0, 0 }};
  569. static const Point phi = {{ 1, 0, 1, -1 }};
  570. static const Point invphi = {{ 0, 0, 1, -1 }};
  571. switch (c) {
  572. /* P2 tiling: unit-length edges are the long edges, i.e. edges
  573. * 1,2 of AB and edge 0 of UV. So AB have edge 0 short. */
  574. case 'A': case 'B':
  575. return invphi;
  576. case 'U': case 'V':
  577. return one;
  578. /* P3 tiling: unit-length edges are edges 1,2 of everything,
  579. * so CD have edge 0 short and XY have it long. */
  580. case 'C': case 'D':
  581. return invphi;
  582. default: /* case 'X': case 'Y': */
  583. return phi;
  584. }
  585. }
  586. PenroseTriangle *penrose_initial(PenroseContext *ctx)
  587. {
  588. char type = ctx->prototype->c[0];
  589. Point origin = {{ 0, 0, 0, 0 }};
  590. Point edge0 = penrose_triangle_edge_0_length(type);
  591. Point negoffset;
  592. size_t i;
  593. PenroseTriangle *tri = snew(PenroseTriangle);
  594. /* Orient the triangle by deciding what vector edge #0 should traverse */
  595. edge0 = point_mul(edge0, point_rot(ctx->orientation));
  596. /* Place the triangle at an arbitrary position, in that orientation */
  597. tri->pc = penrose_coords_copy(ctx->prototype);
  598. penrose_place(tri, origin, edge0, 0);
  599. /* Now translate so that the appropriate vertex is at the origin */
  600. negoffset = tri->vertices[ctx->start_vertex];
  601. for (i = 0; i < 3; i++)
  602. tri->vertices[i] = point_sub(tri->vertices[i], negoffset);
  603. return tri;
  604. }
  605. PenroseTriangle *penrose_adjacent(PenroseContext *ctx,
  606. const PenroseTriangle *src_tri,
  607. unsigned src_edge, unsigned *dst_edge_out)
  608. {
  609. unsigned dst_edge;
  610. PenroseTriangle *dst_tri = snew(PenroseTriangle);
  611. dst_tri->pc = penrose_coords_copy(src_tri->pc);
  612. penrosectx_step(ctx, dst_tri->pc, src_edge, &dst_edge);
  613. penrose_place(dst_tri, src_tri->vertices[(src_edge+1) % 3],
  614. src_tri->vertices[src_edge], dst_edge);
  615. if (dst_edge_out)
  616. *dst_edge_out = dst_edge;
  617. return dst_tri;
  618. }
  619. static int penrose_cmp(void *av, void *bv)
  620. {
  621. PenroseTriangle *a = (PenroseTriangle *)av, *b = (PenroseTriangle *)bv;
  622. size_t i, j;
  623. /* We should only ever need to compare the first two vertices of
  624. * any triangle, because those force the rest */
  625. for (i = 0; i < 2; i++) {
  626. for (j = 0; j < 4; j++) {
  627. int ac = a->vertices[i].coeffs[j], bc = b->vertices[i].coeffs[j];
  628. if (ac < bc)
  629. return -1;
  630. if (ac > bc)
  631. return +1;
  632. }
  633. }
  634. return 0;
  635. }
  636. static unsigned penrose_sibling_edge_index(char c)
  637. {
  638. switch (c) {
  639. case 'A': case 'U': return 2;
  640. case 'B': case 'V': return 1;
  641. default: return 0;
  642. }
  643. }
  644. void penrosectx_generate(
  645. PenroseContext *ctx,
  646. bool (*inbounds)(void *inboundsctx,
  647. const PenroseTriangle *tri), void *inboundsctx,
  648. void (*tile)(void *tilectx, const Point *vertices), void *tilectx)
  649. {
  650. tree234 *placed = newtree234(penrose_cmp);
  651. PenroseTriangle *qhead = NULL, *qtail = NULL;
  652. {
  653. PenroseTriangle *tri = penrose_initial(ctx);
  654. add234(placed, tri);
  655. tri->next = NULL;
  656. tri->reported = false;
  657. if (inbounds(inboundsctx, tri))
  658. qhead = qtail = tri;
  659. }
  660. while (qhead) {
  661. PenroseTriangle *tri = qhead;
  662. unsigned edge;
  663. unsigned sibling_edge = penrose_sibling_edge_index(tri->pc->c[0]);
  664. for (edge = 0; edge < 3; edge++) {
  665. PenroseTriangle *new_tri, *found_tri;
  666. new_tri = penrose_adjacent(ctx, tri, edge, NULL);
  667. if (!inbounds(inboundsctx, new_tri)) {
  668. penrose_free(new_tri);
  669. continue;
  670. }
  671. found_tri = find234(placed, new_tri, NULL);
  672. if (found_tri) {
  673. if (edge == sibling_edge && !tri->reported &&
  674. !found_tri->reported) {
  675. /*
  676. * found_tri and tri are opposite halves of the
  677. * same tile; both are in the tree, and haven't
  678. * yet been reported as a completed tile.
  679. */
  680. unsigned new_sibling_edge = penrose_sibling_edge_index(
  681. found_tri->pc->c[0]);
  682. Point tilevertices[4] = {
  683. tri->vertices[(sibling_edge + 1) % 3],
  684. tri->vertices[(sibling_edge + 2) % 3],
  685. found_tri->vertices[(new_sibling_edge + 1) % 3],
  686. found_tri->vertices[(new_sibling_edge + 2) % 3],
  687. };
  688. tile(tilectx, tilevertices);
  689. tri->reported = true;
  690. found_tri->reported = true;
  691. }
  692. penrose_free(new_tri);
  693. continue;
  694. }
  695. add234(placed, new_tri);
  696. qtail->next = new_tri;
  697. qtail = new_tri;
  698. new_tri->next = NULL;
  699. new_tri->reported = false;
  700. }
  701. qhead = qhead->next;
  702. }
  703. {
  704. PenroseTriangle *tri;
  705. while ((tri = delpos234(placed, 0)) != NULL)
  706. penrose_free(tri);
  707. freetree234(placed);
  708. }
  709. }
  710. const char *penrose_tiling_params_invalid(
  711. const struct PenrosePatchParams *params, int which)
  712. {
  713. size_t i;
  714. if (params->ncoords == 0)
  715. return "expected at least one coordinate";
  716. for (i = 0; i < params->ncoords; i++) {
  717. if (!penrose_valid_letter(params->coords[i], which))
  718. return "invalid coordinate letter";
  719. if (i > 0 && !strchr(penrose_valid_parents(params->coords[i-1]),
  720. params->coords[i]))
  721. return "invalid pair of consecutive coordinates";
  722. }
  723. return NULL;
  724. }
  725. struct PenroseOutputCtx {
  726. int xoff, yoff;
  727. Coord xmin, xmax, ymin, ymax;
  728. penrose_tile_callback_fn external_cb;
  729. void *external_cbctx;
  730. };
  731. static bool inbounds(void *vctx, const PenroseTriangle *tri)
  732. {
  733. struct PenroseOutputCtx *octx = (struct PenroseOutputCtx *)vctx;
  734. size_t i;
  735. for (i = 0; i < 3; i++) {
  736. Coord x = point_x(tri->vertices[i]);
  737. Coord y = point_y(tri->vertices[i]);
  738. if (coord_cmp(x, octx->xmin) < 0 || coord_cmp(x, octx->xmax) > 0 ||
  739. coord_cmp(y, octx->ymin) < 0 || coord_cmp(y, octx->ymax) > 0)
  740. return false;
  741. }
  742. return true;
  743. }
  744. static void null_output_tile(void *vctx, const Point *vertices)
  745. {
  746. }
  747. static void really_output_tile(void *vctx, const Point *vertices)
  748. {
  749. struct PenroseOutputCtx *octx = (struct PenroseOutputCtx *)vctx;
  750. size_t i;
  751. int coords[16];
  752. for (i = 0; i < 4; i++) {
  753. Coord x = point_x(vertices[i]);
  754. Coord y = point_y(vertices[i]);
  755. coords[4*i + 0] = x.c1 + octx->xoff;
  756. coords[4*i + 1] = x.cr5;
  757. coords[4*i + 2] = y.c1 + octx->yoff;
  758. coords[4*i + 3] = y.cr5;
  759. }
  760. octx->external_cb(octx->external_cbctx, coords);
  761. }
  762. static void penrose_set_bounds(struct PenroseOutputCtx *octx, int w, int h)
  763. {
  764. octx->xoff = w/2;
  765. octx->yoff = h/2;
  766. octx->xmin.c1 = -octx->xoff;
  767. octx->xmax.c1 = -octx->xoff + w;
  768. octx->ymin.c1 = octx->yoff - h;
  769. octx->ymax.c1 = octx->yoff;
  770. octx->xmin.cr5 = 0;
  771. octx->xmax.cr5 = 0;
  772. octx->ymin.cr5 = 0;
  773. octx->ymax.cr5 = 0;
  774. }
  775. void penrose_tiling_randomise(struct PenrosePatchParams *params, int which,
  776. int w, int h, random_state *rs)
  777. {
  778. PenroseContext ctx[1];
  779. struct PenroseOutputCtx octx[1];
  780. penrose_set_bounds(octx, w, h);
  781. penrosectx_init_random(ctx, rs, which);
  782. penrosectx_generate(ctx, inbounds, octx, null_output_tile, NULL);
  783. params->orientation = ctx->orientation;
  784. params->start_vertex = ctx->start_vertex;
  785. params->ncoords = ctx->prototype->nc;
  786. params->coords = snewn(params->ncoords, char);
  787. memcpy(params->coords, ctx->prototype->c, params->ncoords);
  788. penrosectx_cleanup(ctx);
  789. }
  790. void penrose_tiling_generate(
  791. const struct PenrosePatchParams *params, int w, int h,
  792. penrose_tile_callback_fn cb, void *cbctx)
  793. {
  794. PenroseContext ctx[1];
  795. struct PenroseOutputCtx octx[1];
  796. penrose_set_bounds(octx, w, h);
  797. octx->external_cb = cb;
  798. octx->external_cbctx = cbctx;
  799. penrosectx_init_from_params(ctx, params);
  800. penrosectx_generate(ctx, inbounds, octx, really_output_tile, octx);
  801. penrosectx_cleanup(ctx);
  802. }