1 /* -*- Mode: C; tab-width: 4 -*-
2 * penrose --- quasiperiodic tilings.
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)penrose.c 4.00 97/01/01 xlockmore";
8 /* Copyright (c) 1996 by Timo Korvola <tkorvola@dopey.hut.fi>
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
23 * 10-May-97: jwz@netscape.com: turned into a standalone program.
28 Be careful, this probably still has a few bugs (many of which may only
29 appear with a very low probability). These are seen with -verbose .
30 If one of these are hit penrose will reinitialize.
34 * See Onoda, Steinhardt, DiVincenzo and Socolar in
35 * Phys. Rev. Lett. 60, #25, 1988 or
36 * Strandburg in Computers in Physics, Sep/Oct 1991.
38 * This implementation uses the simpler version of the growth
39 * algorithm, i.e., if there are no forced vertices, a randomly chosen
40 * tile is added to a randomly chosen vertex (no preference for those
43 * There are two essential differences to the algorithm presented in
44 * the literature: First, we do not allow the tiling to enclose an
45 * untiled area. Whenever this is in danger of happening, we just
46 * do not add the tile, hoping for a better random choice the next
47 * time. Second, when choosing a vertex randomly, we will take
48 * one that lies withing the viewport if available. If this seems to
49 * cause enclosures in the forced rule case, we will allow invisible
50 * vertices to be chosen.
52 * Tiling is restarted whenever one of the following happens: there
53 * are no incomplete vertices within the viewport or the tiling has
54 * extended a window's length beyond the edge of the window
55 * horizontally or vertically or forced rule choice has failed 100
56 * times due to areas about to become enclosed.
61 # define PROGCLASS "Penrose"
62 # define HACK_INIT init_penrose
63 # define HACK_DRAW draw_penrose
64 # define penrose_opts xlockmore_opts
65 # define DEFAULTS "*delay: 10000 \n" \
68 # include "xlockmore.h" /* from the xscreensaver distribution */
69 #else /* !STANDALONE */
70 # include "xlock.h" /* from the xlockmore distribution */
71 #endif /* !STANDALONE */
75 * Annoyingly the ANSI C library people have reserved all identifiers
76 * ending with _t for future use. Hence we use _c as a suffix for
77 * typedefs (c for class, although this is not C++).
83 * In theory one could fit 10 tiles to a single vertex. However, the
84 * vertex rules only allow at most seven tiles to meet at a vertex.
87 #define CELEBRATE 31415927 /* This causes a pause, an error occurred. */
88 #define COMPLETION 3141593 /* This causes a pause, an error occurred. */
90 #define MAX_TILES_PER_VERTEX 7
91 #define N_VERTEX_RULES 8
92 #define ALLOC_NODE( type) ((type *)malloc( sizeof( type)))
93 #define DEF_AMMANN "False"
97 static XrmOptionDescRec opts[] =
99 {"-ammann", ".penrose.ammann", XrmoptionNoArg, (caddr_t) "on"},
100 {"+ammann", ".penrose.ammann", XrmoptionNoArg, (caddr_t) "off"}
102 static argtype vars[] =
104 {(caddr_t *) & ammann, "ammann", "Ammann", DEF_AMMANN, t_Bool}
106 static OptionStruct desc[] =
108 {"-/+ammann", "turn on/off Ammann lines"}
111 ModeSpecOpt penrose_opts = { 2, opts, 1, vars, desc };
115 * These are used to specify directions. They can also be used in bit
116 * masks to specify a combination of directions.
123 * We do not actually maintain objects corresponding to the tiles since
124 * we do not really need them and they would only consume memory and
125 * cause additional bookkeeping. Instead we only have vertices, and
126 * each vertex lists the type of each adjacent tile as well as the
127 * position of the vertex on the tile (hereafter refered to as
128 * "corner"). These positions are numbered in counterclockwise order
129 * so that 0 is where two double arrows meet (see one of the
130 * articles). The tile type and vertex number are stored in a single
131 * integer (we use char, and even most of it remains unused).
133 * The primary use of tile objects would be draw traversal, but we do
134 * not currently do redraws at all (we just start over).
136 #define VT_CORNER_MASK 0x3
137 #define VT_TYPE_MASK 0x4
141 #define VT_TOTAL_MASK 0x7
143 typedef unsigned char vertex_type_c;
146 * These allow one to compute the types of the other corners of the tile. If
147 * you are standing at a vertex of type vt looking towards the middle of the
148 * tile, VT_LEFT( vt) is the vertex on your left etc.
150 #define VT_LEFT( vt) ((((vt) - 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK)))
151 #define VT_RIGHT( vt) ((((vt) + 1) & VT_CORNER_MASK) | (((vt) & VT_TYPE_MASK)))
152 #define VT_FAR( vt) ((vt) ^ 2)
156 * Since we do not do redraws, we only store the vertices we need. These are
157 * the ones with still some empty space around them for the growth algorithm
160 * Here we use a doubly chained ring-like structure as vertices often need
161 * to be removed or inserted (they are kept in geometrical order
162 * circling the tiled area counterclockwise). The ring is refered to by
163 * a pointer to one more or less random node. When deleting nodes one
164 * must make sure that this pointer continues to refer to a valid
165 * node. A vertex count is maintained to make it easier to pick
168 typedef struct forced_node forced_node_c;
170 typedef struct fringe_node {
171 struct fringe_node *prev;
172 struct fringe_node *next;
173 /* These are numbered counterclockwise. The gap, if any, lies
174 between the last and first tiles. */
175 vertex_type_c tiles[MAX_TILES_PER_VERTEX];
177 /* A bit mask used to indicate vertex rules that are still applicable for
178 completing this vertex. Initialize this to (1 << N_VERTEX_RULES) - 1,
179 i.e., all ones, and the rule matching functions will automatically mask
180 out rules that no longer match. */
181 unsigned char rule_mask;
182 /* If the vertex is on the forced vertex list, this points to the
183 pointer to the appropriate node in the list. To remove the
184 vertex from the list just set *list_ptr to the next node,
185 deallocate and decrement node count. */
186 struct forced_node **list_ptr;
187 /* Screen coordinates. */
189 /* We also keep track of 5D coordinates to avoid rounding errors.
190 These are in units of edge length. */
192 /* This is used to quickly check if a vertex is visible. */
193 unsigned char off_screen;
197 fringe_node_c *nodes;
198 /* This does not count off-screen nodes. */
204 * The forced vertex pool contains vertices where at least one
205 * side of the tiled region can only be extended in one way. Note
206 * that this does not necessarily mean that there would only be one
207 * applicable rule. forced_sides are specified using S_LEFT and
208 * S_RIGHT as if looking at the untiled region from the vertex.
211 fringe_node_c *vertex;
212 unsigned forced_sides;
213 struct forced_node *next;
217 forced_node_c *first;
218 int n_nodes, n_visible;
222 /* This is the data related to the tiling of one screen. */
228 forced_pool_c forced;
230 int thick_color, thin_color;
233 static tiling_c *tilings; /* = {0} */
236 /* The tiles are listed in counterclockwise order. */
238 vertex_type_c tiles[MAX_TILES_PER_VERTEX];
242 static vertex_rule_c vertex_rules[N_VERTEX_RULES] =
245 {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2}, 5},
247 {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THICK | 0}, 5},
249 {VT_THICK | 0, VT_THICK | 0, VT_THICK | 0, VT_THIN | 0}, 4},
251 {VT_THICK | 2, VT_THICK | 2, VT_THIN | 1, VT_THIN | 3, VT_THICK | 2,
252 VT_THIN | 1, VT_THIN | 3}, 7},
254 {VT_THICK | 2, VT_THICK | 2, VT_THICK | 2, VT_THICK | 2,
255 VT_THIN | 1, VT_THIN | 3}, 6},
257 {VT_THICK | 1, VT_THICK | 3, VT_THIN | 2}, 3},
259 {VT_THICK | 0, VT_THIN | 0, VT_THIN | 0}, 3},
261 {VT_THICK | 2, VT_THIN | 1, VT_THICK | 3, VT_THICK | 1, VT_THIN | 3}, 5}
265 /* Match information returned by match_rules. */
272 /* Occasionally floating point coordinates are needed. */
278 /* All angles are measured in multiples of 36 degrees. */
281 static angle_c vtype_angles[] =
282 {4, 1, 4, 1, 2, 3, 2, 3};
284 #define vtype_angle( v) (vtype_angles[ v])
287 /* Direction angle of an edge. */
289 vertex_dir(ModeInfo * mi, fringe_node_c * vertex, unsigned side)
291 tiling_c *tp = &tilings[MI_SCREEN(mi)];
293 (side == S_LEFT ? vertex->next : vertex->prev);
296 for (i = 0; i < 5; i++)
297 switch (v2->fived[i] - vertex->fived[i]) {
301 return (2 * i + 5) % 10;
304 if (MI_WIN_IS_VERBOSE(mi)) {
305 (void) fprintf(stderr,
306 "Weirdness in vertex_dir (this has been reported)\n");
307 for (i = 0; i < 5; i++)
308 (void) fprintf(stderr, "v2->fived[%d]=%d, vertex->fived[%d]=%d\n",
309 i, v2->fived[i], i, vertex->fived[i]);
311 MI_PAUSE(mi) = CELEBRATE;
316 /* Move one step to a given direction. */
318 add_unit_vec(angle_c dir, int *fived)
325 fived[dir2i[dir % 5]] += (dir % 2 ? -1 : 1);
329 /* For comparing coordinates. */
330 #define fived_equal( f1, f2) (!memcmp( (f1), (f2), 5 * sizeof( int)))
334 * This computes screen coordinates from 5D representation. Note that X
335 * uses left-handed coordinates (y increases downwards).
338 fived_to_loc(int fived[], tiling_c * tp)
340 static fcoord_c fived_table[5] =
343 float fifth = 8 * atan(1.) / 5;
346 register fcoord_c offset =
348 XPoint pt = tp->origin;
350 if (fived_table[0].x == .0)
351 for (i = 0; i < 5; i++) {
352 fived_table[i].x = cos(fifth * i);
353 fived_table[i].y = sin(fifth * i);
355 for (i = 0; i < 5; i++) {
356 r = fived[i] * tp->edge_length;
357 offset.x += r * fived_table[i].x;
358 offset.y -= r * fived_table[i].y;
360 pt.x += (int) (offset.x + .5);
361 pt.y += (int) (offset.y + .5);
366 /* Mop up dynamic data for one screen. */
368 release_screen(tiling_c * tp)
370 register fringe_node_c *fp1, *fp2;
371 register forced_node_c *lp1, *lp2;
373 if (tp->fringe.nodes == 0)
375 fp1 = tp->fringe.nodes;
379 (void) free((char *) fp2);
380 } while (fp1 != tp->fringe.nodes);
381 tp->fringe.nodes = 0;
382 for (lp1 = tp->forced.first; lp1 != 0;) {
385 (void) free((char *) lp2);
387 tp->forced.first = 0;
391 /* Called to init the mode. */
393 init_penrose(ModeInfo * mi)
399 if (tilings == NULL) {
400 if ((tilings = (tiling_c *) calloc(MI_NUM_SCREENS(mi),
401 sizeof (tiling_c))) == NULL)
404 tp = &tilings[MI_SCREEN(mi)];
407 tp->width = MI_WIN_WIDTH(mi);
408 tp->height = MI_WIN_HEIGHT(mi);
409 if (MI_NPIXELS(mi) > 2) {
410 tp->thick_color = NRAND(MI_NPIXELS(mi));
411 /* Insure good contrast */
412 tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color +
413 MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
417 tp->edge_length = NRAND(MIN(-size, MAX(MINSIZE,
418 MIN(tp->width, tp->height) / 2)) - MINSIZE + 1) + MINSIZE;
419 else if (size < MINSIZE) {
421 tp->edge_length = MAX(MINSIZE, MIN(tp->width, tp->height) / 2);
423 tp->edge_length = MINSIZE;
425 tp->edge_length = MIN(size, MAX(MINSIZE,
426 MIN(tp->width, tp->height) / 2));
427 tp->origin.x = (tp->width / 2 + NRAND(tp->width)) / 2;
428 tp->origin.y = (tp->height / 2 + NRAND(tp->height)) / 2;
429 tp->fringe.n_nodes = 2;
430 if (tp->fringe.nodes != 0)
432 if (tp->fringe.nodes != 0 || tp->forced.first != 0) {
433 if (MI_WIN_IS_VERBOSE(mi)) {
434 (void) fprintf(stderr, "Weirdness in init_penrose()\n");
435 (void) fprintf(stderr, "tp->fringe.nodes = 0 && tp->forced.first = 0\n");
437 release_screen(tp); /* Try again */
440 tp->forced.n_nodes = tp->forced.n_visible = 0;
441 fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c);
443 if (MI_WIN_IS_VERBOSE(mi)) {
444 (void) fprintf(stderr, "Weirdness in init_penrose()\n");
445 (void) fprintf(stderr, "fp = 0\n");
447 fp = tp->fringe.nodes = ALLOC_NODE(fringe_node_c);
451 fp->rule_mask = (1 << N_VERTEX_RULES) - 1;
453 fp->prev = fp->next = ALLOC_NODE(fringe_node_c);
455 if (MI_WIN_IS_VERBOSE(mi)) {
456 (void) fprintf(stderr, "Weirdness in init_penrose()\n");
457 (void) fprintf(stderr, "fp->next = 0\n");
459 fp->prev = fp->next = ALLOC_NODE(fringe_node_c);
463 fp->loc = tp->origin;
464 fp->off_screen = False;
465 for (i = 0; i < 5; i++)
470 fp->next->prev = fp->next->next = fp;
473 fp->fived[i] = 2 * NRAND(2) - 1;
474 fp->loc = fived_to_loc(fp->fived, tp);
475 /* That's it! We have created our first edge. */
479 * This attempts to match the configuration of vertex with the vertex
480 * rules. The return value is a total match count. If matches is
481 * non-null, it will be used to store information about the matches
482 * and must be large enough to contain it. To play it absolutely
483 * safe, allocate room for MAX_TILES_PER_VERTEX * N_VERTEX_RULES
484 * entries when searching all matches. The rule mask of vertex will
485 * be applied and rules masked out will not be searched. Only strict
486 * subsequences match. If first_only is true, the search stops when
487 * the first match is found. Otherwise all matches will be found and
488 * the rule_mask of vertex will be updated, which also happens in
489 * single-match mode if no match is found.
492 match_rules(fringe_node_c * vertex, rule_match_c * matches, int first_only)
494 /* I will assume that I can fit all the relevant bits in vertex->tiles
495 into one unsigned long. With 3 bits per element and at most 7
496 elements this means 21 bits, which should leave plenty of room.
497 After packing the bits the rest is just integer comparisons and
498 some bit shuffling. This is essentially Rabin-Karp without
499 congruence arithmetic. */
501 int hits = 0, good_rules[N_VERTEX_RULES], n_good = 0;
503 vertex_hash = 0, lower_bits_mask = ~(VT_TOTAL_MASK << VT_BITS * (vertex->n_tiles - 1));
504 unsigned new_rule_mask = 0;
506 for (i = 0; i < N_VERTEX_RULES; i++)
507 if (vertex->n_tiles >= vertex_rules[i].n_tiles)
508 vertex->rule_mask &= ~(1 << i);
509 else if (vertex->rule_mask & 1 << i)
510 good_rules[n_good++] = i;
511 for (i = 0; i < vertex->n_tiles; i++)
512 vertex_hash |= (unsigned long) vertex->tiles[i] << (VT_BITS * i);
514 for (j = 0; j < n_good; j++) {
515 unsigned long rule_hash = 0;
516 vertex_rule_c *vr = vertex_rules + good_rules[j];
518 for (i = 0; i < vertex->n_tiles; i++)
519 rule_hash |= (unsigned long) vr->tiles[i] << (VT_BITS * i);
520 if (rule_hash == vertex_hash) {
522 matches[hits].rule = good_rules[j];
523 matches[hits].pos = 0;
529 new_rule_mask |= 1 << good_rules[j];
531 for (i = vr->n_tiles - 1; i > 0; i--) {
532 rule_hash = vr->tiles[i] | (rule_hash & lower_bits_mask) << VT_BITS;
533 if (vertex_hash == rule_hash) {
535 matches[hits].rule = good_rules[j];
536 matches[hits].pos = i;
542 new_rule_mask |= 1 << good_rules[j];
546 vertex->rule_mask = new_rule_mask;
552 * find_completions finds the possible ways to add a tile to a vertex.
553 * The return values is the number of such possibilities. You must
554 * first call match_rules to produce matches and n_matches. sides
555 * specifies which side of the vertex to extend and can be S_LEFT or
556 * S_RIGHT. If results is non-null, it should point to an array large
557 * enough to contain the results, which will be stored there.
558 * MAX_COMPL elements will always suffice. If first_only is true we
559 * stop as soon as we find one possibility (NOT USED).
564 find_completions(fringe_node_c * vertex, rule_match_c * matches, int n_matches,
565 unsigned side, vertex_type_c * results /*, int first_only */ )
569 vertex_type_c buf[MAX_COMPL];
575 for (i = 0; i < n_matches; i++) {
576 vertex_rule_c *rule = vertex_rules + matches[i].rule;
577 int pos = (matches[i].pos
578 + (side == S_RIGHT ? vertex->n_tiles : rule->n_tiles - 1))
580 vertex_type_c vtype = rule->tiles[pos];
583 for (j = 0; j < n_res; j++)
584 if (vtype == results[j]) {
589 results[n_res++] = vtype;
596 * Draw a tile on the display. Vertices must be given in a
597 * counterclockwise order. vtype is the vertex type of v1 (and thus
598 * also gives the tile type).
601 draw_tile(fringe_node_c * v1, fringe_node_c * v2,
602 fringe_node_c * v3, fringe_node_c * v4,
603 vertex_type_c vtype, ModeInfo * mi)
605 Display *display = MI_DISPLAY(mi);
606 Window window = MI_WINDOW(mi);
608 tiling_c *tp = &tilings[MI_SCREEN(mi)];
610 vertex_type_c corner = vtype & VT_CORNER_MASK;
612 if (v1->off_screen && v2->off_screen && v3->off_screen && v4->off_screen)
614 pts[corner] = v1->loc;
615 pts[VT_RIGHT(corner)] = v2->loc;
616 pts[VT_FAR(corner)] = v3->loc;
617 pts[VT_LEFT(corner)] = v4->loc;
619 if (MI_NPIXELS(mi) > 2) {
620 if ((vtype & VT_TYPE_MASK) == VT_THICK)
621 XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color));
623 XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
625 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
626 XFillPolygon(display, window, gc, pts, 4, Convex, CoordModeOrigin);
627 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
628 XDrawLines(display, window, gc, pts, 5, CoordModeOrigin);
631 /* Draw some Ammann lines for debugging purposes. This will probably
632 fail miserably on a b&w display. */
634 if ((vtype & VT_TYPE_MASK) == VT_THICK) {
638 float pi10 = 2 * atan(1.) / 5;
640 r = 1 - sin(pi10) / (2 * sin(3 * pi10));
642 if (MI_NPIXELS(mi) > 2)
643 XSetForeground(display, gc, MI_PIXEL(mi, tp->thin_color));
645 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
646 XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
648 XDrawLine(display, window, gc,
649 (int) (r * pts[3].x + (1 - r) * pts[0].x + .5),
650 (int) (r * pts[3].y + (1 - r) * pts[0].y + .5),
651 (int) (r * pts[1].x + (1 - r) * pts[0].x + .5),
652 (int) (r * pts[1].y + (1 - r) * pts[0].y + .5));
653 if (MI_NPIXELS(mi) <= 2)
654 XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter);
656 if (MI_NPIXELS(mi) > 2)
657 XSetForeground(display, gc, MI_PIXEL(mi, tp->thick_color));
659 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
660 XSetLineAttributes(display, gc, 1, LineOnOffDash, CapNotLast, JoinMiter);
662 XDrawLine(display, window, gc,
663 (int) ((pts[3].x + pts[2].x) / 2 + .5),
664 (int) ((pts[3].y + pts[2].y) / 2 + .5),
665 (int) ((pts[1].x + pts[2].x) / 2 + .5),
666 (int) ((pts[1].y + pts[2].y) / 2 + .5));
667 if (MI_NPIXELS(mi) <= 2)
668 XSetLineAttributes(display, gc, 1, LineSolid, CapNotLast, JoinMiter);
674 * Update the status of this vertex on the forced vertex queue. If
675 * the vertex has become untileable set tp->done. This is supposed
676 * to detect dislocations -- never call this routine with a completely
679 * Check for untileable vertices in check_vertex and stop tiling as
680 * soon as one finds one. I don't know if it is possible to run out
681 * of forced vertices while untileable vertices exist (or will
682 * cavities inevitably appear). If this can happen, add_random_tile
683 * might get called with an untileable vertex, causing ( n <= 1).
684 * (This is what the tp->done checks for).
686 * A MI_PAUSE celebrates the dislocation.
689 check_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp)
691 rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
692 int n_hits = match_rules(vertex, hits, False);
693 unsigned forced_sides = 0;
695 if (vertex->rule_mask == 0) {
697 if (MI_WIN_IS_VERBOSE(mi)) {
698 (void) fprintf(stderr, "Dislocation occured!\n");
700 MI_PAUSE(mi) = CELEBRATE; /* Should be able to recover */
702 if (1 == find_completions(vertex, hits, n_hits, S_LEFT, 0 /*, False */ ))
703 forced_sides |= S_LEFT;
704 if (1 == find_completions(vertex, hits, n_hits, S_RIGHT, 0 /*, False */ ))
705 forced_sides |= S_RIGHT;
706 if (forced_sides == 0) {
707 if (vertex->list_ptr != 0) {
708 forced_node_c *node = *vertex->list_ptr;
710 *vertex->list_ptr = node->next;
712 node->next->vertex->list_ptr = vertex->list_ptr;
714 tp->forced.n_nodes--;
715 if (!vertex->off_screen)
716 tp->forced.n_visible--;
717 vertex->list_ptr = 0;
722 if (vertex->list_ptr == 0) {
723 node = ALLOC_NODE(forced_node_c);
724 node->vertex = vertex;
725 node->next = tp->forced.first;
726 if (tp->forced.first != 0)
727 tp->forced.first->vertex->list_ptr = &(node->next);
728 tp->forced.first = node;
729 vertex->list_ptr = &(tp->forced.first);
730 tp->forced.n_nodes++;
731 if (!vertex->off_screen)
732 tp->forced.n_visible++;
734 node = *vertex->list_ptr;
735 node->forced_sides = forced_sides;
741 * Delete this vertex. If the vertex is a member of the forced vertex queue,
742 * also remove that entry. We assume that the vertex is no longer
743 * connected to the fringe. Note that tp->fringe.nodes must not point to
744 * the vertex being deleted.
747 delete_vertex(ModeInfo * mi, fringe_node_c * vertex, tiling_c * tp)
749 if (tp->fringe.nodes == vertex) {
751 if (MI_WIN_IS_VERBOSE(mi)) {
752 (void) fprintf(stderr, "Weirdness in delete_penrose()\n");
753 (void) fprintf(stderr, "tp->fringe.nodes == vertex\n");
755 MI_PAUSE(mi) = CELEBRATE;
757 if (vertex->list_ptr != 0) {
758 forced_node_c *node = *vertex->list_ptr;
760 *vertex->list_ptr = node->next;
762 node->next->vertex->list_ptr = vertex->list_ptr;
764 tp->forced.n_nodes--;
765 if (!vertex->off_screen)
766 tp->forced.n_visible--;
768 if (!vertex->off_screen)
769 tp->fringe.n_nodes--;
774 /* Check whether the addition of a tile of type vtype would completely fill *
775 the space available at vertex. */
777 fills_vertex(ModeInfo * mi, vertex_type_c vtype, fringe_node_c * vertex)
780 (vertex_dir(mi, vertex, S_LEFT) - vertex_dir(mi, vertex, S_RIGHT)
781 - vtype_angle(vtype)) % 10 == 0;
786 * If you were to add a tile of type vtype to a specified side of
787 * vertex, fringe_changes tells you which other vertices it would
788 * attach to. The addresses of these vertices will be stored in the
789 * last three arguments. Null is stored if the corresponding vertex
790 * would need to be allocated.
792 * The function also analyzes which vertices would be swallowed by the tiling
793 * and thus cut off from the fringe. The result is returned as a bit pattern.
795 #define FC_BAG 1 /* Total enclosure. Should never occur. */
796 #define FC_NEW_RIGHT 2
798 #define FC_NEW_LEFT 8
799 #define FC_NEW_MASK 0xe
800 #define FC_CUT_THIS 0x10
801 #define FC_CUT_RIGHT 0x20
802 #define FC_CUT_FAR 0x40
803 #define FC_CUT_LEFT 0x80
804 #define FC_CUT_MASK 0xf0
805 #define FC_TOTAL_MASK 0xff
808 fringe_changes(ModeInfo * mi, fringe_node_c * vertex,
809 unsigned side, vertex_type_c vtype,
810 fringe_node_c ** right, fringe_node_c ** far,
811 fringe_node_c ** left)
813 fringe_node_c *v, *f = NULL;
814 unsigned result = FC_NEW_FAR; /* We clear this later if necessary. */
818 if (fills_vertex(mi, vtype, vertex)) {
819 result |= FC_CUT_THIS;
820 } else if (side == S_LEFT) {
821 result |= FC_NEW_RIGHT;
825 result |= FC_NEW_LEFT;
830 if (!(result & FC_NEW_LEFT)) {
834 if (fills_vertex(mi, VT_LEFT(vtype), v)) {
835 result = (result & ~FC_NEW_FAR) | FC_CUT_LEFT;
841 if (!(result & FC_NEW_RIGHT)) {
845 if (fills_vertex(mi, VT_RIGHT(vtype), v)) {
846 result = (result & ~FC_NEW_FAR) | FC_CUT_RIGHT;
852 if (!(result & FC_NEW_FAR)
853 && fills_vertex(mi, VT_FAR(vtype), f)) {
854 result |= FC_CUT_FAR;
855 result &= (~FC_NEW_LEFT & ~FC_NEW_RIGHT);
856 if (right && (result & FC_CUT_LEFT))
858 if (left && (result & FC_CUT_RIGHT))
861 if (((result & FC_CUT_LEFT) && (result & FC_CUT_RIGHT))
862 || ((result & FC_CUT_THIS) && (result & FC_CUT_FAR)))
868 /* A couple of lesser helper functions for add_tile. */
870 add_vtype(fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
873 vertex->tiles[vertex->n_tiles++] = vtype;
877 for (i = vertex->n_tiles; i > 0; i--)
878 vertex->tiles[i] = vertex->tiles[i - 1];
879 vertex->tiles[0] = vtype;
884 static fringe_node_c *
885 alloc_vertex(ModeInfo * mi, angle_c dir, fringe_node_c * from, tiling_c * tp)
887 fringe_node_c *v = ALLOC_NODE(fringe_node_c);
891 if (MI_WIN_IS_VERBOSE(mi)) {
892 (void) fprintf(stderr, "Weirdness in alloc_vertex()\n");
893 (void) fprintf(stderr, "v = 0\n");
895 MI_PAUSE(mi) = CELEBRATE;
898 add_unit_vec(dir, v->fived);
899 v->loc = fived_to_loc(v->fived, tp);
900 if (v->loc.x < 0 || v->loc.y < 0
901 || v->loc.x >= tp->width || v->loc.y >= tp->height) {
902 v->off_screen = True;
903 if (v->loc.x < -tp->width || v->loc.y < -tp->height
904 || v->loc.x >= 2 * tp->width || v->loc.y >= 2 * tp->height)
907 v->off_screen = False;
908 tp->fringe.n_nodes++;
911 v->rule_mask = (1 << N_VERTEX_RULES) - 1;
917 * Add a tile described by vtype to the side of vertex. This must be
918 * allowed by the rules -- we do not check it here. New vertices are
919 * allocated as necessary. The fringe and the forced vertex pool are updated.
920 * The new tile is drawn on the display.
922 * One thing we do check here is whether the new tile causes an untiled
923 * area to become enclosed by the tiling. If this would happen, the tile
924 * is not added. The return value is true iff a tile was added.
927 add_tile(ModeInfo * mi,
928 fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
930 tiling_c *tp = &tilings[MI_SCREEN(mi)];
937 unsigned fc = fringe_changes(mi, vertex, side, vtype, &right, &far, &left);
940 ltype = VT_LEFT(vtype),
941 rtype = VT_RIGHT(vtype),
942 ftype = VT_FAR(vtype);
944 /* By our conventions vertex->next lies to the left of vertex and
945 vertex->prev to the right. */
947 /* This should never occur. */
950 if (MI_WIN_IS_VERBOSE(mi)) {
951 (void) fprintf(stderr, "Weirdness in add_tile()\n");
952 (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
955 if (side == S_LEFT) {
957 right = alloc_vertex(mi,
958 vertex_dir(mi, vertex, S_LEFT) - vtype_angle(vtype), vertex, tp);
960 far = alloc_vertex(mi,
961 vertex_dir(mi, left, S_RIGHT) + vtype_angle(ltype), left, tp);
964 left = alloc_vertex(mi,
965 vertex_dir(mi, vertex, S_RIGHT) + vtype_angle(vtype), vertex, tp);
967 far = alloc_vertex(mi,
968 vertex_dir(mi, right, S_LEFT) - vtype_angle(rtype), right, tp);
971 /* Having allocated the new vertices, but before joining them with
972 the rest of the fringe, check if vertices with same coordinates
973 already exist. If any such are found, give up. */
974 node = tp->fringe.nodes;
976 if (((fc & FC_NEW_LEFT) && fived_equal(node->fived, left->fived))
977 || ((fc & FC_NEW_RIGHT) && fived_equal(node->fived, right->fived))
978 || ((fc & FC_NEW_FAR) && fived_equal(node->fived, far->fived))) {
979 /* Better luck next time. */
980 if (fc & FC_NEW_LEFT)
981 delete_vertex(mi, left, tp);
982 if (fc & FC_NEW_RIGHT)
983 delete_vertex(mi, right, tp);
985 delete_vertex(mi, far, tp);
989 } while (node != tp->fringe.nodes);
992 if (!(fc & FC_CUT_THIS))
993 if (side == S_LEFT) {
994 vertex->next = right;
995 right->prev = vertex;
1000 if (!(fc & FC_CUT_FAR)) {
1001 if (!(fc & FC_CUT_LEFT)) {
1005 if (!(fc & FC_CUT_RIGHT)) {
1010 draw_tile(vertex, right, far, left, vtype, mi);
1012 /* Delete vertices that are no longer on the fringe. Check the others. */
1013 if (fc & FC_CUT_THIS) {
1014 tp->fringe.nodes = far;
1015 delete_vertex(mi, vertex, tp);
1017 add_vtype(vertex, side, vtype);
1018 check_vertex(mi, vertex, tp);
1019 tp->fringe.nodes = vertex;
1021 if (fc & FC_CUT_FAR)
1022 delete_vertex(mi, far, tp);
1024 add_vtype(far, fc & FC_CUT_RIGHT ? S_LEFT : S_RIGHT, ftype);
1025 check_vertex(mi, far, tp);
1027 if (fc & FC_CUT_LEFT)
1028 delete_vertex(mi, left, tp);
1030 add_vtype(left, fc & FC_CUT_FAR ? S_LEFT : S_RIGHT, ltype);
1031 check_vertex(mi, left, tp);
1033 if (fc & FC_CUT_RIGHT)
1034 delete_vertex(mi, right, tp);
1036 add_vtype(right, fc & FC_CUT_FAR ? S_RIGHT : S_LEFT, rtype);
1037 check_vertex(mi, right, tp);
1044 * Add a forced tile to a given forced vertex. Basically an easy job,
1045 * since we know what to add. But it might fail if adding the tile
1046 * would cause some untiled area to become enclosed. There is also another
1047 * more exotic culprit: we might have a dislocation. Fortunately, they
1048 * are very rare (the PRL article reported that perfect tilings of over
1049 * 2^50 tiles had been generated). There is a version of the algorithm
1050 * that doesn't produce dislocations, but it's a lot hairier than the
1051 * simpler version I used.
1054 add_forced_tile(ModeInfo * mi, forced_node_c * node)
1056 tiling_c *tp = &tilings[MI_SCREEN(mi)];
1058 vertex_type_c vtype;
1059 rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1062 if (node->forced_sides == (S_LEFT | S_RIGHT))
1063 side = NRAND(2) ? S_LEFT : S_RIGHT;
1065 side = node->forced_sides;
1066 n = match_rules(node->vertex, hits, True);
1067 n = find_completions(node->vertex, hits, n, side, &vtype /*, True */ );
1070 if (MI_WIN_IS_VERBOSE(mi)) {
1071 (void) fprintf(stderr, "Weirdness in add_forced_tile()\n");
1072 (void) fprintf(stderr, "n = %d\n", n);
1075 return add_tile(mi, node->vertex, side, vtype);
1080 * Whether the addition of a tile of vtype on the given side of vertex
1081 * would conform to the rules. The efficient way to do this would be
1082 * to add the new tile and then use the same type of search as in
1083 * match_rules. However, this function is not a performance
1084 * bottleneck (only needed for random tile additions, which are
1085 * relatively infrequent), so I will settle for a simpler implementation.
1088 legal_move(fringe_node_c * vertex, unsigned side, vertex_type_c vtype)
1090 rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1091 vertex_type_c legal_vt[MAX_COMPL];
1092 int n_hits, n_legal, i;
1094 n_hits = match_rules(vertex, hits, False);
1095 n_legal = find_completions(vertex, hits, n_hits, side, legal_vt /*, False */ );
1096 for (i = 0; i < n_legal; i++)
1097 if (legal_vt[i] == vtype)
1104 * Add a randomly chosen tile to a given vertex. This requires more checking
1105 * as we must make sure the new tile conforms to the vertex rules at every
1106 * vertex it touches. */
1108 add_random_tile(fringe_node_c * vertex, ModeInfo * mi)
1110 fringe_node_c *right, *left, *far;
1111 int i, j, n, n_hits, n_good;
1112 unsigned side, fc, no_good, s;
1113 vertex_type_c vtypes[MAX_COMPL];
1114 rule_match_c hits[MAX_TILES_PER_VERTEX * N_VERTEX_RULES];
1115 tiling_c *tp = &tilings[MI_SCREEN(mi)];
1117 if (MI_NPIXELS(mi) > 2) {
1118 tp->thick_color = NRAND(MI_NPIXELS(mi));
1119 /* Insure good contrast */
1120 tp->thin_color = (NRAND(2 * MI_NPIXELS(mi) / 3) + tp->thick_color +
1121 MI_NPIXELS(mi) / 6) % MI_NPIXELS(mi);
1123 tp->thick_color = tp->thin_color = MI_WIN_WHITE_PIXEL(mi);
1124 n_hits = match_rules(vertex, hits, False);
1125 side = NRAND(2) ? S_LEFT : S_RIGHT;
1126 n = find_completions(vertex, hits, n_hits, side, vtypes /*, False */ );
1127 /* One answer would mean a forced tile. */
1130 if (MI_WIN_IS_VERBOSE(mi)) {
1131 (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1132 (void) fprintf(stderr, "n = %d\n", n);
1137 for (i = 0; i < n; i++) {
1138 fc = fringe_changes(mi, vertex, side, vtypes[i], &right, &far, &left);
1141 if (MI_WIN_IS_VERBOSE(mi)) {
1142 (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1143 (void) fprintf(stderr, "fc = %d, FC_BAG = %d\n", fc, FC_BAG);
1147 s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_LEFT)) ? S_RIGHT : S_LEFT);
1148 if (!legal_move(right, s, VT_RIGHT(vtypes[i]))) {
1149 no_good |= (1 << i);
1155 s = (((fc & FC_CUT_FAR) && (fc & FC_CUT_RIGHT)) ? S_LEFT : S_RIGHT);
1156 if (!legal_move(left, s, VT_LEFT(vtypes[i]))) {
1157 no_good |= (1 << i);
1163 s = ((fc & FC_CUT_LEFT) ? S_RIGHT : S_LEFT);
1164 if (!legal_move(far, s, VT_FAR(vtypes[i]))) {
1165 no_good |= (1 << i);
1172 if (MI_WIN_IS_VERBOSE(mi)) {
1173 (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1174 (void) fprintf(stderr, "n_good = %d\n", n_good);
1178 for (i = j = 0; i <= n; i++, j++)
1179 while (no_good & (1 << j))
1182 i = add_tile(mi, vertex, side, vtypes[j - 1]);
1185 if (MI_WIN_IS_VERBOSE(mi)) {
1186 (void) fprintf(stderr, "Weirdness in add_random_tile()\n");
1187 (void) fprintf(stderr, "i = %d\n", i);
1192 /* One step of the growth algorithm. */
1194 draw_penrose(ModeInfo * mi)
1196 tiling_c *tp = &tilings[MI_SCREEN(mi)];
1198 forced_node_c *p = tp->forced.first;
1200 if (tp->done || tp->failures >= 100) {
1204 /* Check for the initial "2-gon". */
1205 if (tp->fringe.nodes->prev == tp->fringe.nodes->next) {
1206 vertex_type_c vtype = VT_TOTAL_MASK & LRAND();
1208 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
1209 (void) add_tile(mi, tp->fringe.nodes, S_LEFT, vtype);
1212 /* No visible nodes left. */
1213 if (tp->fringe.n_nodes == 0) {
1215 MI_PAUSE(mi) = COMPLETION; /* Just finished drawing */
1218 if (tp->forced.n_visible > 0 && tp->failures < 10) {
1219 n = NRAND(tp->forced.n_visible);
1221 while (p->vertex->off_screen)
1228 } else if (tp->forced.n_nodes > 0) {
1229 n = NRAND(tp->forced.n_nodes);
1233 fringe_node_c *p = tp->fringe.nodes;
1235 n = NRAND(tp->fringe.n_nodes);
1240 } while (p->off_screen);
1241 add_random_tile(p, mi);
1245 if (add_forced_tile(mi, p))
1252 /* Total clean-up. */
1254 release_penrose(ModeInfo * mi)
1256 if (tilings != NULL) {
1259 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1260 tiling_c *tp = &tilings[screen];
1264 (void) free((void *) tilings);