Forgot to set 'has_incentre' on triangular grids, which don't use
[sgt/puzzles] / grid.c
1 /*
2 * (c) Lambros Lambrou 2008
3 *
4 * Code for working with general grids, which can be any planar graph
5 * with faces, edges and vertices (dots). Includes generators for a few
6 * types of grid, including square, hexagonal, triangular and others.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #include <math.h>
15 #include <errno.h>
16
17 #include "puzzles.h"
18 #include "tree234.h"
19 #include "grid.h"
20 #include "penrose.h"
21
22 /* Debugging options */
23
24 /*
25 #define DEBUG_GRID
26 */
27
28 /* ----------------------------------------------------------------------
29 * Deallocate or dereference a grid
30 */
31 void grid_free(grid *g)
32 {
33 assert(g->refcount);
34
35 g->refcount--;
36 if (g->refcount == 0) {
37 int i;
38 for (i = 0; i < g->num_faces; i++) {
39 sfree(g->faces[i].dots);
40 sfree(g->faces[i].edges);
41 }
42 for (i = 0; i < g->num_dots; i++) {
43 sfree(g->dots[i].faces);
44 sfree(g->dots[i].edges);
45 }
46 sfree(g->faces);
47 sfree(g->edges);
48 sfree(g->dots);
49 sfree(g);
50 }
51 }
52
53 /* Used by the other grid generators. Create a brand new grid with nothing
54 * initialised (all lists are NULL) */
55 static grid *grid_empty()
56 {
57 grid *g = snew(grid);
58 g->faces = NULL;
59 g->edges = NULL;
60 g->dots = NULL;
61 g->num_faces = g->num_edges = g->num_dots = 0;
62 g->refcount = 1;
63 g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0;
64 return g;
65 }
66
67 /* Helper function to calculate perpendicular distance from
68 * a point P to a line AB. A and B mustn't be equal here.
69 *
70 * Well-known formula for area A of a triangle:
71 * / 1 1 1 \
72 * 2A = determinant of matrix | px ax bx |
73 * \ py ay by /
74 *
75 * Also well-known: 2A = base * height
76 * = perpendicular distance * line-length.
77 *
78 * Combining gives: distance = determinant / line-length(a,b)
79 */
80 static double point_line_distance(long px, long py,
81 long ax, long ay,
82 long bx, long by)
83 {
84 long det = ax*by - bx*ay + bx*py - px*by + px*ay - ax*py;
85 double len;
86 det = max(det, -det);
87 len = sqrt(SQ(ax - bx) + SQ(ay - by));
88 return det / len;
89 }
90
91 /* Determine nearest edge to where the user clicked.
92 * (x, y) is the clicked location, converted to grid coordinates.
93 * Returns the nearest edge, or NULL if no edge is reasonably
94 * near the position.
95 *
96 * Just judging edges by perpendicular distance is not quite right -
97 * the edge might be "off to one side". So we insist that the triangle
98 * with (x,y) has acute angles at the edge's dots.
99 *
100 * edge1
101 * *---------*------
102 * |
103 * | *(x,y)
104 * edge2 |
105 * | edge2 is OK, but edge1 is not, even though
106 * | edge1 is perpendicularly closer to (x,y)
107 * *
108 *
109 */
110 grid_edge *grid_nearest_edge(grid *g, int x, int y)
111 {
112 grid_edge *best_edge;
113 double best_distance = 0;
114 int i;
115
116 best_edge = NULL;
117
118 for (i = 0; i < g->num_edges; i++) {
119 grid_edge *e = &g->edges[i];
120 long e2; /* squared length of edge */
121 long a2, b2; /* squared lengths of other sides */
122 double dist;
123
124 /* See if edge e is eligible - the triangle must have acute angles
125 * at the edge's dots.
126 * Pythagoras formula h^2 = a^2 + b^2 detects right-angles,
127 * so detect acute angles by testing for h^2 < a^2 + b^2 */
128 e2 = SQ((long)e->dot1->x - (long)e->dot2->x) + SQ((long)e->dot1->y - (long)e->dot2->y);
129 a2 = SQ((long)e->dot1->x - (long)x) + SQ((long)e->dot1->y - (long)y);
130 b2 = SQ((long)e->dot2->x - (long)x) + SQ((long)e->dot2->y - (long)y);
131 if (a2 >= e2 + b2) continue;
132 if (b2 >= e2 + a2) continue;
133
134 /* e is eligible so far. Now check the edge is reasonably close
135 * to where the user clicked. Don't want to toggle an edge if the
136 * click was way off the grid.
137 * There is room for experimentation here. We could check the
138 * perpendicular distance is within a certain fraction of the length
139 * of the edge. That amounts to testing a rectangular region around
140 * the edge.
141 * Alternatively, we could check that the angle at the point is obtuse.
142 * That would amount to testing a circular region with the edge as
143 * diameter. */
144 dist = point_line_distance((long)x, (long)y,
145 (long)e->dot1->x, (long)e->dot1->y,
146 (long)e->dot2->x, (long)e->dot2->y);
147 /* Is dist more than half edge length ? */
148 if (4 * SQ(dist) > e2)
149 continue;
150
151 if (best_edge == NULL || dist < best_distance) {
152 best_edge = e;
153 best_distance = dist;
154 }
155 }
156 return best_edge;
157 }
158
159 /* ----------------------------------------------------------------------
160 * Grid generation
161 */
162
163 #ifdef SVG_GRID
164
165 #define SVG_DOTS 1
166 #define SVG_EDGES 2
167 #define SVG_FACES 4
168
169 #define FACE_COLOUR "red"
170 #define EDGE_COLOUR "blue"
171 #define DOT_COLOUR "black"
172
173 static void grid_output_svg(FILE *fp, grid *g, int which)
174 {
175 int i, j;
176
177 fprintf(fp,"\
178 <?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\
179 <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n\
180 \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n\
181 \n\
182 <svg xmlns=\"http://www.w3.org/2000/svg\"\n\
183 xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n");
184
185 if (which & SVG_FACES) {
186 fprintf(fp, "<g>\n");
187 for (i = 0; i < g->num_faces; i++) {
188 grid_face *f = g->faces + i;
189 fprintf(fp, "<polygon points=\"");
190 for (j = 0; j < f->order; j++) {
191 grid_dot *d = f->dots[j];
192 fprintf(fp, "%s%d,%d", (j == 0) ? "" : " ",
193 d->x, d->y);
194 }
195 fprintf(fp, "\" style=\"fill: %s; fill-opacity: 0.2; stroke: %s\" />\n",
196 FACE_COLOUR, FACE_COLOUR);
197 }
198 fprintf(fp, "</g>\n");
199 }
200 if (which & SVG_EDGES) {
201 fprintf(fp, "<g>\n");
202 for (i = 0; i < g->num_edges; i++) {
203 grid_edge *e = g->edges + i;
204 grid_dot *d1 = e->dot1, *d2 = e->dot2;
205
206 fprintf(fp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" "
207 "style=\"stroke: %s\" />\n",
208 d1->x, d1->y, d2->x, d2->y, EDGE_COLOUR);
209 }
210 fprintf(fp, "</g>\n");
211 }
212
213 if (which & SVG_DOTS) {
214 fprintf(fp, "<g>\n");
215 for (i = 0; i < g->num_dots; i++) {
216 grid_dot *d = g->dots + i;
217 fprintf(fp, "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" fill=\"%s\" />",
218 d->x, d->y, g->tilesize/20, g->tilesize/20, DOT_COLOUR);
219 }
220 fprintf(fp, "</g>\n");
221 }
222
223 fprintf(fp, "</svg>\n");
224 }
225 #endif
226
227 #ifdef SVG_GRID
228 static void grid_try_svg(grid *g, int which)
229 {
230 char *svg = getenv("PUZZLES_SVG_GRID");
231 if (svg) {
232 FILE *svgf = fopen(svg, "w");
233 if (svgf) {
234 grid_output_svg(svgf, g, which);
235 fclose(svgf);
236 } else {
237 fprintf(stderr, "Unable to open file `%s': %s", svg, strerror(errno));
238 }
239 }
240 }
241 #endif
242
243 /* Show the basic grid information, before doing grid_make_consistent */
244 static void grid_debug_basic(grid *g)
245 {
246 /* TODO: Maybe we should generate an SVG image of the dots and lines
247 * of the grid here, before grid_make_consistent.
248 * Would help with debugging grid generation. */
249 #ifdef DEBUG_GRID
250 int i;
251 printf("--- Basic Grid Data ---\n");
252 for (i = 0; i < g->num_faces; i++) {
253 grid_face *f = g->faces + i;
254 printf("Face %d: dots[", i);
255 int j;
256 for (j = 0; j < f->order; j++) {
257 grid_dot *d = f->dots[j];
258 printf("%s%d", j ? "," : "", (int)(d - g->dots));
259 }
260 printf("]\n");
261 }
262 #endif
263 #ifdef SVG_GRID
264 grid_try_svg(g, SVG_FACES);
265 #endif
266 }
267
268 /* Show the derived grid information, computed by grid_make_consistent */
269 static void grid_debug_derived(grid *g)
270 {
271 #ifdef DEBUG_GRID
272 /* edges */
273 int i;
274 printf("--- Derived Grid Data ---\n");
275 for (i = 0; i < g->num_edges; i++) {
276 grid_edge *e = g->edges + i;
277 printf("Edge %d: dots[%d,%d] faces[%d,%d]\n",
278 i, (int)(e->dot1 - g->dots), (int)(e->dot2 - g->dots),
279 e->face1 ? (int)(e->face1 - g->faces) : -1,
280 e->face2 ? (int)(e->face2 - g->faces) : -1);
281 }
282 /* faces */
283 for (i = 0; i < g->num_faces; i++) {
284 grid_face *f = g->faces + i;
285 int j;
286 printf("Face %d: faces[", i);
287 for (j = 0; j < f->order; j++) {
288 grid_edge *e = f->edges[j];
289 grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1;
290 printf("%s%d", j ? "," : "", f2 ? (int)(f2 - g->faces) : -1);
291 }
292 printf("]\n");
293 }
294 /* dots */
295 for (i = 0; i < g->num_dots; i++) {
296 grid_dot *d = g->dots + i;
297 int j;
298 printf("Dot %d: dots[", i);
299 for (j = 0; j < d->order; j++) {
300 grid_edge *e = d->edges[j];
301 grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1;
302 printf("%s%d", j ? "," : "", (int)(d2 - g->dots));
303 }
304 printf("] faces[");
305 for (j = 0; j < d->order; j++) {
306 grid_face *f = d->faces[j];
307 printf("%s%d", j ? "," : "", f ? (int)(f - g->faces) : -1);
308 }
309 printf("]\n");
310 }
311 #endif
312 #ifdef SVG_GRID
313 grid_try_svg(g, SVG_DOTS | SVG_EDGES | SVG_FACES);
314 #endif
315 }
316
317 /* Helper function for building incomplete-edges list in
318 * grid_make_consistent() */
319 static int grid_edge_bydots_cmpfn(void *v1, void *v2)
320 {
321 grid_edge *a = v1;
322 grid_edge *b = v2;
323 grid_dot *da, *db;
324
325 /* Pointer subtraction is valid here, because all dots point into the
326 * same dot-list (g->dots).
327 * Edges are not "normalised" - the 2 dots could be stored in any order,
328 * so we need to take this into account when comparing edges. */
329
330 /* Compare first dots */
331 da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2;
332 db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2;
333 if (da != db)
334 return db - da;
335 /* Compare last dots */
336 da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1;
337 db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1;
338 if (da != db)
339 return db - da;
340
341 return 0;
342 }
343
344 /*
345 * 'Vigorously trim' a grid, by which I mean deleting any isolated or
346 * uninteresting faces. By which, in turn, I mean: ensure that the
347 * grid is composed solely of faces adjacent to at least one
348 * 'landlocked' dot (i.e. one not in contact with the infinite
349 * exterior face), and that all those dots are in a single connected
350 * component.
351 *
352 * This function operates on, and returns, a grid satisfying the
353 * preconditions to grid_make_consistent() rather than the
354 * postconditions. (So call it first.)
355 */
356 static void grid_trim_vigorously(grid *g)
357 {
358 int *dotpairs, *faces, *dots;
359 int *dsf;
360 int i, j, k, size, newfaces, newdots;
361
362 /*
363 * First construct a matrix in which each ordered pair of dots is
364 * mapped to the index of the face in which those dots occur in
365 * that order.
366 */
367 dotpairs = snewn(g->num_dots * g->num_dots, int);
368 for (i = 0; i < g->num_dots; i++)
369 for (j = 0; j < g->num_dots; j++)
370 dotpairs[i*g->num_dots+j] = -1;
371 for (i = 0; i < g->num_faces; i++) {
372 grid_face *f = g->faces + i;
373 int dot0 = f->dots[f->order-1] - g->dots;
374 for (j = 0; j < f->order; j++) {
375 int dot1 = f->dots[j] - g->dots;
376 dotpairs[dot0 * g->num_dots + dot1] = i;
377 dot0 = dot1;
378 }
379 }
380
381 /*
382 * Now we can identify landlocked dots: they're the ones all of
383 * whose edges have a mirror-image counterpart in this matrix.
384 */
385 dots = snewn(g->num_dots, int);
386 for (i = 0; i < g->num_dots; i++) {
387 dots[i] = TRUE;
388 for (j = 0; j < g->num_dots; j++) {
389 if ((dotpairs[i*g->num_dots+j] >= 0) ^
390 (dotpairs[j*g->num_dots+i] >= 0))
391 dots[i] = FALSE; /* non-duplicated edge: coastal dot */
392 }
393 }
394
395 /*
396 * Now identify connected pairs of landlocked dots, and form a dsf
397 * unifying them.
398 */
399 dsf = snew_dsf(g->num_dots);
400 for (i = 0; i < g->num_dots; i++)
401 for (j = 0; j < i; j++)
402 if (dots[i] && dots[j] &&
403 dotpairs[i*g->num_dots+j] >= 0 &&
404 dotpairs[j*g->num_dots+i] >= 0)
405 dsf_merge(dsf, i, j);
406
407 /*
408 * Now look for the largest component.
409 */
410 size = 0;
411 j = -1;
412 for (i = 0; i < g->num_dots; i++) {
413 int newsize;
414 if (dots[i] && dsf_canonify(dsf, i) == i &&
415 (newsize = dsf_size(dsf, i)) > size) {
416 j = i;
417 size = newsize;
418 }
419 }
420
421 /*
422 * Work out which faces we're going to keep (precisely those with
423 * at least one dot in the same connected component as j) and
424 * which dots (those required by any face we're keeping).
425 *
426 * At this point we reuse the 'dots' array to indicate the dots
427 * we're keeping, rather than the ones that are landlocked.
428 */
429 faces = snewn(g->num_faces, int);
430 for (i = 0; i < g->num_faces; i++)
431 faces[i] = 0;
432 for (i = 0; i < g->num_dots; i++)
433 dots[i] = 0;
434 for (i = 0; i < g->num_faces; i++) {
435 grid_face *f = g->faces + i;
436 int keep = FALSE;
437 for (k = 0; k < f->order; k++)
438 if (dsf_canonify(dsf, f->dots[k] - g->dots) == j)
439 keep = TRUE;
440 if (keep) {
441 faces[i] = TRUE;
442 for (k = 0; k < f->order; k++)
443 dots[f->dots[k]-g->dots] = TRUE;
444 }
445 }
446
447 /*
448 * Work out the new indices of those faces and dots, when we
449 * compact the arrays containing them.
450 */
451 for (i = newfaces = 0; i < g->num_faces; i++)
452 faces[i] = (faces[i] ? newfaces++ : -1);
453 for (i = newdots = 0; i < g->num_dots; i++)
454 dots[i] = (dots[i] ? newdots++ : -1);
455
456 /*
457 * Go through and compact the arrays.
458 */
459 for (i = 0; i < g->num_dots; i++)
460 if (dots[i] >= 0) {
461 grid_dot *dnew = g->dots + dots[i], *dold = g->dots + i;
462 *dnew = *dold; /* structure copy */
463 }
464 for (i = 0; i < g->num_faces; i++)
465 if (faces[i] >= 0) {
466 grid_face *fnew = g->faces + faces[i], *fold = g->faces + i;
467 *fnew = *fold; /* structure copy */
468 for (j = 0; j < fnew->order; j++) {
469 /*
470 * Reindex the dots in this face.
471 */
472 k = fnew->dots[j] - g->dots;
473 fnew->dots[j] = g->dots + dots[k];
474 }
475 }
476 g->num_faces = newfaces;
477 g->num_dots = newdots;
478
479 sfree(dotpairs);
480 sfree(dsf);
481 sfree(dots);
482 sfree(faces);
483 }
484
485 /* Input: grid has its dots and faces initialised:
486 * - dots have (optionally) x and y coordinates, but no edges or faces
487 * (pointers are NULL).
488 * - edges not initialised at all
489 * - faces initialised and know which dots they have (but no edges yet). The
490 * dots around each face are assumed to be clockwise.
491 *
492 * Output: grid is complete and valid with all relationships defined.
493 */
494 static void grid_make_consistent(grid *g)
495 {
496 int i;
497 tree234 *incomplete_edges;
498 grid_edge *next_new_edge; /* Where new edge will go into g->edges */
499
500 grid_debug_basic(g);
501
502 /* ====== Stage 1 ======
503 * Generate edges
504 */
505
506 /* We know how many dots and faces there are, so we can find the exact
507 * number of edges from Euler's polyhedral formula: F + V = E + 2 .
508 * We use "-1", not "-2" here, because Euler's formula includes the
509 * infinite face, which we don't count. */
510 g->num_edges = g->num_faces + g->num_dots - 1;
511 g->edges = snewn(g->num_edges, grid_edge);
512 next_new_edge = g->edges;
513
514 /* Iterate over faces, and over each face's dots, generating edges as we
515 * go. As we find each new edge, we can immediately fill in the edge's
516 * dots, but only one of the edge's faces. Later on in the iteration, we
517 * will find the same edge again (unless it's on the border), but we will
518 * know the other face.
519 * For efficiency, maintain a list of the incomplete edges, sorted by
520 * their dots. */
521 incomplete_edges = newtree234(grid_edge_bydots_cmpfn);
522 for (i = 0; i < g->num_faces; i++) {
523 grid_face *f = g->faces + i;
524 int j;
525 for (j = 0; j < f->order; j++) {
526 grid_edge e; /* fake edge for searching */
527 grid_edge *edge_found;
528 int j2 = j + 1;
529 if (j2 == f->order)
530 j2 = 0;
531 e.dot1 = f->dots[j];
532 e.dot2 = f->dots[j2];
533 /* Use del234 instead of find234, because we always want to
534 * remove the edge if found */
535 edge_found = del234(incomplete_edges, &e);
536 if (edge_found) {
537 /* This edge already added, so fill out missing face.
538 * Edge is already removed from incomplete_edges. */
539 edge_found->face2 = f;
540 } else {
541 assert(next_new_edge - g->edges < g->num_edges);
542 next_new_edge->dot1 = e.dot1;
543 next_new_edge->dot2 = e.dot2;
544 next_new_edge->face1 = f;
545 next_new_edge->face2 = NULL; /* potentially infinite face */
546 add234(incomplete_edges, next_new_edge);
547 ++next_new_edge;
548 }
549 }
550 }
551 freetree234(incomplete_edges);
552
553 /* ====== Stage 2 ======
554 * For each face, build its edge list.
555 */
556
557 /* Allocate space for each edge list. Can do this, because each face's
558 * edge-list is the same size as its dot-list. */
559 for (i = 0; i < g->num_faces; i++) {
560 grid_face *f = g->faces + i;
561 int j;
562 f->edges = snewn(f->order, grid_edge*);
563 /* Preload with NULLs, to help detect potential bugs. */
564 for (j = 0; j < f->order; j++)
565 f->edges[j] = NULL;
566 }
567
568 /* Iterate over each edge, and over both its faces. Add this edge to
569 * the face's edge-list, after finding where it should go in the
570 * sequence. */
571 for (i = 0; i < g->num_edges; i++) {
572 grid_edge *e = g->edges + i;
573 int j;
574 for (j = 0; j < 2; j++) {
575 grid_face *f = j ? e->face2 : e->face1;
576 int k, k2;
577 if (f == NULL) continue;
578 /* Find one of the dots around the face */
579 for (k = 0; k < f->order; k++) {
580 if (f->dots[k] == e->dot1)
581 break; /* found dot1 */
582 }
583 assert(k != f->order); /* Must find the dot around this face */
584
585 /* Labelling scheme: as we walk clockwise around the face,
586 * starting at dot0 (f->dots[0]), we hit:
587 * (dot0), edge0, dot1, edge1, dot2,...
588 *
589 * 0
590 * 0-----1
591 * |
592 * |1
593 * |
594 * 3-----2
595 * 2
596 *
597 * Therefore, edgeK joins dotK and dot{K+1}
598 */
599
600 /* Around this face, either the next dot or the previous dot
601 * must be e->dot2. Otherwise the edge is wrong. */
602 k2 = k + 1;
603 if (k2 == f->order)
604 k2 = 0;
605 if (f->dots[k2] == e->dot2) {
606 /* dot1(k) and dot2(k2) go clockwise around this face, so add
607 * this edge at position k (see diagram). */
608 assert(f->edges[k] == NULL);
609 f->edges[k] = e;
610 continue;
611 }
612 /* Try previous dot */
613 k2 = k - 1;
614 if (k2 == -1)
615 k2 = f->order - 1;
616 if (f->dots[k2] == e->dot2) {
617 /* dot1(k) and dot2(k2) go anticlockwise around this face. */
618 assert(f->edges[k2] == NULL);
619 f->edges[k2] = e;
620 continue;
621 }
622 assert(!"Grid broken: bad edge-face relationship");
623 }
624 }
625
626 /* ====== Stage 3 ======
627 * For each dot, build its edge-list and face-list.
628 */
629
630 /* We don't know how many edges/faces go around each dot, so we can't
631 * allocate the right space for these lists. Pre-compute the sizes by
632 * iterating over each edge and recording a tally against each dot. */
633 for (i = 0; i < g->num_dots; i++) {
634 g->dots[i].order = 0;
635 }
636 for (i = 0; i < g->num_edges; i++) {
637 grid_edge *e = g->edges + i;
638 ++(e->dot1->order);
639 ++(e->dot2->order);
640 }
641 /* Now we have the sizes, pre-allocate the edge and face lists. */
642 for (i = 0; i < g->num_dots; i++) {
643 grid_dot *d = g->dots + i;
644 int j;
645 assert(d->order >= 2); /* sanity check */
646 d->edges = snewn(d->order, grid_edge*);
647 d->faces = snewn(d->order, grid_face*);
648 for (j = 0; j < d->order; j++) {
649 d->edges[j] = NULL;
650 d->faces[j] = NULL;
651 }
652 }
653 /* For each dot, need to find a face that touches it, so we can seed
654 * the edge-face-edge-face process around each dot. */
655 for (i = 0; i < g->num_faces; i++) {
656 grid_face *f = g->faces + i;
657 int j;
658 for (j = 0; j < f->order; j++) {
659 grid_dot *d = f->dots[j];
660 d->faces[0] = f;
661 }
662 }
663 /* Each dot now has a face in its first slot. Generate the remaining
664 * faces and edges around the dot, by searching both clockwise and
665 * anticlockwise from the first face. Need to do both directions,
666 * because of the possibility of hitting the infinite face, which
667 * blocks progress. But there's only one such face, so we will
668 * succeed in finding every edge and face this way. */
669 for (i = 0; i < g->num_dots; i++) {
670 grid_dot *d = g->dots + i;
671 int current_face1 = 0; /* ascends clockwise */
672 int current_face2 = 0; /* descends anticlockwise */
673
674 /* Labelling scheme: as we walk clockwise around the dot, starting
675 * at face0 (d->faces[0]), we hit:
676 * (face0), edge0, face1, edge1, face2,...
677 *
678 * 0
679 * |
680 * 0 | 1
681 * |
682 * -----d-----1
683 * |
684 * | 2
685 * |
686 * 2
687 *
688 * So, for example, face1 should be joined to edge0 and edge1,
689 * and those edges should appear in an anticlockwise sense around
690 * that face (see diagram). */
691
692 /* clockwise search */
693 while (TRUE) {
694 grid_face *f = d->faces[current_face1];
695 grid_edge *e;
696 int j;
697 assert(f != NULL);
698 /* find dot around this face */
699 for (j = 0; j < f->order; j++) {
700 if (f->dots[j] == d)
701 break;
702 }
703 assert(j != f->order); /* must find dot */
704
705 /* Around f, required edge is anticlockwise from the dot. See
706 * the other labelling scheme higher up, for why we subtract 1
707 * from j. */
708 j--;
709 if (j == -1)
710 j = f->order - 1;
711 e = f->edges[j];
712 d->edges[current_face1] = e; /* set edge */
713 current_face1++;
714 if (current_face1 == d->order)
715 break;
716 else {
717 /* set face */
718 d->faces[current_face1] =
719 (e->face1 == f) ? e->face2 : e->face1;
720 if (d->faces[current_face1] == NULL)
721 break; /* cannot progress beyond infinite face */
722 }
723 }
724 /* If the clockwise search made it all the way round, don't need to
725 * bother with the anticlockwise search. */
726 if (current_face1 == d->order)
727 continue; /* this dot is complete, move on to next dot */
728
729 /* anticlockwise search */
730 while (TRUE) {
731 grid_face *f = d->faces[current_face2];
732 grid_edge *e;
733 int j;
734 assert(f != NULL);
735 /* find dot around this face */
736 for (j = 0; j < f->order; j++) {
737 if (f->dots[j] == d)
738 break;
739 }
740 assert(j != f->order); /* must find dot */
741
742 /* Around f, required edge is clockwise from the dot. */
743 e = f->edges[j];
744
745 current_face2--;
746 if (current_face2 == -1)
747 current_face2 = d->order - 1;
748 d->edges[current_face2] = e; /* set edge */
749
750 /* set face */
751 if (current_face2 == current_face1)
752 break;
753 d->faces[current_face2] =
754 (e->face1 == f) ? e->face2 : e->face1;
755 /* There's only 1 infinite face, so we must get all the way
756 * to current_face1 before we hit it. */
757 assert(d->faces[current_face2]);
758 }
759 }
760
761 /* ====== Stage 4 ======
762 * Compute other grid settings
763 */
764
765 /* Bounding rectangle */
766 for (i = 0; i < g->num_dots; i++) {
767 grid_dot *d = g->dots + i;
768 if (i == 0) {
769 g->lowest_x = g->highest_x = d->x;
770 g->lowest_y = g->highest_y = d->y;
771 } else {
772 g->lowest_x = min(g->lowest_x, d->x);
773 g->highest_x = max(g->highest_x, d->x);
774 g->lowest_y = min(g->lowest_y, d->y);
775 g->highest_y = max(g->highest_y, d->y);
776 }
777 }
778
779 grid_debug_derived(g);
780 }
781
782 /* Helpers for making grid-generation easier. These functions are only
783 * intended for use during grid generation. */
784
785 /* Comparison function for the (tree234) sorted dot list */
786 static int grid_point_cmp_fn(void *v1, void *v2)
787 {
788 grid_dot *p1 = v1;
789 grid_dot *p2 = v2;
790 if (p1->y != p2->y)
791 return p2->y - p1->y;
792 else
793 return p2->x - p1->x;
794 }
795 /* Add a new face to the grid, with its dot list allocated.
796 * Assumes there's enough space allocated for the new face in grid->faces */
797 static void grid_face_add_new(grid *g, int face_size)
798 {
799 int i;
800 grid_face *new_face = g->faces + g->num_faces;
801 new_face->order = face_size;
802 new_face->dots = snewn(face_size, grid_dot*);
803 for (i = 0; i < face_size; i++)
804 new_face->dots[i] = NULL;
805 new_face->edges = NULL;
806 new_face->has_incentre = FALSE;
807 g->num_faces++;
808 }
809 /* Assumes dot list has enough space */
810 static grid_dot *grid_dot_add_new(grid *g, int x, int y)
811 {
812 grid_dot *new_dot = g->dots + g->num_dots;
813 new_dot->order = 0;
814 new_dot->edges = NULL;
815 new_dot->faces = NULL;
816 new_dot->x = x;
817 new_dot->y = y;
818 g->num_dots++;
819 return new_dot;
820 }
821 /* Retrieve a dot with these (x,y) coordinates. Either return an existing dot
822 * in the dot_list, or add a new dot to the grid (and the dot_list) and
823 * return that.
824 * Assumes g->dots has enough capacity allocated */
825 static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y)
826 {
827 grid_dot test, *ret;
828
829 test.order = 0;
830 test.edges = NULL;
831 test.faces = NULL;
832 test.x = x;
833 test.y = y;
834 ret = find234(dot_list, &test, NULL);
835 if (ret)
836 return ret;
837
838 ret = grid_dot_add_new(g, x, y);
839 add234(dot_list, ret);
840 return ret;
841 }
842
843 /* Sets the last face of the grid to include this dot, at this position
844 * around the face. Assumes num_faces is at least 1 (a new face has
845 * previously been added, with the required number of dots allocated) */
846 static void grid_face_set_dot(grid *g, grid_dot *d, int position)
847 {
848 grid_face *last_face = g->faces + g->num_faces - 1;
849 last_face->dots[position] = d;
850 }
851
852 /*
853 * Helper routines for grid_find_incentre.
854 */
855 static int solve_2x2_matrix(double mx[4], double vin[2], double vout[2])
856 {
857 double inv[4];
858 double det;
859 det = (mx[0]*mx[3] - mx[1]*mx[2]);
860 if (det == 0)
861 return FALSE;
862
863 inv[0] = mx[3] / det;
864 inv[1] = -mx[1] / det;
865 inv[2] = -mx[2] / det;
866 inv[3] = mx[0] / det;
867
868 vout[0] = inv[0]*vin[0] + inv[1]*vin[1];
869 vout[1] = inv[2]*vin[0] + inv[3]*vin[1];
870
871 return TRUE;
872 }
873 static int solve_3x3_matrix(double mx[9], double vin[3], double vout[3])
874 {
875 double inv[9];
876 double det;
877
878 det = (mx[0]*mx[4]*mx[8] + mx[1]*mx[5]*mx[6] + mx[2]*mx[3]*mx[7] -
879 mx[0]*mx[5]*mx[7] - mx[1]*mx[3]*mx[8] - mx[2]*mx[4]*mx[6]);
880 if (det == 0)
881 return FALSE;
882
883 inv[0] = (mx[4]*mx[8] - mx[5]*mx[7]) / det;
884 inv[1] = (mx[2]*mx[7] - mx[1]*mx[8]) / det;
885 inv[2] = (mx[1]*mx[5] - mx[2]*mx[4]) / det;
886 inv[3] = (mx[5]*mx[6] - mx[3]*mx[8]) / det;
887 inv[4] = (mx[0]*mx[8] - mx[2]*mx[6]) / det;
888 inv[5] = (mx[2]*mx[3] - mx[0]*mx[5]) / det;
889 inv[6] = (mx[3]*mx[7] - mx[4]*mx[6]) / det;
890 inv[7] = (mx[1]*mx[6] - mx[0]*mx[7]) / det;
891 inv[8] = (mx[0]*mx[4] - mx[1]*mx[3]) / det;
892
893 vout[0] = inv[0]*vin[0] + inv[1]*vin[1] + inv[2]*vin[2];
894 vout[1] = inv[3]*vin[0] + inv[4]*vin[1] + inv[5]*vin[2];
895 vout[2] = inv[6]*vin[0] + inv[7]*vin[1] + inv[8]*vin[2];
896
897 return TRUE;
898 }
899
900 void grid_find_incentre(grid_face *f)
901 {
902 double xbest, ybest, bestdist;
903 int i, j, k, m;
904 grid_dot *edgedot1[3], *edgedot2[3];
905 grid_dot *dots[3];
906 int nedges, ndots;
907
908 if (f->has_incentre)
909 return;
910
911 /*
912 * Find the point in the polygon with the maximum distance to any
913 * edge or corner.
914 *
915 * Such a point must exist which is in contact with at least three
916 * edges and/or vertices. (Proof: if it's only in contact with two
917 * edges and/or vertices, it can't even be at a _local_ maximum -
918 * any such circle can always be expanded in some direction.) So
919 * we iterate through all 3-subsets of the combined set of edges
920 * and vertices; for each subset we generate one or two candidate
921 * points that might be the incentre, and then we vet each one to
922 * see if it's inside the polygon and what its maximum radius is.
923 *
924 * (There's one case which this algorithm will get noticeably
925 * wrong, and that's when a continuum of equally good answers
926 * exists due to parallel edges. Consider a long thin rectangle,
927 * for instance, or a parallelogram. This algorithm will pick a
928 * point near one end, and choose the end arbitrarily; obviously a
929 * nicer point to choose would be in the centre. To fix this I
930 * would have to introduce a special-case system which detected
931 * parallel edges in advance, set aside all candidate points
932 * generated using both edges in a parallel pair, and generated
933 * some additional candidate points half way between them. Also,
934 * of course, I'd have to cope with rounding error making such a
935 * point look worse than one of its endpoints. So I haven't done
936 * this for the moment, and will cross it if necessary when I come
937 * to it.)
938 *
939 * We don't actually iterate literally over _edges_, in the sense
940 * of grid_edge structures. Instead, we fill in edgedot1[] and
941 * edgedot2[] with a pair of dots adjacent in the face's list of
942 * vertices. This ensures that we get the edges in consistent
943 * orientation, which we could not do from the grid structure
944 * alone. (A moment's consideration of an order-3 vertex should
945 * make it clear that if a notional arrow was written on each
946 * edge, _at least one_ of the three faces bordering that vertex
947 * would have to have the two arrows tip-to-tip or tail-to-tail
948 * rather than tip-to-tail.)
949 */
950 nedges = ndots = 0;
951 bestdist = 0;
952 xbest = ybest = 0;
953
954 for (i = 0; i+2 < 2*f->order; i++) {
955 if (i < f->order) {
956 edgedot1[nedges] = f->dots[i];
957 edgedot2[nedges++] = f->dots[(i+1)%f->order];
958 } else
959 dots[ndots++] = f->dots[i - f->order];
960
961 for (j = i+1; j+1 < 2*f->order; j++) {
962 if (j < f->order) {
963 edgedot1[nedges] = f->dots[j];
964 edgedot2[nedges++] = f->dots[(j+1)%f->order];
965 } else
966 dots[ndots++] = f->dots[j - f->order];
967
968 for (k = j+1; k < 2*f->order; k++) {
969 double cx[2], cy[2]; /* candidate positions */
970 int cn = 0; /* number of candidates */
971
972 if (k < f->order) {
973 edgedot1[nedges] = f->dots[k];
974 edgedot2[nedges++] = f->dots[(k+1)%f->order];
975 } else
976 dots[ndots++] = f->dots[k - f->order];
977
978 /*
979 * Find a point, or pair of points, equidistant from
980 * all the specified edges and/or vertices.
981 */
982 if (nedges == 3) {
983 /*
984 * Three edges. This is a linear matrix equation:
985 * each row of the matrix represents the fact that
986 * the point (x,y) we seek is at distance r from
987 * that edge, and we solve three of those
988 * simultaneously to obtain x,y,r. (We ignore r.)
989 */
990 double matrix[9], vector[3], vector2[3];
991 int m;
992
993 for (m = 0; m < 3; m++) {
994 int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x;
995 int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y;
996 int dx = x2-x1, dy = y2-y1;
997
998 /*
999 * ((x,y) - (x1,y1)) . (dy,-dx) = r |(dx,dy)|
1000 *
1001 * => x dy - y dx - r |(dx,dy)| = (x1 dy - y1 dx)
1002 */
1003 matrix[3*m+0] = dy;
1004 matrix[3*m+1] = -dx;
1005 matrix[3*m+2] = -sqrt((double)dx*dx+(double)dy*dy);
1006 vector[m] = (double)x1*dy - (double)y1*dx;
1007 }
1008
1009 if (solve_3x3_matrix(matrix, vector, vector2)) {
1010 cx[cn] = vector2[0];
1011 cy[cn] = vector2[1];
1012 cn++;
1013 }
1014 } else if (nedges == 2) {
1015 /*
1016 * Two edges and a dot. This will end up in a
1017 * quadratic equation.
1018 *
1019 * First, look at the two edges. Having our point
1020 * be some distance r from both of them gives rise
1021 * to a pair of linear equations in x,y,r of the
1022 * form
1023 *
1024 * (x-x1) dy - (y-y1) dx = r sqrt(dx^2+dy^2)
1025 *
1026 * We eliminate r between those equations to give
1027 * us a single linear equation in x,y describing
1028 * the locus of points equidistant from both lines
1029 * - i.e. the angle bisector.
1030 *
1031 * We then choose one of x,y to be a parameter t,
1032 * and derive linear formulae for x,y,r in terms
1033 * of t. This enables us to write down the
1034 * circular equation (x-xd)^2+(y-yd)^2=r^2 as a
1035 * quadratic in t; solving that and substituting
1036 * in for x,y gives us two candidate points.
1037 */
1038 double eqs[2][4]; /* a,b,c,d : ax+by+cr=d */
1039 double eq[3]; /* a,b,c: ax+by=c */
1040 double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */
1041 double q[3]; /* a,b,c: at^2+bt+c=0 */
1042 double disc;
1043
1044 /* Find equations of the two input lines. */
1045 for (m = 0; m < 2; m++) {
1046 int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x;
1047 int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y;
1048 int dx = x2-x1, dy = y2-y1;
1049
1050 eqs[m][0] = dy;
1051 eqs[m][1] = -dx;
1052 eqs[m][2] = -sqrt(dx*dx+dy*dy);
1053 eqs[m][3] = x1*dy - y1*dx;
1054 }
1055
1056 /* Derive the angle bisector by eliminating r. */
1057 eq[0] = eqs[0][0]*eqs[1][2] - eqs[1][0]*eqs[0][2];
1058 eq[1] = eqs[0][1]*eqs[1][2] - eqs[1][1]*eqs[0][2];
1059 eq[2] = eqs[0][3]*eqs[1][2] - eqs[1][3]*eqs[0][2];
1060
1061 /* Parametrise x and y in terms of some t. */
1062 if (abs(eq[0]) < abs(eq[1])) {
1063 /* Parameter is x. */
1064 xt[0] = 1; xt[1] = 0;
1065 yt[0] = -eq[0]/eq[1]; yt[1] = eq[2]/eq[1];
1066 } else {
1067 /* Parameter is y. */
1068 yt[0] = 1; yt[1] = 0;
1069 xt[0] = -eq[1]/eq[0]; xt[1] = eq[2]/eq[0];
1070 }
1071
1072 /* Find a linear representation of r using eqs[0]. */
1073 rt[0] = -(eqs[0][0]*xt[0] + eqs[0][1]*yt[0])/eqs[0][2];
1074 rt[1] = (eqs[0][3] - eqs[0][0]*xt[1] -
1075 eqs[0][1]*yt[1])/eqs[0][2];
1076
1077 /* Construct the quadratic equation. */
1078 q[0] = -rt[0]*rt[0];
1079 q[1] = -2*rt[0]*rt[1];
1080 q[2] = -rt[1]*rt[1];
1081 q[0] += xt[0]*xt[0];
1082 q[1] += 2*xt[0]*(xt[1]-dots[0]->x);
1083 q[2] += (xt[1]-dots[0]->x)*(xt[1]-dots[0]->x);
1084 q[0] += yt[0]*yt[0];
1085 q[1] += 2*yt[0]*(yt[1]-dots[0]->y);
1086 q[2] += (yt[1]-dots[0]->y)*(yt[1]-dots[0]->y);
1087
1088 /* And solve it. */
1089 disc = q[1]*q[1] - 4*q[0]*q[2];
1090 if (disc >= 0) {
1091 double t;
1092
1093 disc = sqrt(disc);
1094
1095 t = (-q[1] + disc) / (2*q[0]);
1096 cx[cn] = xt[0]*t + xt[1];
1097 cy[cn] = yt[0]*t + yt[1];
1098 cn++;
1099
1100 t = (-q[1] - disc) / (2*q[0]);
1101 cx[cn] = xt[0]*t + xt[1];
1102 cy[cn] = yt[0]*t + yt[1];
1103 cn++;
1104 }
1105 } else if (nedges == 1) {
1106 /*
1107 * Two dots and an edge. This one's another
1108 * quadratic equation.
1109 *
1110 * The point we want must lie on the perpendicular
1111 * bisector of the two dots; that much is obvious.
1112 * So we can construct a parametrisation of that
1113 * bisecting line, giving linear formulae for x,y
1114 * in terms of t. We can also express the distance
1115 * from the edge as such a linear formula.
1116 *
1117 * Then we set that equal to the radius of the
1118 * circle passing through the two points, which is
1119 * a Pythagoras exercise; that gives rise to a
1120 * quadratic in t, which we solve.
1121 */
1122 double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */
1123 double q[3]; /* a,b,c: at^2+bt+c=0 */
1124 double disc;
1125 double halfsep;
1126
1127 /* Find parametric formulae for x,y. */
1128 {
1129 int x1 = dots[0]->x, x2 = dots[1]->x;
1130 int y1 = dots[0]->y, y2 = dots[1]->y;
1131 int dx = x2-x1, dy = y2-y1;
1132 double d = sqrt((double)dx*dx + (double)dy*dy);
1133
1134 xt[1] = (x1+x2)/2.0;
1135 yt[1] = (y1+y2)/2.0;
1136 /* It's convenient if we have t at standard scale. */
1137 xt[0] = -dy/d;
1138 yt[0] = dx/d;
1139
1140 /* Also note down half the separation between
1141 * the dots, for use in computing the circle radius. */
1142 halfsep = 0.5*d;
1143 }
1144
1145 /* Find a parametric formula for r. */
1146 {
1147 int x1 = edgedot1[0]->x, x2 = edgedot2[0]->x;
1148 int y1 = edgedot1[0]->y, y2 = edgedot2[0]->y;
1149 int dx = x2-x1, dy = y2-y1;
1150 double d = sqrt((double)dx*dx + (double)dy*dy);
1151 rt[0] = (xt[0]*dy - yt[0]*dx) / d;
1152 rt[1] = ((xt[1]-x1)*dy - (yt[1]-y1)*dx) / d;
1153 }
1154
1155 /* Construct the quadratic equation. */
1156 q[0] = rt[0]*rt[0];
1157 q[1] = 2*rt[0]*rt[1];
1158 q[2] = rt[1]*rt[1];
1159 q[0] -= 1;
1160 q[2] -= halfsep*halfsep;
1161
1162 /* And solve it. */
1163 disc = q[1]*q[1] - 4*q[0]*q[2];
1164 if (disc >= 0) {
1165 double t;
1166
1167 disc = sqrt(disc);
1168
1169 t = (-q[1] + disc) / (2*q[0]);
1170 cx[cn] = xt[0]*t + xt[1];
1171 cy[cn] = yt[0]*t + yt[1];
1172 cn++;
1173
1174 t = (-q[1] - disc) / (2*q[0]);
1175 cx[cn] = xt[0]*t + xt[1];
1176 cy[cn] = yt[0]*t + yt[1];
1177 cn++;
1178 }
1179 } else if (nedges == 0) {
1180 /*
1181 * Three dots. This is another linear matrix
1182 * equation, this time with each row of the matrix
1183 * representing the perpendicular bisector between
1184 * two of the points. Of course we only need two
1185 * such lines to find their intersection, so we
1186 * need only solve a 2x2 matrix equation.
1187 */
1188
1189 double matrix[4], vector[2], vector2[2];
1190 int m;
1191
1192 for (m = 0; m < 2; m++) {
1193 int x1 = dots[m]->x, x2 = dots[m+1]->x;
1194 int y1 = dots[m]->y, y2 = dots[m+1]->y;
1195 int dx = x2-x1, dy = y2-y1;
1196
1197 /*
1198 * ((x,y) - (x1,y1)) . (dx,dy) = 1/2 |(dx,dy)|^2
1199 *
1200 * => 2x dx + 2y dy = dx^2+dy^2 + (2 x1 dx + 2 y1 dy)
1201 */
1202 matrix[2*m+0] = 2*dx;
1203 matrix[2*m+1] = 2*dy;
1204 vector[m] = ((double)dx*dx + (double)dy*dy +
1205 2.0*x1*dx + 2.0*y1*dy);
1206 }
1207
1208 if (solve_2x2_matrix(matrix, vector, vector2)) {
1209 cx[cn] = vector2[0];
1210 cy[cn] = vector2[1];
1211 cn++;
1212 }
1213 }
1214
1215 /*
1216 * Now go through our candidate points and see if any
1217 * of them are better than what we've got so far.
1218 */
1219 for (m = 0; m < cn; m++) {
1220 double x = cx[m], y = cy[m];
1221
1222 /*
1223 * First, disqualify the point if it's not inside
1224 * the polygon, which we work out by counting the
1225 * edges to the right of the point. (For
1226 * tiebreaking purposes when edges start or end on
1227 * our y-coordinate or go right through it, we
1228 * consider our point to be offset by a small
1229 * _positive_ epsilon in both the x- and
1230 * y-direction.)
1231 */
1232 int e, in = 0;
1233 for (e = 0; e < f->order; e++) {
1234 int xs = f->edges[e]->dot1->x;
1235 int xe = f->edges[e]->dot2->x;
1236 int ys = f->edges[e]->dot1->y;
1237 int ye = f->edges[e]->dot2->y;
1238 if ((y >= ys && y < ye) || (y >= ye && y < ys)) {
1239 /*
1240 * The line goes past our y-position. Now we need
1241 * to know if its x-coordinate when it does so is
1242 * to our right.
1243 *
1244 * The x-coordinate in question is mathematically
1245 * (y - ys) * (xe - xs) / (ye - ys), and we want
1246 * to know whether (x - xs) >= that. Of course we
1247 * avoid the division, so we can work in integers;
1248 * to do this we must multiply both sides of the
1249 * inequality by ye - ys, which means we must
1250 * first check that's not negative.
1251 */
1252 int num = xe - xs, denom = ye - ys;
1253 if (denom < 0) {
1254 num = -num;
1255 denom = -denom;
1256 }
1257 if ((x - xs) * denom >= (y - ys) * num)
1258 in ^= 1;
1259 }
1260 }
1261
1262 if (in) {
1263 double mindist = HUGE_VAL;
1264 int e, d;
1265
1266 /*
1267 * This point is inside the polygon, so now we check
1268 * its minimum distance to every edge and corner.
1269 * First the corners ...
1270 */
1271 for (d = 0; d < f->order; d++) {
1272 int xp = f->dots[d]->x;
1273 int yp = f->dots[d]->y;
1274 double dx = x - xp, dy = y - yp;
1275 double dist = dx*dx + dy*dy;
1276 if (mindist > dist)
1277 mindist = dist;
1278 }
1279
1280 /*
1281 * ... and now also check the perpendicular distance
1282 * to every edge, if the perpendicular lies between
1283 * the edge's endpoints.
1284 */
1285 for (e = 0; e < f->order; e++) {
1286 int xs = f->edges[e]->dot1->x;
1287 int xe = f->edges[e]->dot2->x;
1288 int ys = f->edges[e]->dot1->y;
1289 int ye = f->edges[e]->dot2->y;
1290
1291 /*
1292 * If s and e are our endpoints, and p our
1293 * candidate circle centre, the foot of a
1294 * perpendicular from p to the line se lies
1295 * between s and e if and only if (p-s).(e-s) lies
1296 * strictly between 0 and (e-s).(e-s).
1297 */
1298 int edx = xe - xs, edy = ye - ys;
1299 double pdx = x - xs, pdy = y - ys;
1300 double pde = pdx * edx + pdy * edy;
1301 long ede = (long)edx * edx + (long)edy * edy;
1302 if (0 < pde && pde < ede) {
1303 /*
1304 * Yes, the nearest point on this edge is
1305 * closer than either endpoint, so we must
1306 * take it into account by measuring the
1307 * perpendicular distance to the edge and
1308 * checking its square against mindist.
1309 */
1310
1311 double pdre = pdx * edy - pdy * edx;
1312 double sqlen = pdre * pdre / ede;
1313
1314 if (mindist > sqlen)
1315 mindist = sqlen;
1316 }
1317 }
1318
1319 /*
1320 * Right. Now we know the biggest circle around this
1321 * point, so we can check it against bestdist.
1322 */
1323 if (bestdist < mindist) {
1324 bestdist = mindist;
1325 xbest = x;
1326 ybest = y;
1327 }
1328 }
1329 }
1330
1331 if (k < f->order)
1332 nedges--;
1333 else
1334 ndots--;
1335 }
1336 if (j < f->order)
1337 nedges--;
1338 else
1339 ndots--;
1340 }
1341 if (i < f->order)
1342 nedges--;
1343 else
1344 ndots--;
1345 }
1346
1347 assert(bestdist > 0);
1348
1349 f->has_incentre = TRUE;
1350 f->ix = xbest + 0.5; /* round to nearest */
1351 f->iy = ybest + 0.5;
1352 }
1353
1354 /* ------ Generate various types of grid ------ */
1355
1356 /* General method is to generate faces, by calculating their dot coordinates.
1357 * As new faces are added, we keep track of all the dots so we can tell when
1358 * a new face reuses an existing dot. For example, two squares touching at an
1359 * edge would generate six unique dots: four dots from the first face, then
1360 * two additional dots for the second face, because we detect the other two
1361 * dots have already been taken up. This list is stored in a tree234
1362 * called "points". No extra memory-allocation needed here - we store the
1363 * actual grid_dot* pointers, which all point into the g->dots list.
1364 * For this reason, we have to calculate coordinates in such a way as to
1365 * eliminate any rounding errors, so we can detect when a dot on one
1366 * face precisely lands on a dot of a different face. No floating-point
1367 * arithmetic here!
1368 */
1369
1370 #define SQUARE_TILESIZE 20
1371
1372 void grid_size_square(int width, int height,
1373 int *tilesize, int *xextent, int *yextent)
1374 {
1375 int a = SQUARE_TILESIZE;
1376
1377 *tilesize = a;
1378 *xextent = width * a;
1379 *yextent = height * a;
1380 }
1381
1382 grid *grid_new_square(int width, int height, char *desc)
1383 {
1384 int x, y;
1385 /* Side length */
1386 int a = SQUARE_TILESIZE;
1387
1388 /* Upper bounds - don't have to be exact */
1389 int max_faces = width * height;
1390 int max_dots = (width + 1) * (height + 1);
1391
1392 tree234 *points;
1393
1394 grid *g = grid_empty();
1395 g->tilesize = a;
1396 g->faces = snewn(max_faces, grid_face);
1397 g->dots = snewn(max_dots, grid_dot);
1398
1399 points = newtree234(grid_point_cmp_fn);
1400
1401 /* generate square faces */
1402 for (y = 0; y < height; y++) {
1403 for (x = 0; x < width; x++) {
1404 grid_dot *d;
1405 /* face position */
1406 int px = a * x;
1407 int py = a * y;
1408
1409 grid_face_add_new(g, 4);
1410 d = grid_get_dot(g, points, px, py);
1411 grid_face_set_dot(g, d, 0);
1412 d = grid_get_dot(g, points, px + a, py);
1413 grid_face_set_dot(g, d, 1);
1414 d = grid_get_dot(g, points, px + a, py + a);
1415 grid_face_set_dot(g, d, 2);
1416 d = grid_get_dot(g, points, px, py + a);
1417 grid_face_set_dot(g, d, 3);
1418 }
1419 }
1420
1421 freetree234(points);
1422 assert(g->num_faces <= max_faces);
1423 assert(g->num_dots <= max_dots);
1424
1425 grid_make_consistent(g);
1426 return g;
1427 }
1428
1429 #define HONEY_TILESIZE 45
1430 /* Vector for side of hexagon - ratio is close to sqrt(3) */
1431 #define HONEY_A 15
1432 #define HONEY_B 26
1433
1434 void grid_size_honeycomb(int width, int height,
1435 int *tilesize, int *xextent, int *yextent)
1436 {
1437 int a = HONEY_A;
1438 int b = HONEY_B;
1439
1440 *tilesize = HONEY_TILESIZE;
1441 *xextent = (3 * a * (width-1)) + 4*a;
1442 *yextent = (2 * b * (height-1)) + 3*b;
1443 }
1444
1445 grid *grid_new_honeycomb(int width, int height, char *desc)
1446 {
1447 int x, y;
1448 int a = HONEY_A;
1449 int b = HONEY_B;
1450
1451 /* Upper bounds - don't have to be exact */
1452 int max_faces = width * height;
1453 int max_dots = 2 * (width + 1) * (height + 1);
1454
1455 tree234 *points;
1456
1457 grid *g = grid_empty();
1458 g->tilesize = HONEY_TILESIZE;
1459 g->faces = snewn(max_faces, grid_face);
1460 g->dots = snewn(max_dots, grid_dot);
1461
1462 points = newtree234(grid_point_cmp_fn);
1463
1464 /* generate hexagonal faces */
1465 for (y = 0; y < height; y++) {
1466 for (x = 0; x < width; x++) {
1467 grid_dot *d;
1468 /* face centre */
1469 int cx = 3 * a * x;
1470 int cy = 2 * b * y;
1471 if (x % 2)
1472 cy += b;
1473 grid_face_add_new(g, 6);
1474
1475 d = grid_get_dot(g, points, cx - a, cy - b);
1476 grid_face_set_dot(g, d, 0);
1477 d = grid_get_dot(g, points, cx + a, cy - b);
1478 grid_face_set_dot(g, d, 1);
1479 d = grid_get_dot(g, points, cx + 2*a, cy);
1480 grid_face_set_dot(g, d, 2);
1481 d = grid_get_dot(g, points, cx + a, cy + b);
1482 grid_face_set_dot(g, d, 3);
1483 d = grid_get_dot(g, points, cx - a, cy + b);
1484 grid_face_set_dot(g, d, 4);
1485 d = grid_get_dot(g, points, cx - 2*a, cy);
1486 grid_face_set_dot(g, d, 5);
1487 }
1488 }
1489
1490 freetree234(points);
1491 assert(g->num_faces <= max_faces);
1492 assert(g->num_dots <= max_dots);
1493
1494 grid_make_consistent(g);
1495 return g;
1496 }
1497
1498 #define TRIANGLE_TILESIZE 18
1499 /* Vector for side of triangle - ratio is close to sqrt(3) */
1500 #define TRIANGLE_VEC_X 15
1501 #define TRIANGLE_VEC_Y 26
1502
1503 void grid_size_triangular(int width, int height,
1504 int *tilesize, int *xextent, int *yextent)
1505 {
1506 int vec_x = TRIANGLE_VEC_X;
1507 int vec_y = TRIANGLE_VEC_Y;
1508
1509 *tilesize = TRIANGLE_TILESIZE;
1510 *xextent = width * 2 * vec_x + vec_x;
1511 *yextent = height * vec_y;
1512 }
1513
1514 /* Doesn't use the previous method of generation, it pre-dates it!
1515 * A triangular grid is just about simple enough to do by "brute force" */
1516 grid *grid_new_triangular(int width, int height, char *desc)
1517 {
1518 int x,y;
1519
1520 /* Vector for side of triangle - ratio is close to sqrt(3) */
1521 int vec_x = TRIANGLE_VEC_X;
1522 int vec_y = TRIANGLE_VEC_Y;
1523
1524 int index;
1525
1526 /* convenient alias */
1527 int w = width + 1;
1528
1529 grid *g = grid_empty();
1530 g->tilesize = TRIANGLE_TILESIZE;
1531
1532 g->num_faces = width * height * 2;
1533 g->num_dots = (width + 1) * (height + 1);
1534 g->faces = snewn(g->num_faces, grid_face);
1535 g->dots = snewn(g->num_dots, grid_dot);
1536
1537 /* generate dots */
1538 index = 0;
1539 for (y = 0; y <= height; y++) {
1540 for (x = 0; x <= width; x++) {
1541 grid_dot *d = g->dots + index;
1542 /* odd rows are offset to the right */
1543 d->order = 0;
1544 d->edges = NULL;
1545 d->faces = NULL;
1546 d->x = x * 2 * vec_x + ((y % 2) ? vec_x : 0);
1547 d->y = y * vec_y;
1548 index++;
1549 }
1550 }
1551
1552 /* generate faces */
1553 index = 0;
1554 for (y = 0; y < height; y++) {
1555 for (x = 0; x < width; x++) {
1556 /* initialise two faces for this (x,y) */
1557 grid_face *f1 = g->faces + index;
1558 grid_face *f2 = f1 + 1;
1559 f1->edges = NULL;
1560 f1->order = 3;
1561 f1->dots = snewn(f1->order, grid_dot*);
1562 f1->has_incentre = FALSE;
1563 f2->edges = NULL;
1564 f2->order = 3;
1565 f2->dots = snewn(f2->order, grid_dot*);
1566 f2->has_incentre = FALSE;
1567
1568 /* face descriptions depend on whether the row-number is
1569 * odd or even */
1570 if (y % 2) {
1571 f1->dots[0] = g->dots + y * w + x;
1572 f1->dots[1] = g->dots + (y + 1) * w + x + 1;
1573 f1->dots[2] = g->dots + (y + 1) * w + x;
1574 f2->dots[0] = g->dots + y * w + x;
1575 f2->dots[1] = g->dots + y * w + x + 1;
1576 f2->dots[2] = g->dots + (y + 1) * w + x + 1;
1577 } else {
1578 f1->dots[0] = g->dots + y * w + x;
1579 f1->dots[1] = g->dots + y * w + x + 1;
1580 f1->dots[2] = g->dots + (y + 1) * w + x;
1581 f2->dots[0] = g->dots + y * w + x + 1;
1582 f2->dots[1] = g->dots + (y + 1) * w + x + 1;
1583 f2->dots[2] = g->dots + (y + 1) * w + x;
1584 }
1585 index += 2;
1586 }
1587 }
1588
1589 grid_make_consistent(g);
1590 return g;
1591 }
1592
1593 #define SNUBSQUARE_TILESIZE 18
1594 /* Vector for side of triangle - ratio is close to sqrt(3) */
1595 #define SNUBSQUARE_A 15
1596 #define SNUBSQUARE_B 26
1597
1598 void grid_size_snubsquare(int width, int height,
1599 int *tilesize, int *xextent, int *yextent)
1600 {
1601 int a = SNUBSQUARE_A;
1602 int b = SNUBSQUARE_B;
1603
1604 *tilesize = SNUBSQUARE_TILESIZE;
1605 *xextent = (a+b) * (width-1) + a + b;
1606 *yextent = (a+b) * (height-1) + a + b;
1607 }
1608
1609 grid *grid_new_snubsquare(int width, int height, char *desc)
1610 {
1611 int x, y;
1612 int a = SNUBSQUARE_A;
1613 int b = SNUBSQUARE_B;
1614
1615 /* Upper bounds - don't have to be exact */
1616 int max_faces = 3 * width * height;
1617 int max_dots = 2 * (width + 1) * (height + 1);
1618
1619 tree234 *points;
1620
1621 grid *g = grid_empty();
1622 g->tilesize = SNUBSQUARE_TILESIZE;
1623 g->faces = snewn(max_faces, grid_face);
1624 g->dots = snewn(max_dots, grid_dot);
1625
1626 points = newtree234(grid_point_cmp_fn);
1627
1628 for (y = 0; y < height; y++) {
1629 for (x = 0; x < width; x++) {
1630 grid_dot *d;
1631 /* face position */
1632 int px = (a + b) * x;
1633 int py = (a + b) * y;
1634
1635 /* generate square faces */
1636 grid_face_add_new(g, 4);
1637 if ((x + y) % 2) {
1638 d = grid_get_dot(g, points, px + a, py);
1639 grid_face_set_dot(g, d, 0);
1640 d = grid_get_dot(g, points, px + a + b, py + a);
1641 grid_face_set_dot(g, d, 1);
1642 d = grid_get_dot(g, points, px + b, py + a + b);
1643 grid_face_set_dot(g, d, 2);
1644 d = grid_get_dot(g, points, px, py + b);
1645 grid_face_set_dot(g, d, 3);
1646 } else {
1647 d = grid_get_dot(g, points, px + b, py);
1648 grid_face_set_dot(g, d, 0);
1649 d = grid_get_dot(g, points, px + a + b, py + b);
1650 grid_face_set_dot(g, d, 1);
1651 d = grid_get_dot(g, points, px + a, py + a + b);
1652 grid_face_set_dot(g, d, 2);
1653 d = grid_get_dot(g, points, px, py + a);
1654 grid_face_set_dot(g, d, 3);
1655 }
1656
1657 /* generate up/down triangles */
1658 if (x > 0) {
1659 grid_face_add_new(g, 3);
1660 if ((x + y) % 2) {
1661 d = grid_get_dot(g, points, px + a, py);
1662 grid_face_set_dot(g, d, 0);
1663 d = grid_get_dot(g, points, px, py + b);
1664 grid_face_set_dot(g, d, 1);
1665 d = grid_get_dot(g, points, px - a, py);
1666 grid_face_set_dot(g, d, 2);
1667 } else {
1668 d = grid_get_dot(g, points, px, py + a);
1669 grid_face_set_dot(g, d, 0);
1670 d = grid_get_dot(g, points, px + a, py + a + b);
1671 grid_face_set_dot(g, d, 1);
1672 d = grid_get_dot(g, points, px - a, py + a + b);
1673 grid_face_set_dot(g, d, 2);
1674 }
1675 }
1676
1677 /* generate left/right triangles */
1678 if (y > 0) {
1679 grid_face_add_new(g, 3);
1680 if ((x + y) % 2) {
1681 d = grid_get_dot(g, points, px + a, py);
1682 grid_face_set_dot(g, d, 0);
1683 d = grid_get_dot(g, points, px + a + b, py - a);
1684 grid_face_set_dot(g, d, 1);
1685 d = grid_get_dot(g, points, px + a + b, py + a);
1686 grid_face_set_dot(g, d, 2);
1687 } else {
1688 d = grid_get_dot(g, points, px, py - a);
1689 grid_face_set_dot(g, d, 0);
1690 d = grid_get_dot(g, points, px + b, py);
1691 grid_face_set_dot(g, d, 1);
1692 d = grid_get_dot(g, points, px, py + a);
1693 grid_face_set_dot(g, d, 2);
1694 }
1695 }
1696 }
1697 }
1698
1699 freetree234(points);
1700 assert(g->num_faces <= max_faces);
1701 assert(g->num_dots <= max_dots);
1702
1703 grid_make_consistent(g);
1704 return g;
1705 }
1706
1707 #define CAIRO_TILESIZE 40
1708 /* Vector for side of pentagon - ratio is close to (4+sqrt(7))/3 */
1709 #define CAIRO_A 14
1710 #define CAIRO_B 31
1711
1712 void grid_size_cairo(int width, int height,
1713 int *tilesize, int *xextent, int *yextent)
1714 {
1715 int b = CAIRO_B; /* a unused in determining grid size. */
1716
1717 *tilesize = CAIRO_TILESIZE;
1718 *xextent = 2*b*(width-1) + 2*b;
1719 *yextent = 2*b*(height-1) + 2*b;
1720 }
1721
1722 grid *grid_new_cairo(int width, int height, char *desc)
1723 {
1724 int x, y;
1725 int a = CAIRO_A;
1726 int b = CAIRO_B;
1727
1728 /* Upper bounds - don't have to be exact */
1729 int max_faces = 2 * width * height;
1730 int max_dots = 3 * (width + 1) * (height + 1);
1731
1732 tree234 *points;
1733
1734 grid *g = grid_empty();
1735 g->tilesize = CAIRO_TILESIZE;
1736 g->faces = snewn(max_faces, grid_face);
1737 g->dots = snewn(max_dots, grid_dot);
1738
1739 points = newtree234(grid_point_cmp_fn);
1740
1741 for (y = 0; y < height; y++) {
1742 for (x = 0; x < width; x++) {
1743 grid_dot *d;
1744 /* cell position */
1745 int px = 2 * b * x;
1746 int py = 2 * b * y;
1747
1748 /* horizontal pentagons */
1749 if (y > 0) {
1750 grid_face_add_new(g, 5);
1751 if ((x + y) % 2) {
1752 d = grid_get_dot(g, points, px + a, py - b);
1753 grid_face_set_dot(g, d, 0);
1754 d = grid_get_dot(g, points, px + 2*b - a, py - b);
1755 grid_face_set_dot(g, d, 1);
1756 d = grid_get_dot(g, points, px + 2*b, py);
1757 grid_face_set_dot(g, d, 2);
1758 d = grid_get_dot(g, points, px + b, py + a);
1759 grid_face_set_dot(g, d, 3);
1760 d = grid_get_dot(g, points, px, py);
1761 grid_face_set_dot(g, d, 4);
1762 } else {
1763 d = grid_get_dot(g, points, px, py);
1764 grid_face_set_dot(g, d, 0);
1765 d = grid_get_dot(g, points, px + b, py - a);
1766 grid_face_set_dot(g, d, 1);
1767 d = grid_get_dot(g, points, px + 2*b, py);
1768 grid_face_set_dot(g, d, 2);
1769 d = grid_get_dot(g, points, px + 2*b - a, py + b);
1770 grid_face_set_dot(g, d, 3);
1771 d = grid_get_dot(g, points, px + a, py + b);
1772 grid_face_set_dot(g, d, 4);
1773 }
1774 }
1775 /* vertical pentagons */
1776 if (x > 0) {
1777 grid_face_add_new(g, 5);
1778 if ((x + y) % 2) {
1779 d = grid_get_dot(g, points, px, py);
1780 grid_face_set_dot(g, d, 0);
1781 d = grid_get_dot(g, points, px + b, py + a);
1782 grid_face_set_dot(g, d, 1);
1783 d = grid_get_dot(g, points, px + b, py + 2*b - a);
1784 grid_face_set_dot(g, d, 2);
1785 d = grid_get_dot(g, points, px, py + 2*b);
1786 grid_face_set_dot(g, d, 3);
1787 d = grid_get_dot(g, points, px - a, py + b);
1788 grid_face_set_dot(g, d, 4);
1789 } else {
1790 d = grid_get_dot(g, points, px, py);
1791 grid_face_set_dot(g, d, 0);
1792 d = grid_get_dot(g, points, px + a, py + b);
1793 grid_face_set_dot(g, d, 1);
1794 d = grid_get_dot(g, points, px, py + 2*b);
1795 grid_face_set_dot(g, d, 2);
1796 d = grid_get_dot(g, points, px - b, py + 2*b - a);
1797 grid_face_set_dot(g, d, 3);
1798 d = grid_get_dot(g, points, px - b, py + a);
1799 grid_face_set_dot(g, d, 4);
1800 }
1801 }
1802 }
1803 }
1804
1805 freetree234(points);
1806 assert(g->num_faces <= max_faces);
1807 assert(g->num_dots <= max_dots);
1808
1809 grid_make_consistent(g);
1810 return g;
1811 }
1812
1813 #define GREATHEX_TILESIZE 18
1814 /* Vector for side of triangle - ratio is close to sqrt(3) */
1815 #define GREATHEX_A 15
1816 #define GREATHEX_B 26
1817
1818 void grid_size_greathexagonal(int width, int height,
1819 int *tilesize, int *xextent, int *yextent)
1820 {
1821 int a = GREATHEX_A;
1822 int b = GREATHEX_B;
1823
1824 *tilesize = GREATHEX_TILESIZE;
1825 *xextent = (3*a + b) * (width-1) + 4*a;
1826 *yextent = (2*a + 2*b) * (height-1) + 3*b + a;
1827 }
1828
1829 grid *grid_new_greathexagonal(int width, int height, char *desc)
1830 {
1831 int x, y;
1832 int a = GREATHEX_A;
1833 int b = GREATHEX_B;
1834
1835 /* Upper bounds - don't have to be exact */
1836 int max_faces = 6 * (width + 1) * (height + 1);
1837 int max_dots = 6 * width * height;
1838
1839 tree234 *points;
1840
1841 grid *g = grid_empty();
1842 g->tilesize = GREATHEX_TILESIZE;
1843 g->faces = snewn(max_faces, grid_face);
1844 g->dots = snewn(max_dots, grid_dot);
1845
1846 points = newtree234(grid_point_cmp_fn);
1847
1848 for (y = 0; y < height; y++) {
1849 for (x = 0; x < width; x++) {
1850 grid_dot *d;
1851 /* centre of hexagon */
1852 int px = (3*a + b) * x;
1853 int py = (2*a + 2*b) * y;
1854 if (x % 2)
1855 py += a + b;
1856
1857 /* hexagon */
1858 grid_face_add_new(g, 6);
1859 d = grid_get_dot(g, points, px - a, py - b);
1860 grid_face_set_dot(g, d, 0);
1861 d = grid_get_dot(g, points, px + a, py - b);
1862 grid_face_set_dot(g, d, 1);
1863 d = grid_get_dot(g, points, px + 2*a, py);
1864 grid_face_set_dot(g, d, 2);
1865 d = grid_get_dot(g, points, px + a, py + b);
1866 grid_face_set_dot(g, d, 3);
1867 d = grid_get_dot(g, points, px - a, py + b);
1868 grid_face_set_dot(g, d, 4);
1869 d = grid_get_dot(g, points, px - 2*a, py);
1870 grid_face_set_dot(g, d, 5);
1871
1872 /* square below hexagon */
1873 if (y < height - 1) {
1874 grid_face_add_new(g, 4);
1875 d = grid_get_dot(g, points, px - a, py + b);
1876 grid_face_set_dot(g, d, 0);
1877 d = grid_get_dot(g, points, px + a, py + b);
1878 grid_face_set_dot(g, d, 1);
1879 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1880 grid_face_set_dot(g, d, 2);
1881 d = grid_get_dot(g, points, px - a, py + 2*a + b);
1882 grid_face_set_dot(g, d, 3);
1883 }
1884
1885 /* square below right */
1886 if ((x < width - 1) && (((x % 2) == 0) || (y < height - 1))) {
1887 grid_face_add_new(g, 4);
1888 d = grid_get_dot(g, points, px + 2*a, py);
1889 grid_face_set_dot(g, d, 0);
1890 d = grid_get_dot(g, points, px + 2*a + b, py + a);
1891 grid_face_set_dot(g, d, 1);
1892 d = grid_get_dot(g, points, px + a + b, py + a + b);
1893 grid_face_set_dot(g, d, 2);
1894 d = grid_get_dot(g, points, px + a, py + b);
1895 grid_face_set_dot(g, d, 3);
1896 }
1897
1898 /* square below left */
1899 if ((x > 0) && (((x % 2) == 0) || (y < height - 1))) {
1900 grid_face_add_new(g, 4);
1901 d = grid_get_dot(g, points, px - 2*a, py);
1902 grid_face_set_dot(g, d, 0);
1903 d = grid_get_dot(g, points, px - a, py + b);
1904 grid_face_set_dot(g, d, 1);
1905 d = grid_get_dot(g, points, px - a - b, py + a + b);
1906 grid_face_set_dot(g, d, 2);
1907 d = grid_get_dot(g, points, px - 2*a - b, py + a);
1908 grid_face_set_dot(g, d, 3);
1909 }
1910
1911 /* Triangle below right */
1912 if ((x < width - 1) && (y < height - 1)) {
1913 grid_face_add_new(g, 3);
1914 d = grid_get_dot(g, points, px + a, py + b);
1915 grid_face_set_dot(g, d, 0);
1916 d = grid_get_dot(g, points, px + a + b, py + a + b);
1917 grid_face_set_dot(g, d, 1);
1918 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1919 grid_face_set_dot(g, d, 2);
1920 }
1921
1922 /* Triangle below left */
1923 if ((x > 0) && (y < height - 1)) {
1924 grid_face_add_new(g, 3);
1925 d = grid_get_dot(g, points, px - a, py + b);
1926 grid_face_set_dot(g, d, 0);
1927 d = grid_get_dot(g, points, px - a, py + 2*a + b);
1928 grid_face_set_dot(g, d, 1);
1929 d = grid_get_dot(g, points, px - a - b, py + a + b);
1930 grid_face_set_dot(g, d, 2);
1931 }
1932 }
1933 }
1934
1935 freetree234(points);
1936 assert(g->num_faces <= max_faces);
1937 assert(g->num_dots <= max_dots);
1938
1939 grid_make_consistent(g);
1940 return g;
1941 }
1942
1943 #define OCTAGONAL_TILESIZE 40
1944 /* b/a approx sqrt(2) */
1945 #define OCTAGONAL_A 29
1946 #define OCTAGONAL_B 41
1947
1948 void grid_size_octagonal(int width, int height,
1949 int *tilesize, int *xextent, int *yextent)
1950 {
1951 int a = OCTAGONAL_A;
1952 int b = OCTAGONAL_B;
1953
1954 *tilesize = OCTAGONAL_TILESIZE;
1955 *xextent = (2*a + b) * width;
1956 *yextent = (2*a + b) * height;
1957 }
1958
1959 grid *grid_new_octagonal(int width, int height, char *desc)
1960 {
1961 int x, y;
1962 int a = OCTAGONAL_A;
1963 int b = OCTAGONAL_B;
1964
1965 /* Upper bounds - don't have to be exact */
1966 int max_faces = 2 * width * height;
1967 int max_dots = 4 * (width + 1) * (height + 1);
1968
1969 tree234 *points;
1970
1971 grid *g = grid_empty();
1972 g->tilesize = OCTAGONAL_TILESIZE;
1973 g->faces = snewn(max_faces, grid_face);
1974 g->dots = snewn(max_dots, grid_dot);
1975
1976 points = newtree234(grid_point_cmp_fn);
1977
1978 for (y = 0; y < height; y++) {
1979 for (x = 0; x < width; x++) {
1980 grid_dot *d;
1981 /* cell position */
1982 int px = (2*a + b) * x;
1983 int py = (2*a + b) * y;
1984 /* octagon */
1985 grid_face_add_new(g, 8);
1986 d = grid_get_dot(g, points, px + a, py);
1987 grid_face_set_dot(g, d, 0);
1988 d = grid_get_dot(g, points, px + a + b, py);
1989 grid_face_set_dot(g, d, 1);
1990 d = grid_get_dot(g, points, px + 2*a + b, py + a);
1991 grid_face_set_dot(g, d, 2);
1992 d = grid_get_dot(g, points, px + 2*a + b, py + a + b);
1993 grid_face_set_dot(g, d, 3);
1994 d = grid_get_dot(g, points, px + a + b, py + 2*a + b);
1995 grid_face_set_dot(g, d, 4);
1996 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1997 grid_face_set_dot(g, d, 5);
1998 d = grid_get_dot(g, points, px, py + a + b);
1999 grid_face_set_dot(g, d, 6);
2000 d = grid_get_dot(g, points, px, py + a);
2001 grid_face_set_dot(g, d, 7);
2002
2003 /* diamond */
2004 if ((x > 0) && (y > 0)) {
2005 grid_face_add_new(g, 4);
2006 d = grid_get_dot(g, points, px, py - a);
2007 grid_face_set_dot(g, d, 0);
2008 d = grid_get_dot(g, points, px + a, py);
2009 grid_face_set_dot(g, d, 1);
2010 d = grid_get_dot(g, points, px, py + a);
2011 grid_face_set_dot(g, d, 2);
2012 d = grid_get_dot(g, points, px - a, py);
2013 grid_face_set_dot(g, d, 3);
2014 }
2015 }
2016 }
2017
2018 freetree234(points);
2019 assert(g->num_faces <= max_faces);
2020 assert(g->num_dots <= max_dots);
2021
2022 grid_make_consistent(g);
2023 return g;
2024 }
2025
2026 #define KITE_TILESIZE 40
2027 /* b/a approx sqrt(3) */
2028 #define KITE_A 15
2029 #define KITE_B 26
2030
2031 void grid_size_kites(int width, int height,
2032 int *tilesize, int *xextent, int *yextent)
2033 {
2034 int a = KITE_A;
2035 int b = KITE_B;
2036
2037 *tilesize = KITE_TILESIZE;
2038 *xextent = 4*b * width + 2*b;
2039 *yextent = 6*a * (height-1) + 8*a;
2040 }
2041
2042 grid *grid_new_kites(int width, int height, char *desc)
2043 {
2044 int x, y;
2045 int a = KITE_A;
2046 int b = KITE_B;
2047
2048 /* Upper bounds - don't have to be exact */
2049 int max_faces = 6 * width * height;
2050 int max_dots = 6 * (width + 1) * (height + 1);
2051
2052 tree234 *points;
2053
2054 grid *g = grid_empty();
2055 g->tilesize = KITE_TILESIZE;
2056 g->faces = snewn(max_faces, grid_face);
2057 g->dots = snewn(max_dots, grid_dot);
2058
2059 points = newtree234(grid_point_cmp_fn);
2060
2061 for (y = 0; y < height; y++) {
2062 for (x = 0; x < width; x++) {
2063 grid_dot *d;
2064 /* position of order-6 dot */
2065 int px = 4*b * x;
2066 int py = 6*a * y;
2067 if (y % 2)
2068 px += 2*b;
2069
2070 /* kite pointing up-left */
2071 grid_face_add_new(g, 4);
2072 d = grid_get_dot(g, points, px, py);
2073 grid_face_set_dot(g, d, 0);
2074 d = grid_get_dot(g, points, px + 2*b, py);
2075 grid_face_set_dot(g, d, 1);
2076 d = grid_get_dot(g, points, px + 2*b, py + 2*a);
2077 grid_face_set_dot(g, d, 2);
2078 d = grid_get_dot(g, points, px + b, py + 3*a);
2079 grid_face_set_dot(g, d, 3);
2080
2081 /* kite pointing up */
2082 grid_face_add_new(g, 4);
2083 d = grid_get_dot(g, points, px, py);
2084 grid_face_set_dot(g, d, 0);
2085 d = grid_get_dot(g, points, px + b, py + 3*a);
2086 grid_face_set_dot(g, d, 1);
2087 d = grid_get_dot(g, points, px, py + 4*a);
2088 grid_face_set_dot(g, d, 2);
2089 d = grid_get_dot(g, points, px - b, py + 3*a);
2090 grid_face_set_dot(g, d, 3);
2091
2092 /* kite pointing up-right */
2093 grid_face_add_new(g, 4);
2094 d = grid_get_dot(g, points, px, py);
2095 grid_face_set_dot(g, d, 0);
2096 d = grid_get_dot(g, points, px - b, py + 3*a);
2097 grid_face_set_dot(g, d, 1);
2098 d = grid_get_dot(g, points, px - 2*b, py + 2*a);
2099 grid_face_set_dot(g, d, 2);
2100 d = grid_get_dot(g, points, px - 2*b, py);
2101 grid_face_set_dot(g, d, 3);
2102
2103 /* kite pointing down-right */
2104 grid_face_add_new(g, 4);
2105 d = grid_get_dot(g, points, px, py);
2106 grid_face_set_dot(g, d, 0);
2107 d = grid_get_dot(g, points, px - 2*b, py);
2108 grid_face_set_dot(g, d, 1);
2109 d = grid_get_dot(g, points, px - 2*b, py - 2*a);
2110 grid_face_set_dot(g, d, 2);
2111 d = grid_get_dot(g, points, px - b, py - 3*a);
2112 grid_face_set_dot(g, d, 3);
2113
2114 /* kite pointing down */
2115 grid_face_add_new(g, 4);
2116 d = grid_get_dot(g, points, px, py);
2117 grid_face_set_dot(g, d, 0);
2118 d = grid_get_dot(g, points, px - b, py - 3*a);
2119 grid_face_set_dot(g, d, 1);
2120 d = grid_get_dot(g, points, px, py - 4*a);
2121 grid_face_set_dot(g, d, 2);
2122 d = grid_get_dot(g, points, px + b, py - 3*a);
2123 grid_face_set_dot(g, d, 3);
2124
2125 /* kite pointing down-left */
2126 grid_face_add_new(g, 4);
2127 d = grid_get_dot(g, points, px, py);
2128 grid_face_set_dot(g, d, 0);
2129 d = grid_get_dot(g, points, px + b, py - 3*a);
2130 grid_face_set_dot(g, d, 1);
2131 d = grid_get_dot(g, points, px + 2*b, py - 2*a);
2132 grid_face_set_dot(g, d, 2);
2133 d = grid_get_dot(g, points, px + 2*b, py);
2134 grid_face_set_dot(g, d, 3);
2135 }
2136 }
2137
2138 freetree234(points);
2139 assert(g->num_faces <= max_faces);
2140 assert(g->num_dots <= max_dots);
2141
2142 grid_make_consistent(g);
2143 return g;
2144 }
2145
2146 #define FLORET_TILESIZE 150
2147 /* -py/px is close to tan(30 - atan(sqrt(3)/9))
2148 * using py=26 makes everything lean to the left, rather than right
2149 */
2150 #define FLORET_PX 75
2151 #define FLORET_PY -26
2152
2153 void grid_size_floret(int width, int height,
2154 int *tilesize, int *xextent, int *yextent)
2155 {
2156 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */
2157 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */
2158 int ry = qy-py;
2159 /* rx unused in determining grid size. */
2160
2161 *tilesize = FLORET_TILESIZE;
2162 *xextent = (6*px+3*qx)/2 * (width-1) + 4*qx + 2*px;
2163 *yextent = (5*qy-4*py) * (height-1) + 4*qy + 2*ry;
2164 }
2165
2166 grid *grid_new_floret(int width, int height, char *desc)
2167 {
2168 int x, y;
2169 /* Vectors for sides; weird numbers needed to keep puzzle aligned with window
2170 * -py/px is close to tan(30 - atan(sqrt(3)/9))
2171 * using py=26 makes everything lean to the left, rather than right
2172 */
2173 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */
2174 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */
2175 int rx = qx-px, ry = qy-py; /* |(-15, 78)| = 79.38 */
2176
2177 /* Upper bounds - don't have to be exact */
2178 int max_faces = 6 * width * height;
2179 int max_dots = 9 * (width + 1) * (height + 1);
2180
2181 tree234 *points;
2182
2183 grid *g = grid_empty();
2184 g->tilesize = FLORET_TILESIZE;
2185 g->faces = snewn(max_faces, grid_face);
2186 g->dots = snewn(max_dots, grid_dot);
2187
2188 points = newtree234(grid_point_cmp_fn);
2189
2190 /* generate pentagonal faces */
2191 for (y = 0; y < height; y++) {
2192 for (x = 0; x < width; x++) {
2193 grid_dot *d;
2194 /* face centre */
2195 int cx = (6*px+3*qx)/2 * x;
2196 int cy = (4*py-5*qy) * y;
2197 if (x % 2)
2198 cy -= (4*py-5*qy)/2;
2199 else if (y && y == height-1)
2200 continue; /* make better looking grids? try 3x3 for instance */
2201
2202 grid_face_add_new(g, 5);
2203 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2204 d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 1);
2205 d = grid_get_dot(g, points, cx+2*rx+qx, cy+2*ry+qy); grid_face_set_dot(g, d, 2);
2206 d = grid_get_dot(g, points, cx+2*qx+rx, cy+2*qy+ry); grid_face_set_dot(g, d, 3);
2207 d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 4);
2208
2209 grid_face_add_new(g, 5);
2210 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2211 d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 1);
2212 d = grid_get_dot(g, points, cx+2*qx+px, cy+2*qy+py); grid_face_set_dot(g, d, 2);
2213 d = grid_get_dot(g, points, cx+2*px+qx, cy+2*py+qy); grid_face_set_dot(g, d, 3);
2214 d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 4);
2215
2216 grid_face_add_new(g, 5);
2217 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2218 d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 1);
2219 d = grid_get_dot(g, points, cx+2*px-rx, cy+2*py-ry); grid_face_set_dot(g, d, 2);
2220 d = grid_get_dot(g, points, cx-2*rx+px, cy-2*ry+py); grid_face_set_dot(g, d, 3);
2221 d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 4);
2222
2223 grid_face_add_new(g, 5);
2224 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2225 d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 1);
2226 d = grid_get_dot(g, points, cx-2*rx-qx, cy-2*ry-qy); grid_face_set_dot(g, d, 2);
2227 d = grid_get_dot(g, points, cx-2*qx-rx, cy-2*qy-ry); grid_face_set_dot(g, d, 3);
2228 d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 4);
2229
2230 grid_face_add_new(g, 5);
2231 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2232 d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 1);
2233 d = grid_get_dot(g, points, cx-2*qx-px, cy-2*qy-py); grid_face_set_dot(g, d, 2);
2234 d = grid_get_dot(g, points, cx-2*px-qx, cy-2*py-qy); grid_face_set_dot(g, d, 3);
2235 d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 4);
2236
2237 grid_face_add_new(g, 5);
2238 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0);
2239 d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 1);
2240 d = grid_get_dot(g, points, cx-2*px+rx, cy-2*py+ry); grid_face_set_dot(g, d, 2);
2241 d = grid_get_dot(g, points, cx+2*rx-px, cy+2*ry-py); grid_face_set_dot(g, d, 3);
2242 d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 4);
2243 }
2244 }
2245
2246 freetree234(points);
2247 assert(g->num_faces <= max_faces);
2248 assert(g->num_dots <= max_dots);
2249
2250 grid_make_consistent(g);
2251 return g;
2252 }
2253
2254 /* DODEC_* are used for dodecagonal and great-dodecagonal grids. */
2255 #define DODEC_TILESIZE 26
2256 /* Vector for side of triangle - ratio is close to sqrt(3) */
2257 #define DODEC_A 15
2258 #define DODEC_B 26
2259
2260 void grid_size_dodecagonal(int width, int height,
2261 int *tilesize, int *xextent, int *yextent)
2262 {
2263 int a = DODEC_A;
2264 int b = DODEC_B;
2265
2266 *tilesize = DODEC_TILESIZE;
2267 *xextent = (4*a + 2*b) * (width-1) + 3*(2*a + b);
2268 *yextent = (3*a + 2*b) * (height-1) + 2*(2*a + b);
2269 }
2270
2271 grid *grid_new_dodecagonal(int width, int height, char *desc)
2272 {
2273 int x, y;
2274 int a = DODEC_A;
2275 int b = DODEC_B;
2276
2277 /* Upper bounds - don't have to be exact */
2278 int max_faces = 3 * width * height;
2279 int max_dots = 14 * width * height;
2280
2281 tree234 *points;
2282
2283 grid *g = grid_empty();
2284 g->tilesize = DODEC_TILESIZE;
2285 g->faces = snewn(max_faces, grid_face);
2286 g->dots = snewn(max_dots, grid_dot);
2287
2288 points = newtree234(grid_point_cmp_fn);
2289
2290 for (y = 0; y < height; y++) {
2291 for (x = 0; x < width; x++) {
2292 grid_dot *d;
2293 /* centre of dodecagon */
2294 int px = (4*a + 2*b) * x;
2295 int py = (3*a + 2*b) * y;
2296 if (y % 2)
2297 px += 2*a + b;
2298
2299 /* dodecagon */
2300 grid_face_add_new(g, 12);
2301 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0);
2302 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1);
2303 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2);
2304 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3);
2305 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4);
2306 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5);
2307 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6);
2308 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7);
2309 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8);
2310 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9);
2311 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10);
2312 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11);
2313
2314 /* triangle below dodecagon */
2315 if ((y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) {
2316 grid_face_add_new(g, 3);
2317 d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0);
2318 d = grid_get_dot(g, points, px , py + (2*a + 2*b)); grid_face_set_dot(g, d, 1);
2319 d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 2);
2320 }
2321
2322 /* triangle above dodecagon */
2323 if ((y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) {
2324 grid_face_add_new(g, 3);
2325 d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0);
2326 d = grid_get_dot(g, points, px , py - (2*a + 2*b)); grid_face_set_dot(g, d, 1);
2327 d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 2);
2328 }
2329 }
2330 }
2331
2332 freetree234(points);
2333 assert(g->num_faces <= max_faces);
2334 assert(g->num_dots <= max_dots);
2335
2336 grid_make_consistent(g);
2337 return g;
2338 }
2339
2340 void grid_size_greatdodecagonal(int width, int height,
2341 int *tilesize, int *xextent, int *yextent)
2342 {
2343 int a = DODEC_A;
2344 int b = DODEC_B;
2345
2346 *tilesize = DODEC_TILESIZE;
2347 *xextent = (6*a + 2*b) * (width-1) + 2*(2*a + b) + 3*a + b;
2348 *yextent = (3*a + 3*b) * (height-1) + 2*(2*a + b);
2349 }
2350
2351 grid *grid_new_greatdodecagonal(int width, int height, char *desc)
2352 {
2353 int x, y;
2354 /* Vector for side of triangle - ratio is close to sqrt(3) */
2355 int a = DODEC_A;
2356 int b = DODEC_B;
2357
2358 /* Upper bounds - don't have to be exact */
2359 int max_faces = 30 * width * height;
2360 int max_dots = 200 * width * height;
2361
2362 tree234 *points;
2363
2364 grid *g = grid_empty();
2365 g->tilesize = DODEC_TILESIZE;
2366 g->faces = snewn(max_faces, grid_face);
2367 g->dots = snewn(max_dots, grid_dot);
2368
2369 points = newtree234(grid_point_cmp_fn);
2370
2371 for (y = 0; y < height; y++) {
2372 for (x = 0; x < width; x++) {
2373 grid_dot *d;
2374 /* centre of dodecagon */
2375 int px = (6*a + 2*b) * x;
2376 int py = (3*a + 3*b) * y;
2377 if (y % 2)
2378 px += 3*a + b;
2379
2380 /* dodecagon */
2381 grid_face_add_new(g, 12);
2382 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0);
2383 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1);
2384 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2);
2385 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3);
2386 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4);
2387 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5);
2388 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6);
2389 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7);
2390 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8);
2391 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9);
2392 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10);
2393 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11);
2394
2395 /* hexagon below dodecagon */
2396 if (y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) {
2397 grid_face_add_new(g, 6);
2398 d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0);
2399 d = grid_get_dot(g, points, px + 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 1);
2400 d = grid_get_dot(g, points, px + a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 2);
2401 d = grid_get_dot(g, points, px - a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 3);
2402 d = grid_get_dot(g, points, px - 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 4);
2403 d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 5);
2404 }
2405
2406 /* hexagon above dodecagon */
2407 if (y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) {
2408 grid_face_add_new(g, 6);
2409 d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0);
2410 d = grid_get_dot(g, points, px - 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 1);
2411 d = grid_get_dot(g, points, px - a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 2);
2412 d = grid_get_dot(g, points, px + a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 3);
2413 d = grid_get_dot(g, points, px + 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 4);
2414 d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 5);
2415 }
2416
2417 /* square on right of dodecagon */
2418 if (x < width - 1) {
2419 grid_face_add_new(g, 4);
2420 d = grid_get_dot(g, points, px + 2*a + b, py - a); grid_face_set_dot(g, d, 0);
2421 d = grid_get_dot(g, points, px + 4*a + b, py - a); grid_face_set_dot(g, d, 1);
2422 d = grid_get_dot(g, points, px + 4*a + b, py + a); grid_face_set_dot(g, d, 2);
2423 d = grid_get_dot(g, points, px + 2*a + b, py + a); grid_face_set_dot(g, d, 3);
2424 }
2425
2426 /* square on top right of dodecagon */
2427 if (y && (x < width - 1 || !(y % 2))) {
2428 grid_face_add_new(g, 4);
2429 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0);
2430 d = grid_get_dot(g, points, px + (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 1);
2431 d = grid_get_dot(g, points, px + (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 2);
2432 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 3);
2433 }
2434
2435 /* square on top left of dodecagon */
2436 if (y && (x || (y % 2))) {
2437 grid_face_add_new(g, 4);
2438 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 0);
2439 d = grid_get_dot(g, points, px - (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 1);
2440 d = grid_get_dot(g, points, px - (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 2);
2441 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 3);
2442 }
2443 }
2444 }
2445
2446 freetree234(points);
2447 assert(g->num_faces <= max_faces);
2448 assert(g->num_dots <= max_dots);
2449
2450 grid_make_consistent(g);
2451 return g;
2452 }
2453
2454 typedef struct setface_ctx
2455 {
2456 int xmin, xmax, ymin, ymax;
2457 int aoff;
2458
2459 grid *g;
2460 tree234 *points;
2461 } setface_ctx;
2462
2463 double round(double r)
2464 {
2465 return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5);
2466 }
2467
2468 int set_faces(penrose_state *state, vector *vs, int n, int depth)
2469 {
2470 setface_ctx *sf_ctx = (setface_ctx *)state->ctx;
2471 int i;
2472 int xs[4], ys[4];
2473 double cosa = cos(sf_ctx->aoff * PI / 180.0);
2474 double sina = sin(sf_ctx->aoff * PI / 180.0);
2475
2476 if (depth < state->max_depth) return 0;
2477 #ifdef DEBUG_PENROSE
2478 if (n != 4) return 0; /* triangles are sent as debugging. */
2479 #endif
2480
2481 for (i = 0; i < n; i++) {
2482 double tx = v_x(vs, i), ty = v_y(vs, i);
2483
2484 xs[i] = (int)round( tx*cosa + ty*sina);
2485 ys[i] = (int)round(-tx*sina + ty*cosa);
2486
2487 if (xs[i] < sf_ctx->xmin || xs[i] > sf_ctx->xmax) return 0;
2488 if (ys[i] < sf_ctx->ymin || ys[i] > sf_ctx->ymax) return 0;
2489 }
2490
2491 grid_face_add_new(sf_ctx->g, n);
2492 debug(("penrose: new face l=%f gen=%d...",
2493 penrose_side_length(state->start_size, depth), depth));
2494 for (i = 0; i < n; i++) {
2495 grid_dot *d = grid_get_dot(sf_ctx->g, sf_ctx->points,
2496 xs[i], ys[i]);
2497 grid_face_set_dot(sf_ctx->g, d, i);
2498 debug((" ... dot 0x%x (%d,%d) (was %2.2f,%2.2f)",
2499 d, d->x, d->y, v_x(vs, i), v_y(vs, i)));
2500 }
2501
2502 return 0;
2503 }
2504
2505 #define PENROSE_TILESIZE 100
2506
2507 void grid_size_penrose(int width, int height,
2508 int *tilesize, int *xextent, int *yextent)
2509 {
2510 int l = PENROSE_TILESIZE;
2511
2512 *tilesize = l;
2513 *xextent = l * width;
2514 *yextent = l * height;
2515 }
2516
2517 static char *grid_new_desc_penrose(grid_type type, int width, int height, random_state *rs)
2518 {
2519 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff;
2520 double outer_radius;
2521 int inner_radius;
2522 char gd[255];
2523 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3);
2524
2525 /* We want to produce a random bit of penrose tiling, so we calculate
2526 * a random offset (within the patch that penrose.c calculates for us)
2527 * and an angle (multiple of 36) to rotate the patch. */
2528
2529 penrose_calculate_size(which, tilesize, width, height,
2530 &outer_radius, &startsz, &depth);
2531
2532 /* Calculate radius of (circumcircle of) patch, subtract from
2533 * radius calculated. */
2534 inner_radius = (int)(outer_radius - sqrt(width*width + height*height));
2535
2536 /* Pick a random offset (the easy way: choose within outer square,
2537 * discarding while it's outside the circle) */
2538 do {
2539 xoff = random_upto(rs, 2*inner_radius) - inner_radius;
2540 yoff = random_upto(rs, 2*inner_radius) - inner_radius;
2541 } while (sqrt(xoff*xoff+yoff*yoff) > inner_radius);
2542
2543 aoff = random_upto(rs, 360/36) * 36;
2544
2545 debug(("grid_desc: ts %d, %dx%d patch, orad %2.2f irad %d",
2546 tilesize, width, height, outer_radius, inner_radius));
2547 debug((" -> xoff %d yoff %d aoff %d", xoff, yoff, aoff));
2548
2549 sprintf(gd, "G%d,%d,%d", xoff, yoff, aoff);
2550
2551 return dupstr(gd);
2552 }
2553
2554 static char *grid_validate_desc_penrose(grid_type type, int width, int height, char *desc)
2555 {
2556 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff, inner_radius;
2557 double outer_radius;
2558 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3);
2559
2560 if (!desc)
2561 return "Missing grid description string.";
2562
2563 penrose_calculate_size(which, tilesize, width, height,
2564 &outer_radius, &startsz, &depth);
2565 inner_radius = (int)(outer_radius - sqrt(width*width + height*height));
2566
2567 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3)
2568 return "Invalid format grid description string.";
2569
2570 if (sqrt(xoff*xoff + yoff*yoff) > inner_radius)
2571 return "Patch offset out of bounds.";
2572 if ((aoff % 36) != 0 || aoff < 0 || aoff >= 360)
2573 return "Angle offset out of bounds.";
2574
2575 return NULL;
2576 }
2577
2578 /*
2579 * We're asked for a grid of a particular size, and we generate enough
2580 * of the tiling so we can be sure to have enough random grid from which
2581 * to pick.
2582 */
2583
2584 static grid *grid_new_penrose(int width, int height, int which, char *desc)
2585 {
2586 int max_faces, max_dots, tilesize = PENROSE_TILESIZE;
2587 int xsz, ysz, xoff, yoff;
2588 double rradius;
2589
2590 tree234 *points;
2591 grid *g;
2592
2593 penrose_state ps;
2594 setface_ctx sf_ctx;
2595
2596 penrose_calculate_size(which, tilesize, width, height,
2597 &rradius, &ps.start_size, &ps.max_depth);
2598
2599 debug(("penrose: w%d h%d, tile size %d, start size %d, depth %d",
2600 width, height, tilesize, ps.start_size, ps.max_depth));
2601
2602 ps.new_tile = set_faces;
2603 ps.ctx = &sf_ctx;
2604
2605 max_faces = (width*3) * (height*3); /* somewhat paranoid... */
2606 max_dots = max_faces * 4; /* ditto... */
2607
2608 g = grid_empty();
2609 g->tilesize = tilesize;
2610 g->faces = snewn(max_faces, grid_face);
2611 g->dots = snewn(max_dots, grid_dot);
2612
2613 points = newtree234(grid_point_cmp_fn);
2614
2615 memset(&sf_ctx, 0, sizeof(sf_ctx));
2616 sf_ctx.g = g;
2617 sf_ctx.points = points;
2618
2619 if (desc != NULL) {
2620 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &sf_ctx.aoff) != 3)
2621 assert(!"Invalid grid description.");
2622 } else {
2623 xoff = yoff = 0;
2624 }
2625
2626 xsz = width * tilesize;
2627 ysz = height * tilesize;
2628
2629 sf_ctx.xmin = xoff - xsz/2;
2630 sf_ctx.xmax = xoff + xsz/2;
2631 sf_ctx.ymin = yoff - ysz/2;
2632 sf_ctx.ymax = yoff + ysz/2;
2633
2634 debug(("penrose: centre (%f, %f) xsz %f ysz %f",
2635 0.0, 0.0, xsz, ysz));
2636 debug(("penrose: x range (%f --> %f), y range (%f --> %f)",
2637 sf_ctx.xmin, sf_ctx.xmax, sf_ctx.ymin, sf_ctx.ymax));
2638
2639 penrose(&ps, which);
2640
2641 freetree234(points);
2642 assert(g->num_faces <= max_faces);
2643 assert(g->num_dots <= max_dots);
2644
2645 debug(("penrose: %d faces total (equivalent to %d wide by %d high)",
2646 g->num_faces, g->num_faces/height, g->num_faces/width));
2647
2648 grid_trim_vigorously(g);
2649 grid_make_consistent(g);
2650
2651 /*
2652 * Centre the grid in its originally promised rectangle.
2653 */
2654 g->lowest_x -= ((sf_ctx.xmax - sf_ctx.xmin) -
2655 (g->highest_x - g->lowest_x)) / 2;
2656 g->highest_x = g->lowest_x + (sf_ctx.xmax - sf_ctx.xmin);
2657 g->lowest_y -= ((sf_ctx.ymax - sf_ctx.ymin) -
2658 (g->highest_y - g->lowest_y)) / 2;
2659 g->highest_y = g->lowest_y + (sf_ctx.ymax - sf_ctx.ymin);
2660
2661 return g;
2662 }
2663
2664 void grid_size_penrose_p2_kite(int width, int height,
2665 int *tilesize, int *xextent, int *yextent)
2666 {
2667 grid_size_penrose(width, height, tilesize, xextent, yextent);
2668 }
2669
2670 void grid_size_penrose_p3_thick(int width, int height,
2671 int *tilesize, int *xextent, int *yextent)
2672 {
2673 grid_size_penrose(width, height, tilesize, xextent, yextent);
2674 }
2675
2676 grid *grid_new_penrose_p2_kite(int width, int height, char *desc)
2677 {
2678 return grid_new_penrose(width, height, PENROSE_P2, desc);
2679 }
2680
2681 grid *grid_new_penrose_p3_thick(int width, int height, char *desc)
2682 {
2683 return grid_new_penrose(width, height, PENROSE_P3, desc);
2684 }
2685
2686 /* ----------- End of grid generators ------------- */
2687
2688 #define FNNEW(upper,lower) &grid_new_ ## lower,
2689 #define FNSZ(upper,lower) &grid_size_ ## lower,
2690
2691 static grid *(*(grid_news[]))(int, int, char*) = { GRIDGEN_LIST(FNNEW) };
2692 static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) };
2693
2694 char *grid_new_desc(grid_type type, int width, int height, random_state *rs)
2695 {
2696 if (type != GRID_PENROSE_P2 && type != GRID_PENROSE_P3)
2697 return NULL;
2698
2699 return grid_new_desc_penrose(type, width, height, rs);
2700 }
2701
2702 char *grid_validate_desc(grid_type type, int width, int height, char *desc)
2703 {
2704 if (type != GRID_PENROSE_P2 && type != GRID_PENROSE_P3) {
2705 if (desc != NULL)
2706 return "Grid description strings not used with this grid type";
2707 return NULL;
2708 }
2709
2710 return grid_validate_desc_penrose(type, width, height, desc);
2711 }
2712
2713 grid *grid_new(grid_type type, int width, int height, char *desc)
2714 {
2715 char *err = grid_validate_desc(type, width, height, desc);
2716 if (err) assert(!"Invalid grid description.");
2717
2718 return grid_news[type](width, height, desc);
2719 }
2720
2721 void grid_compute_size(grid_type type, int width, int height,
2722 int *tilesize, int *xextent, int *yextent)
2723 {
2724 grid_sizes[type](width, height, tilesize, xextent, yextent);
2725 }
2726
2727 /* ----------- End of grid helpers ------------- */
2728
2729 /* vim: set shiftwidth=4 tabstop=8: */