A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 3866 lines 142 kB view raw
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 <float.h> 15#include <limits.h> 16#ifdef NO_TGMATH_H 17# include <math.h> 18#else 19# include <tgmath.h> 20#endif 21 22#include "puzzles.h" 23#include "tree234.h" 24#include "grid.h" 25#include "penrose-legacy.h" 26#include "penrose.h" 27#include "hat.h" 28#include "spectre.h" 29 30/* Debugging options */ 31 32/* 33#define DEBUG_GRID 34*/ 35 36/* ---------------------------------------------------------------------- 37 * Deallocate or dereference a grid 38 */ 39void grid_free(grid *g) 40{ 41 assert(g->refcount); 42 43 g->refcount--; 44 if (g->refcount == 0) { 45 int i; 46 for (i = 0; i < g->num_faces; i++) { 47 sfree(g->faces[i]->dots); 48 sfree(g->faces[i]->edges); 49 sfree(g->faces[i]); 50 } 51 for (i = 0; i < g->num_dots; i++) { 52 sfree(g->dots[i]->faces); 53 sfree(g->dots[i]->edges); 54 sfree(g->dots[i]); 55 } 56 for (i = 0; i < g->num_edges; i++) { 57 sfree(g->edges[i]); 58 } 59 sfree(g->faces); 60 sfree(g->edges); 61 sfree(g->dots); 62 sfree(g); 63 } 64} 65 66/* Used by the other grid generators. Create a brand new grid with nothing 67 * initialised (all lists are NULL) */ 68static grid *grid_empty(void) 69{ 70 grid *g = snew(grid); 71 g->faces = NULL; 72 g->edges = NULL; 73 g->dots = NULL; 74 g->num_faces = g->num_edges = g->num_dots = 0; 75 g->size_faces = g->size_edges = g->size_dots = 0; 76 g->refcount = 1; 77 g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0; 78 return g; 79} 80 81/* Helper function to calculate perpendicular distance from 82 * a point P to a line AB. A and B mustn't be equal here. 83 * 84 * Well-known formula for area A of a triangle: 85 * / 1 1 1 \ 86 * 2A = determinant of matrix | px ax bx | 87 * \ py ay by / 88 * 89 * Also well-known: 2A = base * height 90 * = perpendicular distance * line-length. 91 * 92 * Combining gives: distance = determinant / line-length(a,b) 93 */ 94static double point_line_distance(long px, long py, 95 long ax, long ay, 96 long bx, long by) 97{ 98 long det = ax*by - bx*ay + bx*py - px*by + px*ay - ax*py; 99 double len; 100 det = max(det, -det); 101 len = sqrt(SQ(ax - bx) + SQ(ay - by)); 102 return det / len; 103} 104 105/* Determine nearest edge to where the user clicked. 106 * (x, y) is the clicked location, converted to grid coordinates. 107 * Returns the nearest edge, or NULL if no edge is reasonably 108 * near the position. 109 * 110 * Just judging edges by perpendicular distance is not quite right - 111 * the edge might be "off to one side". So we insist that the triangle 112 * with (x,y) has acute angles at the edge's dots. 113 * 114 * edge1 115 * *---------*------ 116 * | 117 * | *(x,y) 118 * edge2 | 119 * | edge2 is OK, but edge1 is not, even though 120 * | edge1 is perpendicularly closer to (x,y) 121 * * 122 * 123 */ 124grid_edge *grid_nearest_edge(grid *g, int x, int y) 125{ 126 grid_edge *best_edge; 127 double best_distance = 0; 128 int i; 129 130 best_edge = NULL; 131 132 for (i = 0; i < g->num_edges; i++) { 133 grid_edge *e = g->edges[i]; 134 long e2; /* squared length of edge */ 135 long a2, b2; /* squared lengths of other sides */ 136 double dist; 137 138 /* See if edge e is eligible - the triangle must have acute angles 139 * at the edge's dots. 140 * Pythagoras formula h^2 = a^2 + b^2 detects right-angles, 141 * so detect acute angles by testing for h^2 < a^2 + b^2 */ 142 e2 = SQ((long)e->dot1->x - (long)e->dot2->x) + SQ((long)e->dot1->y - (long)e->dot2->y); 143 a2 = SQ((long)e->dot1->x - (long)x) + SQ((long)e->dot1->y - (long)y); 144 b2 = SQ((long)e->dot2->x - (long)x) + SQ((long)e->dot2->y - (long)y); 145 if (a2 >= e2 + b2) continue; 146 if (b2 >= e2 + a2) continue; 147 148 /* e is eligible so far. Now check the edge is reasonably close 149 * to where the user clicked. Don't want to toggle an edge if the 150 * click was way off the grid. 151 * There is room for experimentation here. We could check the 152 * perpendicular distance is within a certain fraction of the length 153 * of the edge. That amounts to testing a rectangular region around 154 * the edge. 155 * Alternatively, we could check that the angle at the point is obtuse. 156 * That would amount to testing a circular region with the edge as 157 * diameter. */ 158 dist = point_line_distance((long)x, (long)y, 159 (long)e->dot1->x, (long)e->dot1->y, 160 (long)e->dot2->x, (long)e->dot2->y); 161 /* Is dist more than half edge length ? */ 162 if (4 * SQ(dist) > e2) 163 continue; 164 165 if (best_edge == NULL || dist < best_distance) { 166 best_edge = e; 167 best_distance = dist; 168 } 169 } 170 return best_edge; 171} 172 173/* ---------------------------------------------------------------------- 174 * Grid generation 175 */ 176 177#ifdef SVG_GRID 178 179#define SVG_DOTS 1 180#define SVG_EDGES 2 181#define SVG_FACES 4 182 183#define FACE_COLOUR "red" 184#define EDGE_COLOUR "blue" 185#define DOT_COLOUR "black" 186 187static void grid_output_svg(FILE *fp, grid *g, int which) 188{ 189 int i, j; 190 191 fprintf(fp,"\ 192<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n\ 193<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\"\n\ 194\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n\ 195\n\ 196<svg xmlns=\"http://www.w3.org/2000/svg\"\n\ 197xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\n"); 198 199 if (which & SVG_FACES) { 200 fprintf(fp, "<g>\n"); 201 for (i = 0; i < g->num_faces; i++) { 202 grid_face *f = g->faces[i]; 203 fprintf(fp, "<polygon points=\""); 204 for (j = 0; j < f->order; j++) { 205 grid_dot *d = f->dots[j]; 206 fprintf(fp, "%s%d,%d", (j == 0) ? "" : " ", 207 d->x, d->y); 208 } 209 fprintf(fp, "\" style=\"fill: %s; fill-opacity: 0.2; stroke: %s\" />\n", 210 FACE_COLOUR, FACE_COLOUR); 211 } 212 fprintf(fp, "</g>\n"); 213 } 214 if (which & SVG_EDGES) { 215 fprintf(fp, "<g>\n"); 216 for (i = 0; i < g->num_edges; i++) { 217 grid_edge *e = g->edges[i]; 218 grid_dot *d1 = e->dot1, *d2 = e->dot2; 219 220 fprintf(fp, "<line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%d\" " 221 "style=\"stroke: %s\" />\n", 222 d1->x, d1->y, d2->x, d2->y, EDGE_COLOUR); 223 } 224 fprintf(fp, "</g>\n"); 225 } 226 227 if (which & SVG_DOTS) { 228 fprintf(fp, "<g>\n"); 229 for (i = 0; i < g->num_dots; i++) { 230 grid_dot *d = g->dots[i]; 231 fprintf(fp, "<ellipse cx=\"%d\" cy=\"%d\" rx=\"%d\" ry=\"%d\" fill=\"%s\" />", 232 d->x, d->y, g->tilesize/20, g->tilesize/20, DOT_COLOUR); 233 } 234 fprintf(fp, "</g>\n"); 235 } 236 237 fprintf(fp, "</svg>\n"); 238} 239#endif 240 241#ifdef SVG_GRID 242#include <errno.h> 243 244static void grid_try_svg(grid *g, int which) 245{ 246 char *svg = getenv("PUZZLES_SVG_GRID"); 247 if (svg) { 248 FILE *svgf = fopen(svg, "w"); 249 if (svgf) { 250 grid_output_svg(svgf, g, which); 251 fclose(svgf); 252 } else { 253 fprintf(stderr, "Unable to open file `%s': %s", svg, strerror(errno)); 254 } 255 } 256} 257#endif 258 259/* Show the basic grid information, before doing grid_make_consistent */ 260static void grid_debug_basic(grid *g) 261{ 262 /* TODO: Maybe we should generate an SVG image of the dots and lines 263 * of the grid here, before grid_make_consistent. 264 * Would help with debugging grid generation. */ 265#ifdef DEBUG_GRID 266 int i; 267 printf("--- Basic Grid Data ---\n"); 268 for (i = 0; i < g->num_dots; i++) { 269 grid_dot *d = g->dots[i]; 270 printf("Dot %d at (%d,%d)\n", i, d->x, d->y); 271 } 272 for (i = 0; i < g->num_faces; i++) { 273 grid_face *f = g->faces[i]; 274 printf("Face %d: dots[", i); 275 int j; 276 for (j = 0; j < f->order; j++) { 277 grid_dot *d = f->dots[j]; 278 printf("%s%d", j ? "," : "", (int)(d->index)); 279 } 280 printf("]\n"); 281 } 282#endif 283#ifdef SVG_GRID 284 grid_try_svg(g, SVG_FACES); 285#endif 286} 287 288/* Show the derived grid information, computed by grid_make_consistent */ 289static void grid_debug_derived(grid *g) 290{ 291#ifdef DEBUG_GRID 292 /* edges */ 293 int i; 294 printf("--- Derived Grid Data ---\n"); 295 for (i = 0; i < g->num_edges; i++) { 296 grid_edge *e = g->edges[i]; 297 printf("Edge %d: dots[%d,%d] faces[%d,%d]\n", 298 i, (int)(e->dot1->index), (int)(e->dot2->index), 299 e->face1 ? (int)(e->face1->index) : -1, 300 e->face2 ? (int)(e->face2->index) : -1); 301 } 302 /* faces */ 303 for (i = 0; i < g->num_faces; i++) { 304 grid_face *f = g->faces[i]; 305 int j; 306 printf("Face %d: faces[", i); 307 for (j = 0; j < f->order; j++) { 308 grid_edge *e = f->edges[j]; 309 grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1; 310 printf("%s%d", j ? "," : "", f2 ? f2->index : -1); 311 } 312 printf("]\n"); 313 } 314 /* dots */ 315 for (i = 0; i < g->num_dots; i++) { 316 grid_dot *d = g->dots[i]; 317 int j; 318 printf("Dot %d: dots[", i); 319 for (j = 0; j < d->order; j++) { 320 grid_edge *e = d->edges[j]; 321 grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1; 322 printf("%s%d", j ? "," : "", d2->index); 323 } 324 printf("] faces["); 325 for (j = 0; j < d->order; j++) { 326 grid_face *f = d->faces[j]; 327 printf("%s%d", j ? "," : "", f ? f->index : -1); 328 } 329 printf("]\n"); 330 } 331#endif 332#ifdef SVG_GRID 333 grid_try_svg(g, SVG_DOTS | SVG_EDGES | SVG_FACES); 334#endif 335} 336 337/* Helper function for building incomplete-edges list in 338 * grid_make_consistent() */ 339static int grid_edge_bydots_cmpfn(void *v1, void *v2) 340{ 341 grid_edge *a = v1; 342 grid_edge *b = v2; 343 grid_dot *da, *db; 344 345 /* Edges are not "normalised" - the 2 dots could be stored in any order, 346 * so we need to take this into account when comparing edges. */ 347 348 /* Compare first dots */ 349 da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2; 350 db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2; 351 if (da->index < db->index) 352 return -1; 353 if (da->index > db->index) 354 return +1; 355 /* Compare last dots */ 356 da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1; 357 db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1; 358 if (da->index < db->index) 359 return -1; 360 if (da->index > db->index) 361 return +1; 362 363 return 0; 364} 365 366/* 367 * 'Vigorously trim' a grid, by which I mean deleting any isolated or 368 * uninteresting faces. By which, in turn, I mean: ensure that the 369 * grid is composed solely of faces adjacent to at least one 370 * 'landlocked' dot (i.e. one not in contact with the infinite 371 * exterior face), and that all those dots are in a single connected 372 * component. 373 * 374 * This function operates on, and returns, a grid satisfying the 375 * preconditions to grid_make_consistent() rather than the 376 * postconditions. (So call it first.) 377 */ 378static void grid_trim_vigorously(grid *g) 379{ 380 int *dotpairs, *faces, *dots; 381 DSF *dsf; 382 int i, j, k, size, newfaces, newdots; 383 384 /* 385 * First construct a matrix in which each ordered pair of dots is 386 * mapped to the index of the face in which those dots occur in 387 * that order. 388 */ 389 dotpairs = snewn(g->num_dots * g->num_dots, int); 390 for (i = 0; i < g->num_dots; i++) 391 for (j = 0; j < g->num_dots; j++) 392 dotpairs[i*g->num_dots+j] = -1; 393 for (i = 0; i < g->num_faces; i++) { 394 grid_face *f = g->faces[i]; 395 int dot0 = f->dots[f->order-1]->index; 396 for (j = 0; j < f->order; j++) { 397 int dot1 = f->dots[j]->index; 398 dotpairs[dot0 * g->num_dots + dot1] = i; 399 dot0 = dot1; 400 } 401 } 402 403 /* 404 * Now we can identify landlocked dots: they're the ones all of 405 * whose edges have a mirror-image counterpart in this matrix. 406 */ 407 dots = snewn(g->num_dots, int); 408 for (i = 0; i < g->num_dots; i++) { 409 dots[i] = 1; 410 for (j = 0; j < g->num_dots; j++) { 411 if ((dotpairs[i*g->num_dots+j] >= 0) ^ 412 (dotpairs[j*g->num_dots+i] >= 0)) 413 dots[i] = 0; /* non-duplicated edge: coastal dot */ 414 } 415 } 416 417 /* 418 * Now identify connected pairs of landlocked dots, and form a dsf 419 * unifying them. 420 */ 421 dsf = dsf_new(g->num_dots); 422 for (i = 0; i < g->num_dots; i++) 423 for (j = 0; j < i; j++) 424 if (dots[i] && dots[j] && 425 dotpairs[i*g->num_dots+j] >= 0 && 426 dotpairs[j*g->num_dots+i] >= 0) 427 dsf_merge(dsf, i, j); 428 429 /* 430 * Now look for the largest component. 431 */ 432 size = 0; 433 j = -1; 434 for (i = 0; i < g->num_dots; i++) { 435 int newsize; 436 if (dots[i] && dsf_canonify(dsf, i) == i && 437 (newsize = dsf_size(dsf, i)) > size) { 438 j = i; 439 size = newsize; 440 } 441 } 442 443 /* 444 * Work out which faces we're going to keep (precisely those with 445 * at least one dot in the same connected component as j) and 446 * which dots (those required by any face we're keeping). 447 * 448 * At this point we reuse the 'dots' array to indicate the dots 449 * we're keeping, rather than the ones that are landlocked. 450 */ 451 faces = snewn(g->num_faces, int); 452 for (i = 0; i < g->num_faces; i++) 453 faces[i] = 0; 454 for (i = 0; i < g->num_dots; i++) 455 dots[i] = 0; 456 for (i = 0; i < g->num_faces; i++) { 457 grid_face *f = g->faces[i]; 458 bool keep = false; 459 for (k = 0; k < f->order; k++) 460 if (dsf_canonify(dsf, f->dots[k]->index) == j) 461 keep = true; 462 if (keep) { 463 faces[i] = 1; 464 for (k = 0; k < f->order; k++) 465 dots[f->dots[k]->index] = 1; 466 } 467 } 468 469 /* 470 * Compact the faces array, rewriting the faces' indices and 471 * freeing the unwanted ones. 472 */ 473 for (i = newfaces = 0; i < g->num_faces; i++) { 474 grid_face *f = g->faces[i]; 475 if (faces[i]) { 476 f->index = newfaces++; 477 g->faces[f->index] = f; 478 } else { 479 sfree(f->dots); 480 sfree(f); 481 } 482 } 483 g->num_faces = newfaces; 484 485 /* 486 * Compact the dots array, similarly. 487 */ 488 for (i = newdots = 0; i < g->num_dots; i++) { 489 grid_dot *d = g->dots[i]; 490 if (dots[i]) { 491 d->index = newdots++; 492 g->dots[d->index] = d; 493 } else { 494 sfree(d->edges); 495 sfree(d->faces); 496 sfree(d); 497 } 498 } 499 g->num_dots = newdots; 500 501 sfree(dotpairs); 502 dsf_free(dsf); 503 sfree(dots); 504 sfree(faces); 505} 506 507/* Input: grid has its dots and faces initialised: 508 * - dots have (optionally) x and y coordinates, but no edges or faces 509 * (pointers are NULL). 510 * - edges not initialised at all 511 * - faces initialised and know which dots they have (but no edges yet). The 512 * dots around each face are assumed to be clockwise. 513 * 514 * Output: grid is complete and valid with all relationships defined. 515 */ 516static void grid_make_consistent(grid *g) 517{ 518 int i; 519 tree234 *incomplete_edges; 520 521 grid_debug_basic(g); 522 523 /* ====== Stage 1 ====== 524 * Generate edges 525 */ 526 527 /* Iterate over faces, and over each face's dots, generating edges as we 528 * go. As we find each new edge, we can immediately fill in the edge's 529 * dots, but only one of the edge's faces. Later on in the iteration, we 530 * will find the same edge again (unless it's on the border), but we will 531 * know the other face. 532 * For efficiency, maintain a list of the incomplete edges, sorted by 533 * their dots. */ 534 incomplete_edges = newtree234(grid_edge_bydots_cmpfn); 535 for (i = 0; i < g->num_faces; i++) { 536 grid_face *f = g->faces[i]; 537 int j; 538 for (j = 0; j < f->order; j++) { 539 grid_edge e; /* fake edge for searching */ 540 grid_edge *edge_found; 541 int j2 = j + 1; 542 if (j2 == f->order) 543 j2 = 0; 544 e.dot1 = f->dots[j]; 545 e.dot2 = f->dots[j2]; 546 /* Use del234 instead of find234, because we always want to 547 * remove the edge if found */ 548 edge_found = del234(incomplete_edges, &e); 549 if (edge_found) { 550 /* This edge already added, so fill out missing face. 551 * Edge is already removed from incomplete_edges. */ 552 edge_found->face2 = f; 553 } else { 554 grid_edge *new_edge = snew(grid_edge); 555 new_edge->dot1 = e.dot1; 556 new_edge->dot2 = e.dot2; 557 new_edge->face1 = f; 558 new_edge->face2 = NULL; /* potentially infinite face */ 559 add234(incomplete_edges, new_edge); 560 561 /* And add it to g->edges. */ 562 if (g->num_edges >= g->size_edges) { 563 int increment = g->num_edges / 4 + 128; 564 g->size_edges = (increment < INT_MAX - g->num_edges ? 565 g->num_edges + increment : INT_MAX); 566 g->edges = sresize(g->edges, g->size_edges, grid_edge *); 567 } 568 assert(g->num_edges < INT_MAX); 569 new_edge->index = g->num_edges++; 570 g->edges[new_edge->index] = new_edge; 571 } 572 } 573 } 574 freetree234(incomplete_edges); 575 576 /* ====== Stage 2 ====== 577 * For each face, build its edge list. 578 */ 579 580 /* Allocate space for each edge list. Can do this, because each face's 581 * edge-list is the same size as its dot-list. */ 582 for (i = 0; i < g->num_faces; i++) { 583 grid_face *f = g->faces[i]; 584 int j; 585 f->edges = snewn(f->order, grid_edge*); 586 /* Preload with NULLs, to help detect potential bugs. */ 587 for (j = 0; j < f->order; j++) 588 f->edges[j] = NULL; 589 } 590 591 /* Iterate over each edge, and over both its faces. Add this edge to 592 * the face's edge-list, after finding where it should go in the 593 * sequence. */ 594 for (i = 0; i < g->num_edges; i++) { 595 grid_edge *e = g->edges[i]; 596 int j; 597 for (j = 0; j < 2; j++) { 598 grid_face *f = j ? e->face2 : e->face1; 599 int k, k2; 600 if (f == NULL) continue; 601 /* Find one of the dots around the face */ 602 for (k = 0; k < f->order; k++) { 603 if (f->dots[k] == e->dot1) 604 break; /* found dot1 */ 605 } 606 assert(k != f->order); /* Must find the dot around this face */ 607 608 /* Labelling scheme: as we walk clockwise around the face, 609 * starting at dot0 (f->dots[0]), we hit: 610 * (dot0), edge0, dot1, edge1, dot2,... 611 * 612 * 0 613 * 0-----1 614 * | 615 * |1 616 * | 617 * 3-----2 618 * 2 619 * 620 * Therefore, edgeK joins dotK and dot{K+1} 621 */ 622 623 /* Around this face, either the next dot or the previous dot 624 * must be e->dot2. Otherwise the edge is wrong. */ 625 k2 = k + 1; 626 if (k2 == f->order) 627 k2 = 0; 628 if (f->dots[k2] == e->dot2) { 629 /* dot1(k) and dot2(k2) go clockwise around this face, so add 630 * this edge at position k (see diagram). */ 631 assert(f->edges[k] == NULL); 632 f->edges[k] = e; 633 continue; 634 } 635 /* Try previous dot */ 636 k2 = k - 1; 637 if (k2 == -1) 638 k2 = f->order - 1; 639 if (f->dots[k2] == e->dot2) { 640 /* dot1(k) and dot2(k2) go anticlockwise around this face. */ 641 assert(f->edges[k2] == NULL); 642 f->edges[k2] = e; 643 continue; 644 } 645 assert(!"Grid broken: bad edge-face relationship"); 646 } 647 } 648 649 /* ====== Stage 3 ====== 650 * For each dot, build its edge-list and face-list. 651 */ 652 653 /* We don't know how many edges/faces go around each dot, so we can't 654 * allocate the right space for these lists. Pre-compute the sizes by 655 * iterating over each edge and recording a tally against each dot. */ 656 for (i = 0; i < g->num_dots; i++) { 657 g->dots[i]->order = 0; 658 } 659 for (i = 0; i < g->num_edges; i++) { 660 grid_edge *e = g->edges[i]; 661 ++(e->dot1->order); 662 ++(e->dot2->order); 663 } 664 /* Now we have the sizes, pre-allocate the edge and face lists. */ 665 for (i = 0; i < g->num_dots; i++) { 666 grid_dot *d = g->dots[i]; 667 int j; 668 assert(d->order >= 2); /* sanity check */ 669 d->edges = snewn(d->order, grid_edge*); 670 d->faces = snewn(d->order, grid_face*); 671 for (j = 0; j < d->order; j++) { 672 d->edges[j] = NULL; 673 d->faces[j] = NULL; 674 } 675 } 676 /* For each dot, need to find a face that touches it, so we can seed 677 * the edge-face-edge-face process around each dot. */ 678 for (i = 0; i < g->num_faces; i++) { 679 grid_face *f = g->faces[i]; 680 int j; 681 for (j = 0; j < f->order; j++) { 682 grid_dot *d = f->dots[j]; 683 d->faces[0] = f; 684 } 685 } 686 /* Each dot now has a face in its first slot. Generate the remaining 687 * faces and edges around the dot, by searching both clockwise and 688 * anticlockwise from the first face. Need to do both directions, 689 * because of the possibility of hitting the infinite face, which 690 * blocks progress. But there's only one such face, so we will 691 * succeed in finding every edge and face this way. */ 692 for (i = 0; i < g->num_dots; i++) { 693 grid_dot *d = g->dots[i]; 694 int current_face1 = 0; /* ascends clockwise */ 695 int current_face2 = 0; /* descends anticlockwise */ 696 697 /* Labelling scheme: as we walk clockwise around the dot, starting 698 * at face0 (d->faces[0]), we hit: 699 * (face0), edge0, face1, edge1, face2,... 700 * 701 * 0 702 * | 703 * 0 | 1 704 * | 705 * -----d-----1 706 * | 707 * | 2 708 * | 709 * 2 710 * 711 * So, for example, face1 should be joined to edge0 and edge1, 712 * and those edges should appear in an anticlockwise sense around 713 * that face (see diagram). */ 714 715 /* clockwise search */ 716 while (true) { 717 grid_face *f = d->faces[current_face1]; 718 grid_edge *e; 719 int j; 720 assert(f != NULL); 721 /* find dot around this face */ 722 for (j = 0; j < f->order; j++) { 723 if (f->dots[j] == d) 724 break; 725 } 726 assert(j != f->order); /* must find dot */ 727 728 /* Around f, required edge is anticlockwise from the dot. See 729 * the other labelling scheme higher up, for why we subtract 1 730 * from j. */ 731 j--; 732 if (j == -1) 733 j = f->order - 1; 734 e = f->edges[j]; 735 d->edges[current_face1] = e; /* set edge */ 736 current_face1++; 737 if (current_face1 == d->order) 738 break; 739 else { 740 /* set face */ 741 d->faces[current_face1] = 742 (e->face1 == f) ? e->face2 : e->face1; 743 if (d->faces[current_face1] == NULL) 744 break; /* cannot progress beyond infinite face */ 745 } 746 } 747 /* If the clockwise search made it all the way round, don't need to 748 * bother with the anticlockwise search. */ 749 if (current_face1 == d->order) 750 continue; /* this dot is complete, move on to next dot */ 751 752 /* anticlockwise search */ 753 while (true) { 754 grid_face *f = d->faces[current_face2]; 755 grid_edge *e; 756 int j; 757 assert(f != NULL); 758 /* find dot around this face */ 759 for (j = 0; j < f->order; j++) { 760 if (f->dots[j] == d) 761 break; 762 } 763 assert(j != f->order); /* must find dot */ 764 765 /* Around f, required edge is clockwise from the dot. */ 766 e = f->edges[j]; 767 768 current_face2--; 769 if (current_face2 == -1) 770 current_face2 = d->order - 1; 771 d->edges[current_face2] = e; /* set edge */ 772 773 /* set face */ 774 if (current_face2 == current_face1) 775 break; 776 d->faces[current_face2] = 777 (e->face1 == f) ? e->face2 : e->face1; 778 /* There's only 1 infinite face, so we must get all the way 779 * to current_face1 before we hit it. */ 780 assert(d->faces[current_face2]); 781 } 782 } 783 784 /* ====== Stage 4 ====== 785 * Compute other grid settings 786 */ 787 788 /* Bounding rectangle */ 789 for (i = 0; i < g->num_dots; i++) { 790 grid_dot *d = g->dots[i]; 791 if (i == 0) { 792 g->lowest_x = g->highest_x = d->x; 793 g->lowest_y = g->highest_y = d->y; 794 } else { 795 g->lowest_x = min(g->lowest_x, d->x); 796 g->highest_x = max(g->highest_x, d->x); 797 g->lowest_y = min(g->lowest_y, d->y); 798 g->highest_y = max(g->highest_y, d->y); 799 } 800 } 801 802 grid_debug_derived(g); 803} 804 805/* Helpers for making grid-generation easier. These functions are only 806 * intended for use during grid generation. */ 807 808/* Comparison function for the (tree234) sorted dot list */ 809static int grid_point_cmp_fn(void *v1, void *v2) 810{ 811 grid_dot *p1 = v1; 812 grid_dot *p2 = v2; 813 if (p1->y != p2->y) 814 return p2->y - p1->y; 815 else 816 return p2->x - p1->x; 817} 818/* Add a new face to the grid, with its dot list allocated. */ 819static void grid_face_add_new(grid *g, int face_size) 820{ 821 int i; 822 grid_face *new_face = snew(grid_face); 823 assert(g->num_faces < INT_MAX); 824 if (g->num_faces >= g->size_faces) { 825 int increment = g->num_faces / 4 + 128; 826 g->size_faces = (increment < INT_MAX - g->num_faces ? 827 g->num_faces + increment : INT_MAX); 828 g->faces = sresize(g->faces, g->size_faces, grid_face *); 829 } 830 new_face->index = g->num_faces++; 831 g->faces[new_face->index] = new_face; 832 833 new_face->order = face_size; 834 new_face->dots = snewn(face_size, grid_dot*); 835 for (i = 0; i < face_size; i++) 836 new_face->dots[i] = NULL; 837 new_face->edges = NULL; 838 new_face->has_incentre = false; 839} 840static grid_dot *grid_dot_add_new(grid *g, int x, int y) 841{ 842 grid_dot *new_dot = snew(grid_dot); 843 if (g->num_dots >= g->size_dots) { 844 int increment = g->num_dots / 4 + 128; 845 g->size_dots = (increment < INT_MAX - g->num_dots ? 846 g->num_dots + increment : INT_MAX); 847 g->dots = sresize(g->dots, g->size_dots, grid_dot *); 848 } 849 assert(g->num_dots < INT_MAX); 850 new_dot->index = g->num_dots++; 851 g->dots[new_dot->index] = new_dot; 852 853 new_dot->order = 0; 854 new_dot->edges = NULL; 855 new_dot->faces = NULL; 856 new_dot->x = x; 857 new_dot->y = y; 858 859 return new_dot; 860} 861/* Retrieve a dot with these (x,y) coordinates. Either return an existing dot 862 * in the dot_list, or add a new dot to the grid (and the dot_list) and 863 * return that. */ 864static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y) 865{ 866 grid_dot test, *ret; 867 868 test.order = 0; 869 test.edges = NULL; 870 test.faces = NULL; 871 test.x = x; 872 test.y = y; 873 ret = find234(dot_list, &test, NULL); 874 if (ret) 875 return ret; 876 877 ret = grid_dot_add_new(g, x, y); 878 add234(dot_list, ret); 879 return ret; 880} 881 882/* Sets the last face of the grid to include this dot, at this position 883 * around the face. Assumes num_faces is at least 1 (a new face has 884 * previously been added, with the required number of dots allocated) */ 885static void grid_face_set_dot(grid *g, grid_dot *d, int position) 886{ 887 grid_face *last_face = g->faces[g->num_faces - 1]; 888 last_face->dots[position] = d; 889} 890 891/* 892 * Helper routines for grid_find_incentre. 893 */ 894static bool solve_2x2_matrix(double mx[4], double vin[2], double vout[2]) 895{ 896 double inv[4]; 897 double det; 898 det = (mx[0]*mx[3] - mx[1]*mx[2]); 899 if (det == 0) 900 return false; 901 902 inv[0] = mx[3] / det; 903 inv[1] = -mx[1] / det; 904 inv[2] = -mx[2] / det; 905 inv[3] = mx[0] / det; 906 907 vout[0] = inv[0]*vin[0] + inv[1]*vin[1]; 908 vout[1] = inv[2]*vin[0] + inv[3]*vin[1]; 909 910 return true; 911} 912static bool solve_3x3_matrix(double mx[9], double vin[3], double vout[3]) 913{ 914 double inv[9]; 915 double det; 916 917 det = (mx[0]*mx[4]*mx[8] + mx[1]*mx[5]*mx[6] + mx[2]*mx[3]*mx[7] - 918 mx[0]*mx[5]*mx[7] - mx[1]*mx[3]*mx[8] - mx[2]*mx[4]*mx[6]); 919 if (det == 0) 920 return false; 921 922 inv[0] = (mx[4]*mx[8] - mx[5]*mx[7]) / det; 923 inv[1] = (mx[2]*mx[7] - mx[1]*mx[8]) / det; 924 inv[2] = (mx[1]*mx[5] - mx[2]*mx[4]) / det; 925 inv[3] = (mx[5]*mx[6] - mx[3]*mx[8]) / det; 926 inv[4] = (mx[0]*mx[8] - mx[2]*mx[6]) / det; 927 inv[5] = (mx[2]*mx[3] - mx[0]*mx[5]) / det; 928 inv[6] = (mx[3]*mx[7] - mx[4]*mx[6]) / det; 929 inv[7] = (mx[1]*mx[6] - mx[0]*mx[7]) / det; 930 inv[8] = (mx[0]*mx[4] - mx[1]*mx[3]) / det; 931 932 vout[0] = inv[0]*vin[0] + inv[1]*vin[1] + inv[2]*vin[2]; 933 vout[1] = inv[3]*vin[0] + inv[4]*vin[1] + inv[5]*vin[2]; 934 vout[2] = inv[6]*vin[0] + inv[7]*vin[1] + inv[8]*vin[2]; 935 936 return true; 937} 938 939void grid_find_incentre(grid_face *f) 940{ 941 double xbest, ybest, bestdist; 942 int i, j, k, m; 943 grid_dot *edgedot1[3], *edgedot2[3]; 944 grid_dot *dots[3]; 945 int nedges, ndots; 946 947 if (f->has_incentre) 948 return; 949 950 /* 951 * Find the point in the polygon with the maximum distance to any 952 * edge or corner. 953 * 954 * Such a point must exist which is in contact with at least three 955 * edges and/or vertices. (Proof: if it's only in contact with two 956 * edges and/or vertices, it can't even be at a _local_ maximum - 957 * any such circle can always be expanded in some direction.) So 958 * we iterate through all 3-subsets of the combined set of edges 959 * and vertices; for each subset we generate one or two candidate 960 * points that might be the incentre, and then we vet each one to 961 * see if it's inside the polygon and what its maximum radius is. 962 * 963 * (There's one case which this algorithm will get noticeably 964 * wrong, and that's when a continuum of equally good answers 965 * exists due to parallel edges. Consider a long thin rectangle, 966 * for instance, or a parallelogram. This algorithm will pick a 967 * point near one end, and choose the end arbitrarily; obviously a 968 * nicer point to choose would be in the centre. To fix this I 969 * would have to introduce a special-case system which detected 970 * parallel edges in advance, set aside all candidate points 971 * generated using both edges in a parallel pair, and generated 972 * some additional candidate points half way between them. Also, 973 * of course, I'd have to cope with rounding error making such a 974 * point look worse than one of its endpoints. So I haven't done 975 * this for the moment, and will cross it if necessary when I come 976 * to it.) 977 * 978 * We don't actually iterate literally over _edges_, in the sense 979 * of grid_edge structures. Instead, we fill in edgedot1[] and 980 * edgedot2[] with a pair of dots adjacent in the face's list of 981 * vertices. This ensures that we get the edges in consistent 982 * orientation, which we could not do from the grid structure 983 * alone. (A moment's consideration of an order-3 vertex should 984 * make it clear that if a notional arrow was written on each 985 * edge, _at least one_ of the three faces bordering that vertex 986 * would have to have the two arrows tip-to-tip or tail-to-tail 987 * rather than tip-to-tail.) 988 */ 989 nedges = ndots = 0; 990 bestdist = 0; 991 xbest = ybest = 0; 992 993 for (i = 0; i+2 < 2*f->order; i++) { 994 if (i < f->order) { 995 edgedot1[nedges] = f->dots[i]; 996 edgedot2[nedges++] = f->dots[(i+1)%f->order]; 997 } else 998 dots[ndots++] = f->dots[i - f->order]; 999 1000 for (j = i+1; j+1 < 2*f->order; j++) { 1001 if (j < f->order) { 1002 edgedot1[nedges] = f->dots[j]; 1003 edgedot2[nedges++] = f->dots[(j+1)%f->order]; 1004 } else 1005 dots[ndots++] = f->dots[j - f->order]; 1006 1007 for (k = j+1; k < 2*f->order; k++) { 1008 double cx[2], cy[2]; /* candidate positions */ 1009 int cn = 0; /* number of candidates */ 1010 1011 if (k < f->order) { 1012 edgedot1[nedges] = f->dots[k]; 1013 edgedot2[nedges++] = f->dots[(k+1)%f->order]; 1014 } else 1015 dots[ndots++] = f->dots[k - f->order]; 1016 1017 /* 1018 * Find a point, or pair of points, equidistant from 1019 * all the specified edges and/or vertices. 1020 */ 1021 if (nedges == 3) { 1022 /* 1023 * Three edges. This is a linear matrix equation: 1024 * each row of the matrix represents the fact that 1025 * the point (x,y) we seek is at distance r from 1026 * that edge, and we solve three of those 1027 * simultaneously to obtain x,y,r. (We ignore r.) 1028 */ 1029 double matrix[9], vector[3], vector2[3]; 1030 int m; 1031 1032 for (m = 0; m < 3; m++) { 1033 int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x; 1034 int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y; 1035 int dx = x2-x1, dy = y2-y1; 1036 1037 /* 1038 * ((x,y) - (x1,y1)) . (dy,-dx) = r |(dx,dy)| 1039 * 1040 * => x dy - y dx - r |(dx,dy)| = (x1 dy - y1 dx) 1041 */ 1042 matrix[3*m+0] = dy; 1043 matrix[3*m+1] = -dx; 1044 matrix[3*m+2] = -sqrt((double)dx*dx+(double)dy*dy); 1045 vector[m] = (double)x1*dy - (double)y1*dx; 1046 } 1047 1048 if (solve_3x3_matrix(matrix, vector, vector2)) { 1049 cx[cn] = vector2[0]; 1050 cy[cn] = vector2[1]; 1051 cn++; 1052 } 1053 } else if (nedges == 2) { 1054 /* 1055 * Two edges and a dot. This will end up in a 1056 * quadratic equation. 1057 * 1058 * First, look at the two edges. Having our point 1059 * be some distance r from both of them gives rise 1060 * to a pair of linear equations in x,y,r of the 1061 * form 1062 * 1063 * (x-x1) dy - (y-y1) dx = r sqrt(dx^2+dy^2) 1064 * 1065 * We eliminate r between those equations to give 1066 * us a single linear equation in x,y describing 1067 * the locus of points equidistant from both lines 1068 * - i.e. the angle bisector. 1069 * 1070 * We then choose one of x,y to be a parameter t, 1071 * and derive linear formulae for x,y,r in terms 1072 * of t. This enables us to write down the 1073 * circular equation (x-xd)^2+(y-yd)^2=r^2 as a 1074 * quadratic in t; solving that and substituting 1075 * in for x,y gives us two candidate points. 1076 */ 1077 double eqs[2][4]; /* a,b,c,d : ax+by+cr=d */ 1078 double eq[3]; /* a,b,c: ax+by=c */ 1079 double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */ 1080 double q[3]; /* a,b,c: at^2+bt+c=0 */ 1081 double disc; 1082 1083 /* Find equations of the two input lines. */ 1084 for (m = 0; m < 2; m++) { 1085 int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x; 1086 int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y; 1087 int dx = x2-x1, dy = y2-y1; 1088 1089 eqs[m][0] = dy; 1090 eqs[m][1] = -dx; 1091 eqs[m][2] = -sqrt(dx*dx+dy*dy); 1092 eqs[m][3] = x1*dy - y1*dx; 1093 } 1094 1095 /* Derive the angle bisector by eliminating r. */ 1096 eq[0] = eqs[0][0]*eqs[1][2] - eqs[1][0]*eqs[0][2]; 1097 eq[1] = eqs[0][1]*eqs[1][2] - eqs[1][1]*eqs[0][2]; 1098 eq[2] = eqs[0][3]*eqs[1][2] - eqs[1][3]*eqs[0][2]; 1099 1100 /* Parametrise x and y in terms of some t. */ 1101 if (fabs(eq[0]) < fabs(eq[1])) { 1102 /* Parameter is x. */ 1103 xt[0] = 1; xt[1] = 0; 1104 yt[0] = -eq[0]/eq[1]; yt[1] = eq[2]/eq[1]; 1105 } else { 1106 /* Parameter is y. */ 1107 yt[0] = 1; yt[1] = 0; 1108 xt[0] = -eq[1]/eq[0]; xt[1] = eq[2]/eq[0]; 1109 } 1110 1111 /* Find a linear representation of r using eqs[0]. */ 1112 rt[0] = -(eqs[0][0]*xt[0] + eqs[0][1]*yt[0])/eqs[0][2]; 1113 rt[1] = (eqs[0][3] - eqs[0][0]*xt[1] - 1114 eqs[0][1]*yt[1])/eqs[0][2]; 1115 1116 /* Construct the quadratic equation. */ 1117 q[0] = -rt[0]*rt[0]; 1118 q[1] = -2*rt[0]*rt[1]; 1119 q[2] = -rt[1]*rt[1]; 1120 q[0] += xt[0]*xt[0]; 1121 q[1] += 2*xt[0]*(xt[1]-dots[0]->x); 1122 q[2] += (xt[1]-dots[0]->x)*(xt[1]-dots[0]->x); 1123 q[0] += yt[0]*yt[0]; 1124 q[1] += 2*yt[0]*(yt[1]-dots[0]->y); 1125 q[2] += (yt[1]-dots[0]->y)*(yt[1]-dots[0]->y); 1126 1127 /* And solve it. */ 1128 disc = q[1]*q[1] - 4*q[0]*q[2]; 1129 if (disc >= 0) { 1130 double t; 1131 1132 disc = sqrt(disc); 1133 1134 t = (-q[1] + disc) / (2*q[0]); 1135 cx[cn] = xt[0]*t + xt[1]; 1136 cy[cn] = yt[0]*t + yt[1]; 1137 cn++; 1138 1139 t = (-q[1] - disc) / (2*q[0]); 1140 cx[cn] = xt[0]*t + xt[1]; 1141 cy[cn] = yt[0]*t + yt[1]; 1142 cn++; 1143 } 1144 } else if (nedges == 1) { 1145 /* 1146 * Two dots and an edge. This one's another 1147 * quadratic equation. 1148 * 1149 * The point we want must lie on the perpendicular 1150 * bisector of the two dots; that much is obvious. 1151 * So we can construct a parametrisation of that 1152 * bisecting line, giving linear formulae for x,y 1153 * in terms of t. We can also express the distance 1154 * from the edge as such a linear formula. 1155 * 1156 * Then we set that equal to the radius of the 1157 * circle passing through the two points, which is 1158 * a Pythagoras exercise; that gives rise to a 1159 * quadratic in t, which we solve. 1160 */ 1161 double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */ 1162 double q[3]; /* a,b,c: at^2+bt+c=0 */ 1163 double disc; 1164 double halfsep; 1165 1166 /* Find parametric formulae for x,y. */ 1167 { 1168 int x1 = dots[0]->x, x2 = dots[1]->x; 1169 int y1 = dots[0]->y, y2 = dots[1]->y; 1170 int dx = x2-x1, dy = y2-y1; 1171 double d = sqrt((double)dx*dx + (double)dy*dy); 1172 1173 xt[1] = (x1+x2)/2.0; 1174 yt[1] = (y1+y2)/2.0; 1175 /* It's convenient if we have t at standard scale. */ 1176 xt[0] = -dy/d; 1177 yt[0] = dx/d; 1178 1179 /* Also note down half the separation between 1180 * the dots, for use in computing the circle radius. */ 1181 halfsep = 0.5*d; 1182 } 1183 1184 /* Find a parametric formula for r. */ 1185 { 1186 int x1 = edgedot1[0]->x, x2 = edgedot2[0]->x; 1187 int y1 = edgedot1[0]->y, y2 = edgedot2[0]->y; 1188 int dx = x2-x1, dy = y2-y1; 1189 double d = sqrt((double)dx*dx + (double)dy*dy); 1190 rt[0] = (xt[0]*dy - yt[0]*dx) / d; 1191 rt[1] = ((xt[1]-x1)*dy - (yt[1]-y1)*dx) / d; 1192 } 1193 1194 /* Construct the quadratic equation. */ 1195 q[0] = rt[0]*rt[0]; 1196 q[1] = 2*rt[0]*rt[1]; 1197 q[2] = rt[1]*rt[1]; 1198 q[0] -= 1; 1199 q[2] -= halfsep*halfsep; 1200 1201 /* And solve it. */ 1202 disc = q[1]*q[1] - 4*q[0]*q[2]; 1203 if (disc >= 0) { 1204 double t; 1205 1206 disc = sqrt(disc); 1207 1208 t = (-q[1] + disc) / (2*q[0]); 1209 cx[cn] = xt[0]*t + xt[1]; 1210 cy[cn] = yt[0]*t + yt[1]; 1211 cn++; 1212 1213 t = (-q[1] - disc) / (2*q[0]); 1214 cx[cn] = xt[0]*t + xt[1]; 1215 cy[cn] = yt[0]*t + yt[1]; 1216 cn++; 1217 } 1218 } else if (nedges == 0) { 1219 /* 1220 * Three dots. This is another linear matrix 1221 * equation, this time with each row of the matrix 1222 * representing the perpendicular bisector between 1223 * two of the points. Of course we only need two 1224 * such lines to find their intersection, so we 1225 * need only solve a 2x2 matrix equation. 1226 */ 1227 1228 double matrix[4], vector[2], vector2[2]; 1229 int m; 1230 1231 for (m = 0; m < 2; m++) { 1232 int x1 = dots[m]->x, x2 = dots[m+1]->x; 1233 int y1 = dots[m]->y, y2 = dots[m+1]->y; 1234 int dx = x2-x1, dy = y2-y1; 1235 1236 /* 1237 * ((x,y) - (x1,y1)) . (dx,dy) = 1/2 |(dx,dy)|^2 1238 * 1239 * => 2x dx + 2y dy = dx^2+dy^2 + (2 x1 dx + 2 y1 dy) 1240 */ 1241 matrix[2*m+0] = 2*dx; 1242 matrix[2*m+1] = 2*dy; 1243 vector[m] = ((double)dx*dx + (double)dy*dy + 1244 2.0*x1*dx + 2.0*y1*dy); 1245 } 1246 1247 if (solve_2x2_matrix(matrix, vector, vector2)) { 1248 cx[cn] = vector2[0]; 1249 cy[cn] = vector2[1]; 1250 cn++; 1251 } 1252 } 1253 1254 /* 1255 * Now go through our candidate points and see if any 1256 * of them are better than what we've got so far. 1257 */ 1258 for (m = 0; m < cn; m++) { 1259 double x = cx[m], y = cy[m]; 1260 1261 /* 1262 * First, disqualify the point if it's not inside 1263 * the polygon, which we work out by counting the 1264 * edges to the right of the point. (For 1265 * tiebreaking purposes when edges start or end on 1266 * our y-coordinate or go right through it, we 1267 * consider our point to be offset by a small 1268 * _positive_ epsilon in both the x- and 1269 * y-direction.) 1270 */ 1271 int e; 1272 bool in = false; 1273 for (e = 0; e < f->order; e++) { 1274 int xs = f->edges[e]->dot1->x; 1275 int xe = f->edges[e]->dot2->x; 1276 int ys = f->edges[e]->dot1->y; 1277 int ye = f->edges[e]->dot2->y; 1278 if ((y >= ys && y < ye) || (y >= ye && y < ys)) { 1279 /* 1280 * The line goes past our y-position. Now we need 1281 * to know if its x-coordinate when it does so is 1282 * to our right. 1283 * 1284 * The x-coordinate in question is mathematically 1285 * (y - ys) * (xe - xs) / (ye - ys), and we want 1286 * to know whether (x - xs) >= that. Of course we 1287 * avoid the division, so we can work in integers; 1288 * to do this we must multiply both sides of the 1289 * inequality by ye - ys, which means we must 1290 * first check that's not negative. 1291 */ 1292 int num = xe - xs, denom = ye - ys; 1293 if (denom < 0) { 1294 num = -num; 1295 denom = -denom; 1296 } 1297 if ((x - xs) * denom >= (y - ys) * num) 1298 in = !in; 1299 } 1300 } 1301 1302 if (in) { 1303#ifdef HUGE_VAL 1304 double mindist = HUGE_VAL; 1305#else 1306#ifdef DBL_MAX 1307 double mindist = DBL_MAX; 1308#else 1309#error No way to get maximum floating-point number. 1310#endif 1311#endif 1312 int e, d; 1313 1314 /* 1315 * This point is inside the polygon, so now we check 1316 * its minimum distance to every edge and corner. 1317 * First the corners ... 1318 */ 1319 for (d = 0; d < f->order; d++) { 1320 int xp = f->dots[d]->x; 1321 int yp = f->dots[d]->y; 1322 double dx = x - xp, dy = y - yp; 1323 double dist = dx*dx + dy*dy; 1324 if (mindist > dist) 1325 mindist = dist; 1326 } 1327 1328 /* 1329 * ... and now also check the perpendicular distance 1330 * to every edge, if the perpendicular lies between 1331 * the edge's endpoints. 1332 */ 1333 for (e = 0; e < f->order; e++) { 1334 int xs = f->edges[e]->dot1->x; 1335 int xe = f->edges[e]->dot2->x; 1336 int ys = f->edges[e]->dot1->y; 1337 int ye = f->edges[e]->dot2->y; 1338 1339 /* 1340 * If s and e are our endpoints, and p our 1341 * candidate circle centre, the foot of a 1342 * perpendicular from p to the line se lies 1343 * between s and e if and only if (p-s).(e-s) lies 1344 * strictly between 0 and (e-s).(e-s). 1345 */ 1346 int edx = xe - xs, edy = ye - ys; 1347 double pdx = x - xs, pdy = y - ys; 1348 double pde = pdx * edx + pdy * edy; 1349 long ede = (long)edx * edx + (long)edy * edy; 1350 if (0 < pde && pde < ede) { 1351 /* 1352 * Yes, the nearest point on this edge is 1353 * closer than either endpoint, so we must 1354 * take it into account by measuring the 1355 * perpendicular distance to the edge and 1356 * checking its square against mindist. 1357 */ 1358 1359 double pdre = pdx * edy - pdy * edx; 1360 double sqlen = pdre * pdre / ede; 1361 1362 if (mindist > sqlen) 1363 mindist = sqlen; 1364 } 1365 } 1366 1367 /* 1368 * Right. Now we know the biggest circle around this 1369 * point, so we can check it against bestdist. 1370 */ 1371 if (bestdist < mindist) { 1372 bestdist = mindist; 1373 xbest = x; 1374 ybest = y; 1375 } 1376 } 1377 } 1378 1379 if (k < f->order) 1380 nedges--; 1381 else 1382 ndots--; 1383 } 1384 if (j < f->order) 1385 nedges--; 1386 else 1387 ndots--; 1388 } 1389 if (i < f->order) 1390 nedges--; 1391 else 1392 ndots--; 1393 } 1394 1395 assert(bestdist > 0); 1396 1397 f->has_incentre = true; 1398 f->ix = xbest + 0.5; /* round to nearest */ 1399 f->iy = ybest + 0.5; 1400} 1401 1402/* ------ Generate various types of grid ------ */ 1403 1404/* General method is to generate faces, by calculating their dot coordinates. 1405 * As new faces are added, we keep track of all the dots so we can tell when 1406 * a new face reuses an existing dot. For example, two squares touching at an 1407 * edge would generate six unique dots: four dots from the first face, then 1408 * two additional dots for the second face, because we detect the other two 1409 * dots have already been taken up. This list is stored in a tree234 1410 * called "points". No extra memory-allocation needed here - we store the 1411 * actual grid_dot* pointers, which all point into the g->dots list. 1412 * For this reason, we have to calculate coordinates in such a way as to 1413 * eliminate any rounding errors, so we can detect when a dot on one 1414 * face precisely lands on a dot of a different face. No floating-point 1415 * arithmetic here! 1416 */ 1417 1418#define SQUARE_TILESIZE 20 1419 1420static const char *grid_validate_params_square(int width, int height) 1421{ 1422 if (width > INT_MAX / SQUARE_TILESIZE || /* xextent */ 1423 height > INT_MAX / SQUARE_TILESIZE || /* yextent */ 1424 width + 1 > INT_MAX / (height + 1)) /* max_dots */ 1425 return "Grid size must not be unreasonably large"; 1426 return NULL; 1427} 1428 1429static void grid_size_square(int width, int height, 1430 int *tilesize, int *xextent, int *yextent) 1431{ 1432 int a = SQUARE_TILESIZE; 1433 1434 *tilesize = a; 1435 *xextent = width * a; 1436 *yextent = height * a; 1437} 1438 1439static grid *grid_new_square(int width, int height, const char *desc) 1440{ 1441 int x, y; 1442 /* Side length */ 1443 int a = SQUARE_TILESIZE; 1444 1445 tree234 *points; 1446 1447 grid *g = grid_empty(); 1448 g->tilesize = a; 1449 1450 points = newtree234(grid_point_cmp_fn); 1451 1452 /* generate square faces */ 1453 for (y = 0; y < height; y++) { 1454 for (x = 0; x < width; x++) { 1455 grid_dot *d; 1456 /* face position */ 1457 int px = a * x; 1458 int py = a * y; 1459 1460 grid_face_add_new(g, 4); 1461 d = grid_get_dot(g, points, px, py); 1462 grid_face_set_dot(g, d, 0); 1463 d = grid_get_dot(g, points, px + a, py); 1464 grid_face_set_dot(g, d, 1); 1465 d = grid_get_dot(g, points, px + a, py + a); 1466 grid_face_set_dot(g, d, 2); 1467 d = grid_get_dot(g, points, px, py + a); 1468 grid_face_set_dot(g, d, 3); 1469 } 1470 } 1471 1472 freetree234(points); 1473 1474 grid_make_consistent(g); 1475 return g; 1476} 1477 1478#define HONEY_TILESIZE 45 1479/* Vector for side of hexagon - ratio is close to sqrt(3) */ 1480#define HONEY_A 15 1481#define HONEY_B 26 1482 1483static const char *grid_validate_params_honeycomb(int width, int height) 1484{ 1485 int a = HONEY_A; 1486 int b = HONEY_B; 1487 1488 if (width - 1 > (INT_MAX - 4*a) / (3 * a) || /* xextent */ 1489 height - 1 > (INT_MAX - 3*b) / (2 * b) || /* yextent */ 1490 width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */ 1491 return "Grid size must not be unreasonably large"; 1492 return NULL; 1493} 1494 1495static void grid_size_honeycomb(int width, int height, 1496 int *tilesize, int *xextent, int *yextent) 1497{ 1498 int a = HONEY_A; 1499 int b = HONEY_B; 1500 1501 *tilesize = HONEY_TILESIZE; 1502 *xextent = (3 * a * (width-1)) + 4*a; 1503 *yextent = (2 * b * (height-1)) + 3*b; 1504} 1505 1506static grid *grid_new_honeycomb(int width, int height, const char *desc) 1507{ 1508 int x, y; 1509 int a = HONEY_A; 1510 int b = HONEY_B; 1511 1512 tree234 *points; 1513 1514 grid *g = grid_empty(); 1515 g->tilesize = HONEY_TILESIZE; 1516 1517 points = newtree234(grid_point_cmp_fn); 1518 1519 /* generate hexagonal faces */ 1520 for (y = 0; y < height; y++) { 1521 for (x = 0; x < width; x++) { 1522 grid_dot *d; 1523 /* face centre */ 1524 int cx = 3 * a * x; 1525 int cy = 2 * b * y; 1526 if (x % 2) 1527 cy += b; 1528 grid_face_add_new(g, 6); 1529 1530 d = grid_get_dot(g, points, cx - a, cy - b); 1531 grid_face_set_dot(g, d, 0); 1532 d = grid_get_dot(g, points, cx + a, cy - b); 1533 grid_face_set_dot(g, d, 1); 1534 d = grid_get_dot(g, points, cx + 2*a, cy); 1535 grid_face_set_dot(g, d, 2); 1536 d = grid_get_dot(g, points, cx + a, cy + b); 1537 grid_face_set_dot(g, d, 3); 1538 d = grid_get_dot(g, points, cx - a, cy + b); 1539 grid_face_set_dot(g, d, 4); 1540 d = grid_get_dot(g, points, cx - 2*a, cy); 1541 grid_face_set_dot(g, d, 5); 1542 } 1543 } 1544 1545 freetree234(points); 1546 1547 grid_make_consistent(g); 1548 return g; 1549} 1550 1551#define TRIANGLE_TILESIZE 18 1552/* Vector for side of triangle - ratio is close to sqrt(3) */ 1553#define TRIANGLE_VEC_X 15 1554#define TRIANGLE_VEC_Y 26 1555 1556static const char *grid_validate_params_triangular(int width, int height) 1557{ 1558 int vec_x = TRIANGLE_VEC_X; 1559 int vec_y = TRIANGLE_VEC_Y; 1560 1561 if (width > INT_MAX / (2 * vec_x) - 1 || /* xextent */ 1562 height > INT_MAX / vec_y || /* yextent */ 1563 width + 1 > INT_MAX / 4 / (height + 1)) /* max_dots */ 1564 return "Grid size must not be unreasonably large"; 1565 return NULL; 1566} 1567 1568static void grid_size_triangular(int width, int height, 1569 int *tilesize, int *xextent, int *yextent) 1570{ 1571 int vec_x = TRIANGLE_VEC_X; 1572 int vec_y = TRIANGLE_VEC_Y; 1573 1574 *tilesize = TRIANGLE_TILESIZE; 1575 *xextent = (width+1) * 2 * vec_x; 1576 *yextent = height * vec_y; 1577} 1578 1579static const char *grid_validate_desc_triangular(grid_type type, int width, 1580 int height, const char *desc) 1581{ 1582 /* 1583 * Triangular grids: an absent description is valid (indicating 1584 * the old-style approach which had 'ears', i.e. triangles 1585 * connected to only one other face, at some grid corners), and so 1586 * is a description reading just "0" (indicating the new-style 1587 * approach in which those ears are trimmed off). Anything else is 1588 * illegal. 1589 */ 1590 1591 if (!desc || !strcmp(desc, "0")) 1592 return NULL; 1593 1594 return "Unrecognised grid description."; 1595} 1596 1597/* Doesn't use the previous method of generation, it pre-dates it! 1598 * A triangular grid is just about simple enough to do by "brute force" */ 1599static grid *grid_new_triangular(int width, int height, const char *desc) 1600{ 1601 int x,y; 1602 int version = (desc == NULL ? -1 : atoi(desc)); 1603 1604 /* Vector for side of triangle - ratio is close to sqrt(3) */ 1605 int vec_x = TRIANGLE_VEC_X; 1606 int vec_y = TRIANGLE_VEC_Y; 1607 1608 int index; 1609 1610 /* convenient alias */ 1611 int w = width + 1; 1612 1613 grid *g = grid_empty(); 1614 g->tilesize = TRIANGLE_TILESIZE; 1615 1616 if (version == -1) { 1617 /* 1618 * Old-style triangular grid generation, preserved as-is for 1619 * backwards compatibility with old game ids, in which it's 1620 * just a little asymmetric and there are 'ears' (faces linked 1621 * to only one other face) at two grid corners. 1622 * 1623 * Example old-style game ids, which should still work, and in 1624 * which you should see the ears in the TL/BR corners on the 1625 * first one and in the TL/BL corners on the second: 1626 * 1627 * 5x5t1:2c2a1a2a201a1a1a1112a1a2b1211f0b21a2a2a0a 1628 * 5x6t1:a022a212h1a1d1a12c2b11a012b1a20d1a0a12e 1629 */ 1630 1631 g->num_faces = g->size_faces = width * height * 2; 1632 g->num_dots = g->size_dots = (width + 1) * (height + 1); 1633 g->faces = snewn(g->size_faces, grid_face *); 1634 g->dots = snewn(g->size_dots, grid_dot *); 1635 1636 /* generate dots */ 1637 index = 0; 1638 for (y = 0; y <= height; y++) { 1639 for (x = 0; x <= width; x++) { 1640 grid_dot *d = snew(grid_dot); 1641 d->index = index; 1642 g->dots[d->index] = d; 1643 /* odd rows are offset to the right */ 1644 d->order = 0; 1645 d->edges = NULL; 1646 d->faces = NULL; 1647 d->x = x * 2 * vec_x + ((y % 2) ? vec_x : 0); 1648 d->y = y * vec_y; 1649 index++; 1650 } 1651 } 1652 1653 /* generate faces */ 1654 index = 0; 1655 for (y = 0; y < height; y++) { 1656 for (x = 0; x < width; x++) { 1657 /* initialise two faces for this (x,y) */ 1658 grid_face *f1 = snew(grid_face), *f2 = snew(grid_face); 1659 f1->index = index; 1660 f2->index = index + 1; 1661 g->faces[f1->index] = f1; 1662 g->faces[f2->index] = f2; 1663 f1->edges = NULL; 1664 f1->order = 3; 1665 f1->dots = snewn(f1->order, grid_dot*); 1666 f1->has_incentre = false; 1667 f2->edges = NULL; 1668 f2->order = 3; 1669 f2->dots = snewn(f2->order, grid_dot*); 1670 f2->has_incentre = false; 1671 1672 /* face descriptions depend on whether the row-number is 1673 * odd or even */ 1674 if (y % 2) { 1675 f1->dots[0] = g->dots[y * w + x]; 1676 f1->dots[1] = g->dots[(y + 1) * w + x + 1]; 1677 f1->dots[2] = g->dots[(y + 1) * w + x]; 1678 f2->dots[0] = g->dots[y * w + x]; 1679 f2->dots[1] = g->dots[y * w + x + 1]; 1680 f2->dots[2] = g->dots[(y + 1) * w + x + 1]; 1681 } else { 1682 f1->dots[0] = g->dots[y * w + x]; 1683 f1->dots[1] = g->dots[y * w + x + 1]; 1684 f1->dots[2] = g->dots[(y + 1) * w + x]; 1685 f2->dots[0] = g->dots[y * w + x + 1]; 1686 f2->dots[1] = g->dots[(y + 1) * w + x + 1]; 1687 f2->dots[2] = g->dots[(y + 1) * w + x]; 1688 } 1689 index += 2; 1690 } 1691 } 1692 } else { 1693 /* 1694 * New-style approach, in which there are never any 'ears', 1695 * and if height is even then the grid is nicely 4-way 1696 * symmetric. 1697 * 1698 * Example new-style grids: 1699 * 1700 * 5x5t1:0_21120b11a1a01a1a00c1a0b211021c1h1a2a1a0a 1701 * 5x6t1:0_a1212c22c2a02a2f22a0c12a110d0e1c0c0a101121a1 1702 */ 1703 tree234 *points = newtree234(grid_point_cmp_fn); 1704 1705 for (y = 0; y < height; y++) { 1706 /* 1707 * Each row contains (width+1) triangles one way up, and 1708 * (width) triangles the other way up. Which way up is 1709 * which varies with parity of y. Also, the dots around 1710 * each face will flip direction with parity of y, so we 1711 * set up n1 and n2 to cope with that easily. 1712 */ 1713 int y0, y1, n1, n2; 1714 y0 = y1 = y * vec_y; 1715 if (y % 2) { 1716 y1 += vec_y; 1717 n1 = 2; n2 = 1; 1718 } else { 1719 y0 += vec_y; 1720 n1 = 1; n2 = 2; 1721 } 1722 1723 for (x = 0; x <= width; x++) { 1724 int x0 = 2*x * vec_x, x1 = x0 + vec_x, x2 = x1 + vec_x; 1725 1726 /* 1727 * If the grid has odd height, then we skip the first 1728 * and last triangles on this row, otherwise they'll 1729 * end up as ears. 1730 */ 1731 if (height % 2 == 1 && y == height-1 && (x == 0 || x == width)) 1732 continue; 1733 1734 grid_face_add_new(g, 3); 1735 grid_face_set_dot(g, grid_get_dot(g, points, x0, y0), 0); 1736 grid_face_set_dot(g, grid_get_dot(g, points, x1, y1), n1); 1737 grid_face_set_dot(g, grid_get_dot(g, points, x2, y0), n2); 1738 } 1739 1740 for (x = 0; x < width; x++) { 1741 int x0 = (2*x+1) * vec_x, x1 = x0 + vec_x, x2 = x1 + vec_x; 1742 1743 grid_face_add_new(g, 3); 1744 grid_face_set_dot(g, grid_get_dot(g, points, x0, y1), 0); 1745 grid_face_set_dot(g, grid_get_dot(g, points, x1, y0), n2); 1746 grid_face_set_dot(g, grid_get_dot(g, points, x2, y1), n1); 1747 } 1748 } 1749 1750 freetree234(points); 1751 } 1752 1753 grid_make_consistent(g); 1754 return g; 1755} 1756 1757#define SNUBSQUARE_TILESIZE 18 1758/* Vector for side of triangle - ratio is close to sqrt(3) */ 1759#define SNUBSQUARE_A 15 1760#define SNUBSQUARE_B 26 1761 1762static const char *grid_validate_params_snubsquare(int width, int height) 1763{ 1764 int a = SNUBSQUARE_A; 1765 int b = SNUBSQUARE_B; 1766 1767 if (width-1 > (INT_MAX - (a + b)) / (a+b) || /* xextent */ 1768 height > (INT_MAX - (a + b)) / (a+b) || /* yextent */ 1769 width > INT_MAX / 3 / height || /* max_faces */ 1770 width + 1 > INT_MAX / 2 / (height + 1)) /* max_dots */ 1771 return "Grid size must not be unreasonably large"; 1772 return NULL; 1773} 1774 1775static void grid_size_snubsquare(int width, int height, 1776 int *tilesize, int *xextent, int *yextent) 1777{ 1778 int a = SNUBSQUARE_A; 1779 int b = SNUBSQUARE_B; 1780 1781 *tilesize = SNUBSQUARE_TILESIZE; 1782 *xextent = (a+b) * (width-1) + a + b; 1783 *yextent = (a+b) * (height-1) + a + b; 1784} 1785 1786static grid *grid_new_snubsquare(int width, int height, const char *desc) 1787{ 1788 int x, y; 1789 int a = SNUBSQUARE_A; 1790 int b = SNUBSQUARE_B; 1791 1792 tree234 *points; 1793 1794 grid *g = grid_empty(); 1795 g->tilesize = SNUBSQUARE_TILESIZE; 1796 1797 points = newtree234(grid_point_cmp_fn); 1798 1799 for (y = 0; y < height; y++) { 1800 for (x = 0; x < width; x++) { 1801 grid_dot *d; 1802 /* face position */ 1803 int px = (a + b) * x; 1804 int py = (a + b) * y; 1805 1806 /* generate square faces */ 1807 grid_face_add_new(g, 4); 1808 if ((x + y) % 2) { 1809 d = grid_get_dot(g, points, px + a, py); 1810 grid_face_set_dot(g, d, 0); 1811 d = grid_get_dot(g, points, px + a + b, py + a); 1812 grid_face_set_dot(g, d, 1); 1813 d = grid_get_dot(g, points, px + b, py + a + b); 1814 grid_face_set_dot(g, d, 2); 1815 d = grid_get_dot(g, points, px, py + b); 1816 grid_face_set_dot(g, d, 3); 1817 } else { 1818 d = grid_get_dot(g, points, px + b, py); 1819 grid_face_set_dot(g, d, 0); 1820 d = grid_get_dot(g, points, px + a + b, py + b); 1821 grid_face_set_dot(g, d, 1); 1822 d = grid_get_dot(g, points, px + a, py + a + b); 1823 grid_face_set_dot(g, d, 2); 1824 d = grid_get_dot(g, points, px, py + a); 1825 grid_face_set_dot(g, d, 3); 1826 } 1827 1828 /* generate up/down triangles */ 1829 if (x > 0) { 1830 grid_face_add_new(g, 3); 1831 if ((x + y) % 2) { 1832 d = grid_get_dot(g, points, px + a, py); 1833 grid_face_set_dot(g, d, 0); 1834 d = grid_get_dot(g, points, px, py + b); 1835 grid_face_set_dot(g, d, 1); 1836 d = grid_get_dot(g, points, px - a, py); 1837 grid_face_set_dot(g, d, 2); 1838 } else { 1839 d = grid_get_dot(g, points, px, py + a); 1840 grid_face_set_dot(g, d, 0); 1841 d = grid_get_dot(g, points, px + a, py + a + b); 1842 grid_face_set_dot(g, d, 1); 1843 d = grid_get_dot(g, points, px - a, py + a + b); 1844 grid_face_set_dot(g, d, 2); 1845 } 1846 } 1847 1848 /* generate left/right triangles */ 1849 if (y > 0) { 1850 grid_face_add_new(g, 3); 1851 if ((x + y) % 2) { 1852 d = grid_get_dot(g, points, px + a, py); 1853 grid_face_set_dot(g, d, 0); 1854 d = grid_get_dot(g, points, px + a + b, py - a); 1855 grid_face_set_dot(g, d, 1); 1856 d = grid_get_dot(g, points, px + a + b, py + a); 1857 grid_face_set_dot(g, d, 2); 1858 } else { 1859 d = grid_get_dot(g, points, px, py - a); 1860 grid_face_set_dot(g, d, 0); 1861 d = grid_get_dot(g, points, px + b, py); 1862 grid_face_set_dot(g, d, 1); 1863 d = grid_get_dot(g, points, px, py + a); 1864 grid_face_set_dot(g, d, 2); 1865 } 1866 } 1867 } 1868 } 1869 1870 freetree234(points); 1871 1872 grid_make_consistent(g); 1873 return g; 1874} 1875 1876#define CAIRO_TILESIZE 40 1877/* Vector for side of pentagon - ratio is close to (4+sqrt(7))/3 */ 1878#define CAIRO_A 14 1879#define CAIRO_B 31 1880 1881static const char *grid_validate_params_cairo(int width, int height) 1882{ 1883 int b = CAIRO_B; /* a unused in determining grid size. */ 1884 1885 if (width - 1 > (INT_MAX - 2*b) / (2*b) || /* xextent */ 1886 height - 1 > (INT_MAX - 2*b) / (2*b) || /* yextent */ 1887 width > INT_MAX / 2 / height || /* max_faces */ 1888 width + 1 > INT_MAX / 3 / (height + 1)) /* max_dots */ 1889 return "Grid size must not be unreasonably large"; 1890 return NULL; 1891} 1892 1893static void grid_size_cairo(int width, int height, 1894 int *tilesize, int *xextent, int *yextent) 1895{ 1896 int b = CAIRO_B; /* a unused in determining grid size. */ 1897 1898 *tilesize = CAIRO_TILESIZE; 1899 *xextent = 2*b*(width-1) + 2*b; 1900 *yextent = 2*b*(height-1) + 2*b; 1901} 1902 1903static grid *grid_new_cairo(int width, int height, const char *desc) 1904{ 1905 int x, y; 1906 int a = CAIRO_A; 1907 int b = CAIRO_B; 1908 1909 tree234 *points; 1910 1911 grid *g = grid_empty(); 1912 g->tilesize = CAIRO_TILESIZE; 1913 1914 points = newtree234(grid_point_cmp_fn); 1915 1916 for (y = 0; y < height; y++) { 1917 for (x = 0; x < width; x++) { 1918 grid_dot *d; 1919 /* cell position */ 1920 int px = 2 * b * x; 1921 int py = 2 * b * y; 1922 1923 /* horizontal pentagons */ 1924 if (y > 0) { 1925 grid_face_add_new(g, 5); 1926 if ((x + y) % 2) { 1927 d = grid_get_dot(g, points, px + a, py - b); 1928 grid_face_set_dot(g, d, 0); 1929 d = grid_get_dot(g, points, px + 2*b - a, py - b); 1930 grid_face_set_dot(g, d, 1); 1931 d = grid_get_dot(g, points, px + 2*b, py); 1932 grid_face_set_dot(g, d, 2); 1933 d = grid_get_dot(g, points, px + b, py + a); 1934 grid_face_set_dot(g, d, 3); 1935 d = grid_get_dot(g, points, px, py); 1936 grid_face_set_dot(g, d, 4); 1937 } else { 1938 d = grid_get_dot(g, points, px, py); 1939 grid_face_set_dot(g, d, 0); 1940 d = grid_get_dot(g, points, px + b, py - a); 1941 grid_face_set_dot(g, d, 1); 1942 d = grid_get_dot(g, points, px + 2*b, py); 1943 grid_face_set_dot(g, d, 2); 1944 d = grid_get_dot(g, points, px + 2*b - a, py + b); 1945 grid_face_set_dot(g, d, 3); 1946 d = grid_get_dot(g, points, px + a, py + b); 1947 grid_face_set_dot(g, d, 4); 1948 } 1949 } 1950 /* vertical pentagons */ 1951 if (x > 0) { 1952 grid_face_add_new(g, 5); 1953 if ((x + y) % 2) { 1954 d = grid_get_dot(g, points, px, py); 1955 grid_face_set_dot(g, d, 0); 1956 d = grid_get_dot(g, points, px + b, py + a); 1957 grid_face_set_dot(g, d, 1); 1958 d = grid_get_dot(g, points, px + b, py + 2*b - a); 1959 grid_face_set_dot(g, d, 2); 1960 d = grid_get_dot(g, points, px, py + 2*b); 1961 grid_face_set_dot(g, d, 3); 1962 d = grid_get_dot(g, points, px - a, py + b); 1963 grid_face_set_dot(g, d, 4); 1964 } else { 1965 d = grid_get_dot(g, points, px, py); 1966 grid_face_set_dot(g, d, 0); 1967 d = grid_get_dot(g, points, px + a, py + b); 1968 grid_face_set_dot(g, d, 1); 1969 d = grid_get_dot(g, points, px, py + 2*b); 1970 grid_face_set_dot(g, d, 2); 1971 d = grid_get_dot(g, points, px - b, py + 2*b - a); 1972 grid_face_set_dot(g, d, 3); 1973 d = grid_get_dot(g, points, px - b, py + a); 1974 grid_face_set_dot(g, d, 4); 1975 } 1976 } 1977 } 1978 } 1979 1980 freetree234(points); 1981 1982 grid_make_consistent(g); 1983 return g; 1984} 1985 1986#define GREATHEX_TILESIZE 18 1987/* Vector for side of triangle - ratio is close to sqrt(3) */ 1988#define GREATHEX_A 15 1989#define GREATHEX_B 26 1990 1991static const char *grid_validate_params_greathexagonal(int width, int height) 1992{ 1993 int a = GREATHEX_A; 1994 int b = GREATHEX_B; 1995 1996 if (width-1 > (INT_MAX - 4*a) / (3*a + b) || /* xextent */ 1997 height-1 > (INT_MAX - (3*b + a)) / (2*a + 2*b) || /* yextent */ 1998 width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */ 1999 return "Grid size must not be unreasonably large"; 2000 return NULL; 2001} 2002 2003static void grid_size_greathexagonal(int width, int height, 2004 int *tilesize, int *xextent, int *yextent) 2005{ 2006 int a = GREATHEX_A; 2007 int b = GREATHEX_B; 2008 2009 *tilesize = GREATHEX_TILESIZE; 2010 *xextent = (3*a + b) * (width-1) + 4*a; 2011 *yextent = (2*a + 2*b) * (height-1) + 3*b + a; 2012} 2013 2014static grid *grid_new_greathexagonal(int width, int height, const char *desc) 2015{ 2016 int x, y; 2017 int a = GREATHEX_A; 2018 int b = GREATHEX_B; 2019 2020 tree234 *points; 2021 2022 grid *g = grid_empty(); 2023 g->tilesize = GREATHEX_TILESIZE; 2024 2025 points = newtree234(grid_point_cmp_fn); 2026 2027 for (y = 0; y < height; y++) { 2028 for (x = 0; x < width; x++) { 2029 grid_dot *d; 2030 /* centre of hexagon */ 2031 int px = (3*a + b) * x; 2032 int py = (2*a + 2*b) * y; 2033 if (x % 2) 2034 py += a + b; 2035 2036 /* hexagon */ 2037 grid_face_add_new(g, 6); 2038 d = grid_get_dot(g, points, px - a, py - b); 2039 grid_face_set_dot(g, d, 0); 2040 d = grid_get_dot(g, points, px + a, py - b); 2041 grid_face_set_dot(g, d, 1); 2042 d = grid_get_dot(g, points, px + 2*a, py); 2043 grid_face_set_dot(g, d, 2); 2044 d = grid_get_dot(g, points, px + a, py + b); 2045 grid_face_set_dot(g, d, 3); 2046 d = grid_get_dot(g, points, px - a, py + b); 2047 grid_face_set_dot(g, d, 4); 2048 d = grid_get_dot(g, points, px - 2*a, py); 2049 grid_face_set_dot(g, d, 5); 2050 2051 /* square below hexagon */ 2052 if (y < height - 1) { 2053 grid_face_add_new(g, 4); 2054 d = grid_get_dot(g, points, px - a, py + b); 2055 grid_face_set_dot(g, d, 0); 2056 d = grid_get_dot(g, points, px + a, py + b); 2057 grid_face_set_dot(g, d, 1); 2058 d = grid_get_dot(g, points, px + a, py + 2*a + b); 2059 grid_face_set_dot(g, d, 2); 2060 d = grid_get_dot(g, points, px - a, py + 2*a + b); 2061 grid_face_set_dot(g, d, 3); 2062 } 2063 2064 /* square below right */ 2065 if ((x < width - 1) && (((x % 2) == 0) || (y < height - 1))) { 2066 grid_face_add_new(g, 4); 2067 d = grid_get_dot(g, points, px + 2*a, py); 2068 grid_face_set_dot(g, d, 0); 2069 d = grid_get_dot(g, points, px + 2*a + b, py + a); 2070 grid_face_set_dot(g, d, 1); 2071 d = grid_get_dot(g, points, px + a + b, py + a + b); 2072 grid_face_set_dot(g, d, 2); 2073 d = grid_get_dot(g, points, px + a, py + b); 2074 grid_face_set_dot(g, d, 3); 2075 } 2076 2077 /* square below left */ 2078 if ((x > 0) && (((x % 2) == 0) || (y < height - 1))) { 2079 grid_face_add_new(g, 4); 2080 d = grid_get_dot(g, points, px - 2*a, py); 2081 grid_face_set_dot(g, d, 0); 2082 d = grid_get_dot(g, points, px - a, py + b); 2083 grid_face_set_dot(g, d, 1); 2084 d = grid_get_dot(g, points, px - a - b, py + a + b); 2085 grid_face_set_dot(g, d, 2); 2086 d = grid_get_dot(g, points, px - 2*a - b, py + a); 2087 grid_face_set_dot(g, d, 3); 2088 } 2089 2090 /* Triangle below right */ 2091 if ((x < width - 1) && (y < height - 1)) { 2092 grid_face_add_new(g, 3); 2093 d = grid_get_dot(g, points, px + a, py + b); 2094 grid_face_set_dot(g, d, 0); 2095 d = grid_get_dot(g, points, px + a + b, py + a + b); 2096 grid_face_set_dot(g, d, 1); 2097 d = grid_get_dot(g, points, px + a, py + 2*a + b); 2098 grid_face_set_dot(g, d, 2); 2099 } 2100 2101 /* Triangle below left */ 2102 if ((x > 0) && (y < height - 1)) { 2103 grid_face_add_new(g, 3); 2104 d = grid_get_dot(g, points, px - a, py + b); 2105 grid_face_set_dot(g, d, 0); 2106 d = grid_get_dot(g, points, px - a, py + 2*a + b); 2107 grid_face_set_dot(g, d, 1); 2108 d = grid_get_dot(g, points, px - a - b, py + a + b); 2109 grid_face_set_dot(g, d, 2); 2110 } 2111 } 2112 } 2113 2114 freetree234(points); 2115 2116 grid_make_consistent(g); 2117 return g; 2118} 2119 2120#define KAGOME_TILESIZE 18 2121/* Vector for side of triangle - ratio is close to sqrt(3) */ 2122#define KAGOME_A 15 2123#define KAGOME_B 26 2124 2125static const char *grid_validate_params_kagome(int width, int height) 2126{ 2127 int a = KAGOME_A; 2128 int b = KAGOME_B; 2129 2130 if (width-1 > (INT_MAX - 6*a) / (4*a) || /* xextent */ 2131 height-1 > (INT_MAX - 2*b) / (2*b) || /* yextent */ 2132 width + 1 > INT_MAX / 6 / (height + 1)) /* max_faces */ 2133 return "Grid size must not be unreasonably large"; 2134 return NULL; 2135} 2136 2137static void grid_size_kagome(int width, int height, 2138 int *tilesize, int *xextent, int *yextent) 2139{ 2140 int a = KAGOME_A; 2141 int b = KAGOME_B; 2142 2143 *tilesize = KAGOME_TILESIZE; 2144 *xextent = (4*a) * (width-1) + 6*a; 2145 *yextent = (2*b) * (height-1) + 2*b; 2146} 2147 2148static grid *grid_new_kagome(int width, int height, const char *desc) 2149{ 2150 int x, y; 2151 int a = KAGOME_A; 2152 int b = KAGOME_B; 2153 2154 tree234 *points; 2155 2156 grid *g = grid_empty(); 2157 g->tilesize = KAGOME_TILESIZE; 2158 2159 points = newtree234(grid_point_cmp_fn); 2160 2161 for (y = 0; y < height; y++) { 2162 for (x = 0; x < width; x++) { 2163 grid_dot *d; 2164 /* centre of hexagon */ 2165 int px = (4*a) * x; 2166 int py = (2*b) * y; 2167 if (y % 2) 2168 px += 2*a; 2169 2170 /* hexagon */ 2171 grid_face_add_new(g, 6); 2172 d = grid_get_dot(g, points, px + a, py - b); grid_face_set_dot(g, d, 0); 2173 d = grid_get_dot(g, points, px + 2*a, py ); grid_face_set_dot(g, d, 1); 2174 d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 2); 2175 d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 3); 2176 d = grid_get_dot(g, points, px - 2*a, py ); grid_face_set_dot(g, d, 4); 2177 d = grid_get_dot(g, points, px - a, py - b); grid_face_set_dot(g, d, 5); 2178 2179 /* Triangle above right */ 2180 if ((x < width - 1) || (!(y % 2) && y)) { 2181 grid_face_add_new(g, 3); 2182 d = grid_get_dot(g, points, px + 3*a, py - b); grid_face_set_dot(g, d, 0); 2183 d = grid_get_dot(g, points, px + 2*a, py ); grid_face_set_dot(g, d, 1); 2184 d = grid_get_dot(g, points, px + a, py - b); grid_face_set_dot(g, d, 2); 2185 } 2186 2187 /* Triangle below right */ 2188 if ((x < width - 1) || (!(y % 2) && (y < height - 1))) { 2189 grid_face_add_new(g, 3); 2190 d = grid_get_dot(g, points, px + 3*a, py + b); grid_face_set_dot(g, d, 0); 2191 d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 1); 2192 d = grid_get_dot(g, points, px + 2*a, py ); grid_face_set_dot(g, d, 2); 2193 } 2194 2195 /* Left triangles */ 2196 if (!x && (y % 2)) { 2197 /* Triangle above left */ 2198 grid_face_add_new(g, 3); 2199 d = grid_get_dot(g, points, px - a, py - b); grid_face_set_dot(g, d, 0); 2200 d = grid_get_dot(g, points, px - 2*a, py ); grid_face_set_dot(g, d, 1); 2201 d = grid_get_dot(g, points, px - 3*a, py - b); grid_face_set_dot(g, d, 2); 2202 2203 /* Triangle below left */ 2204 if (y < height - 1) { 2205 grid_face_add_new(g, 3); 2206 d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 0); 2207 d = grid_get_dot(g, points, px - 3*a, py + b); grid_face_set_dot(g, d, 1); 2208 d = grid_get_dot(g, points, px - 2*a, py ); grid_face_set_dot(g, d, 2); 2209 } 2210 } 2211 } 2212 } 2213 2214 freetree234(points); 2215 2216 grid_make_consistent(g); 2217 return g; 2218} 2219 2220#define OCTAGONAL_TILESIZE 40 2221/* b/a approx sqrt(2) */ 2222#define OCTAGONAL_A 29 2223#define OCTAGONAL_B 41 2224 2225static const char *grid_validate_params_octagonal(int width, int height) 2226{ 2227 int a = OCTAGONAL_A; 2228 int b = OCTAGONAL_B; 2229 2230 if (width > INT_MAX / (2*a + b) || /* xextent */ 2231 height > INT_MAX / (2*a + b) || /* yextent */ 2232 height + 1 > INT_MAX / 4 / (width + 1)) /* max_dots */ 2233 return "Grid size must not be unreasonably large"; 2234 return NULL; 2235} 2236 2237static void grid_size_octagonal(int width, int height, 2238 int *tilesize, int *xextent, int *yextent) 2239{ 2240 int a = OCTAGONAL_A; 2241 int b = OCTAGONAL_B; 2242 2243 *tilesize = OCTAGONAL_TILESIZE; 2244 *xextent = (2*a + b) * width; 2245 *yextent = (2*a + b) * height; 2246} 2247 2248static grid *grid_new_octagonal(int width, int height, const char *desc) 2249{ 2250 int x, y; 2251 int a = OCTAGONAL_A; 2252 int b = OCTAGONAL_B; 2253 2254 tree234 *points; 2255 2256 grid *g = grid_empty(); 2257 g->tilesize = OCTAGONAL_TILESIZE; 2258 2259 points = newtree234(grid_point_cmp_fn); 2260 2261 for (y = 0; y < height; y++) { 2262 for (x = 0; x < width; x++) { 2263 grid_dot *d; 2264 /* cell position */ 2265 int px = (2*a + b) * x; 2266 int py = (2*a + b) * y; 2267 /* octagon */ 2268 grid_face_add_new(g, 8); 2269 d = grid_get_dot(g, points, px + a, py); 2270 grid_face_set_dot(g, d, 0); 2271 d = grid_get_dot(g, points, px + a + b, py); 2272 grid_face_set_dot(g, d, 1); 2273 d = grid_get_dot(g, points, px + 2*a + b, py + a); 2274 grid_face_set_dot(g, d, 2); 2275 d = grid_get_dot(g, points, px + 2*a + b, py + a + b); 2276 grid_face_set_dot(g, d, 3); 2277 d = grid_get_dot(g, points, px + a + b, py + 2*a + b); 2278 grid_face_set_dot(g, d, 4); 2279 d = grid_get_dot(g, points, px + a, py + 2*a + b); 2280 grid_face_set_dot(g, d, 5); 2281 d = grid_get_dot(g, points, px, py + a + b); 2282 grid_face_set_dot(g, d, 6); 2283 d = grid_get_dot(g, points, px, py + a); 2284 grid_face_set_dot(g, d, 7); 2285 2286 /* diamond */ 2287 if ((x > 0) && (y > 0)) { 2288 grid_face_add_new(g, 4); 2289 d = grid_get_dot(g, points, px, py - a); 2290 grid_face_set_dot(g, d, 0); 2291 d = grid_get_dot(g, points, px + a, py); 2292 grid_face_set_dot(g, d, 1); 2293 d = grid_get_dot(g, points, px, py + a); 2294 grid_face_set_dot(g, d, 2); 2295 d = grid_get_dot(g, points, px - a, py); 2296 grid_face_set_dot(g, d, 3); 2297 } 2298 } 2299 } 2300 2301 freetree234(points); 2302 2303 grid_make_consistent(g); 2304 return g; 2305} 2306 2307#define KITE_TILESIZE 40 2308/* b/a approx sqrt(3) */ 2309#define KITE_A 15 2310#define KITE_B 26 2311 2312static const char *grid_validate_params_kites(int width, int height) 2313{ 2314 int a = KITE_A; 2315 int b = KITE_B; 2316 2317 if (width > (INT_MAX - 2*b) / (4*b) || /* xextent */ 2318 height - 1 > (INT_MAX - 8*a) / (6*a) || /* yextent */ 2319 width + 1 > INT_MAX / 6 / (height + 1)) /* max_dots */ 2320 return "Grid size must not be unreasonably large"; 2321 return NULL; 2322} 2323 2324static void grid_size_kites(int width, int height, 2325 int *tilesize, int *xextent, int *yextent) 2326{ 2327 int a = KITE_A; 2328 int b = KITE_B; 2329 2330 *tilesize = KITE_TILESIZE; 2331 *xextent = 4*b * width + 2*b; 2332 *yextent = 6*a * (height-1) + 8*a; 2333} 2334 2335static grid *grid_new_kites(int width, int height, const char *desc) 2336{ 2337 int x, y; 2338 int a = KITE_A; 2339 int b = KITE_B; 2340 2341 tree234 *points; 2342 2343 grid *g = grid_empty(); 2344 g->tilesize = KITE_TILESIZE; 2345 2346 points = newtree234(grid_point_cmp_fn); 2347 2348 for (y = 0; y < height; y++) { 2349 for (x = 0; x < width; x++) { 2350 grid_dot *d; 2351 /* position of order-6 dot */ 2352 int px = 4*b * x; 2353 int py = 6*a * y; 2354 if (y % 2) 2355 px += 2*b; 2356 2357 /* kite pointing up-left */ 2358 grid_face_add_new(g, 4); 2359 d = grid_get_dot(g, points, px, py); 2360 grid_face_set_dot(g, d, 0); 2361 d = grid_get_dot(g, points, px + 2*b, py); 2362 grid_face_set_dot(g, d, 1); 2363 d = grid_get_dot(g, points, px + 2*b, py + 2*a); 2364 grid_face_set_dot(g, d, 2); 2365 d = grid_get_dot(g, points, px + b, py + 3*a); 2366 grid_face_set_dot(g, d, 3); 2367 2368 /* kite pointing up */ 2369 grid_face_add_new(g, 4); 2370 d = grid_get_dot(g, points, px, py); 2371 grid_face_set_dot(g, d, 0); 2372 d = grid_get_dot(g, points, px + b, py + 3*a); 2373 grid_face_set_dot(g, d, 1); 2374 d = grid_get_dot(g, points, px, py + 4*a); 2375 grid_face_set_dot(g, d, 2); 2376 d = grid_get_dot(g, points, px - b, py + 3*a); 2377 grid_face_set_dot(g, d, 3); 2378 2379 /* kite pointing up-right */ 2380 grid_face_add_new(g, 4); 2381 d = grid_get_dot(g, points, px, py); 2382 grid_face_set_dot(g, d, 0); 2383 d = grid_get_dot(g, points, px - b, py + 3*a); 2384 grid_face_set_dot(g, d, 1); 2385 d = grid_get_dot(g, points, px - 2*b, py + 2*a); 2386 grid_face_set_dot(g, d, 2); 2387 d = grid_get_dot(g, points, px - 2*b, py); 2388 grid_face_set_dot(g, d, 3); 2389 2390 /* kite pointing down-right */ 2391 grid_face_add_new(g, 4); 2392 d = grid_get_dot(g, points, px, py); 2393 grid_face_set_dot(g, d, 0); 2394 d = grid_get_dot(g, points, px - 2*b, py); 2395 grid_face_set_dot(g, d, 1); 2396 d = grid_get_dot(g, points, px - 2*b, py - 2*a); 2397 grid_face_set_dot(g, d, 2); 2398 d = grid_get_dot(g, points, px - b, py - 3*a); 2399 grid_face_set_dot(g, d, 3); 2400 2401 /* kite pointing down */ 2402 grid_face_add_new(g, 4); 2403 d = grid_get_dot(g, points, px, py); 2404 grid_face_set_dot(g, d, 0); 2405 d = grid_get_dot(g, points, px - b, py - 3*a); 2406 grid_face_set_dot(g, d, 1); 2407 d = grid_get_dot(g, points, px, py - 4*a); 2408 grid_face_set_dot(g, d, 2); 2409 d = grid_get_dot(g, points, px + b, py - 3*a); 2410 grid_face_set_dot(g, d, 3); 2411 2412 /* kite pointing down-left */ 2413 grid_face_add_new(g, 4); 2414 d = grid_get_dot(g, points, px, py); 2415 grid_face_set_dot(g, d, 0); 2416 d = grid_get_dot(g, points, px + b, py - 3*a); 2417 grid_face_set_dot(g, d, 1); 2418 d = grid_get_dot(g, points, px + 2*b, py - 2*a); 2419 grid_face_set_dot(g, d, 2); 2420 d = grid_get_dot(g, points, px + 2*b, py); 2421 grid_face_set_dot(g, d, 3); 2422 } 2423 } 2424 2425 freetree234(points); 2426 2427 grid_make_consistent(g); 2428 return g; 2429} 2430 2431#define FLORET_TILESIZE 150 2432/* -py/px is close to tan(30 - atan(sqrt(3)/9)) 2433 * using py=26 makes everything lean to the left, rather than right 2434 */ 2435#define FLORET_PX 75 2436#define FLORET_PY -26 2437 2438static const char *grid_validate_params_floret(int width, int height) 2439{ 2440 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ 2441 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ 2442 int ry = qy-py; 2443 /* rx unused in determining grid size. */ 2444 2445 if (width - 1 > (INT_MAX - (4*px + 2*qx)) / ((6*px+3*qx)/2) ||/* xextent */ 2446 height - 1 > (INT_MAX - (4*ry - 2*qy)) / (5*qy-4*py) || /* yextent */ 2447 width + 1 > INT_MAX / 9 / (height + 1)) /* max_dots */ 2448 return "Grid size must not be unreasonably large"; 2449 return NULL; 2450} 2451 2452static void grid_size_floret(int width, int height, 2453 int *tilesize, int *xextent, int *yextent) 2454{ 2455 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ 2456 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ 2457 int ry = qy-py; 2458 /* rx unused in determining grid size. */ 2459 2460 *tilesize = FLORET_TILESIZE; 2461 *xextent = (6*px+3*qx)/2 * (width-1) + 4*px + 2*qx; 2462 *yextent = (5*qy-4*py) * (height-1) + 4*ry + 2*qy; 2463 if (height == 1) 2464 *yextent += (5*qy-4*py)/2; 2465} 2466 2467static grid *grid_new_floret(int width, int height, const char *desc) 2468{ 2469 int x, y; 2470 /* Vectors for sides; weird numbers needed to keep puzzle aligned with window 2471 * -py/px is close to tan(30 - atan(sqrt(3)/9)) 2472 * using py=26 makes everything lean to the left, rather than right 2473 */ 2474 int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ 2475 int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ 2476 int rx = qx-px, ry = qy-py; /* |(-15, 78)| = 79.38 */ 2477 2478 tree234 *points; 2479 2480 grid *g = grid_empty(); 2481 g->tilesize = FLORET_TILESIZE; 2482 2483 points = newtree234(grid_point_cmp_fn); 2484 2485 /* generate pentagonal faces */ 2486 for (y = 0; y < height; y++) { 2487 for (x = 0; x < width; x++) { 2488 grid_dot *d; 2489 /* face centre */ 2490 int cx = (6*px+3*qx)/2 * x; 2491 int cy = (4*py-5*qy) * y; 2492 if (x % 2) 2493 cy -= (4*py-5*qy)/2; 2494 else if (y && y == height-1 && width > 1) 2495 continue; /* make better looking grids? try 3x3 for instance */ 2496 2497 grid_face_add_new(g, 5); 2498 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2499 d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 1); 2500 d = grid_get_dot(g, points, cx+2*rx+qx, cy+2*ry+qy); grid_face_set_dot(g, d, 2); 2501 d = grid_get_dot(g, points, cx+2*qx+rx, cy+2*qy+ry); grid_face_set_dot(g, d, 3); 2502 d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 4); 2503 2504 grid_face_add_new(g, 5); 2505 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2506 d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 1); 2507 d = grid_get_dot(g, points, cx+2*qx+px, cy+2*qy+py); grid_face_set_dot(g, d, 2); 2508 d = grid_get_dot(g, points, cx+2*px+qx, cy+2*py+qy); grid_face_set_dot(g, d, 3); 2509 d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 4); 2510 2511 grid_face_add_new(g, 5); 2512 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2513 d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 1); 2514 d = grid_get_dot(g, points, cx+2*px-rx, cy+2*py-ry); grid_face_set_dot(g, d, 2); 2515 d = grid_get_dot(g, points, cx-2*rx+px, cy-2*ry+py); grid_face_set_dot(g, d, 3); 2516 d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 4); 2517 2518 grid_face_add_new(g, 5); 2519 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2520 d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 1); 2521 d = grid_get_dot(g, points, cx-2*rx-qx, cy-2*ry-qy); grid_face_set_dot(g, d, 2); 2522 d = grid_get_dot(g, points, cx-2*qx-rx, cy-2*qy-ry); grid_face_set_dot(g, d, 3); 2523 d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 4); 2524 2525 grid_face_add_new(g, 5); 2526 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2527 d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 1); 2528 d = grid_get_dot(g, points, cx-2*qx-px, cy-2*qy-py); grid_face_set_dot(g, d, 2); 2529 d = grid_get_dot(g, points, cx-2*px-qx, cy-2*py-qy); grid_face_set_dot(g, d, 3); 2530 d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 4); 2531 2532 grid_face_add_new(g, 5); 2533 d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); 2534 d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 1); 2535 d = grid_get_dot(g, points, cx-2*px+rx, cy-2*py+ry); grid_face_set_dot(g, d, 2); 2536 d = grid_get_dot(g, points, cx+2*rx-px, cy+2*ry-py); grid_face_set_dot(g, d, 3); 2537 d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 4); 2538 } 2539 } 2540 2541 freetree234(points); 2542 2543 grid_make_consistent(g); 2544 return g; 2545} 2546 2547/* DODEC_* are used for dodecagonal and great-dodecagonal grids. */ 2548#define DODEC_TILESIZE 26 2549/* Vector for side of triangle - ratio is close to sqrt(3) */ 2550#define DODEC_A 15 2551#define DODEC_B 26 2552 2553static const char *grid_validate_params_dodecagonal(int width, int height) 2554{ 2555 int a = DODEC_A; 2556 int b = DODEC_B; 2557 2558 if (width - 1 > (INT_MAX - 3*(2*a + b)) / (4*a + 2*b) || /* xextent */ 2559 height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 2*b) || /* yextent */ 2560 width > INT_MAX / 14 / height) /* max_dots */ 2561 return "Grid size must not be unreasonably large"; 2562 return NULL; 2563} 2564 2565static void grid_size_dodecagonal(int width, int height, 2566 int *tilesize, int *xextent, int *yextent) 2567{ 2568 int a = DODEC_A; 2569 int b = DODEC_B; 2570 2571 *tilesize = DODEC_TILESIZE; 2572 *xextent = (4*a + 2*b) * (width-1) + 3*(2*a + b); 2573 *yextent = (3*a + 2*b) * (height-1) + 2*(2*a + b); 2574} 2575 2576static grid *grid_new_dodecagonal(int width, int height, const char *desc) 2577{ 2578 int x, y; 2579 int a = DODEC_A; 2580 int b = DODEC_B; 2581 2582 tree234 *points; 2583 2584 grid *g = grid_empty(); 2585 g->tilesize = DODEC_TILESIZE; 2586 2587 points = newtree234(grid_point_cmp_fn); 2588 2589 for (y = 0; y < height; y++) { 2590 for (x = 0; x < width; x++) { 2591 grid_dot *d; 2592 /* centre of dodecagon */ 2593 int px = (4*a + 2*b) * x; 2594 int py = (3*a + 2*b) * y; 2595 if (y % 2) 2596 px += 2*a + b; 2597 2598 /* dodecagon */ 2599 grid_face_add_new(g, 12); 2600 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2601 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); 2602 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); 2603 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); 2604 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); 2605 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); 2606 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); 2607 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); 2608 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); 2609 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); 2610 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); 2611 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); 2612 2613 /* triangle below dodecagon */ 2614 if ((y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) { 2615 grid_face_add_new(g, 3); 2616 d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); 2617 d = grid_get_dot(g, points, px , py + (2*a + 2*b)); grid_face_set_dot(g, d, 1); 2618 d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 2); 2619 } 2620 2621 /* triangle above dodecagon */ 2622 if ((y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) { 2623 grid_face_add_new(g, 3); 2624 d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0); 2625 d = grid_get_dot(g, points, px , py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); 2626 d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 2); 2627 } 2628 } 2629 } 2630 2631 freetree234(points); 2632 2633 grid_make_consistent(g); 2634 return g; 2635} 2636 2637static const char *grid_validate_params_greatdodecagonal(int width, int height) 2638{ 2639 int a = DODEC_A; 2640 int b = DODEC_B; 2641 2642 if (width - 1 > (INT_MAX - (2*(2*a + b) + 3*a + b)) / (6*a + 2*b) || 2643 height - 1 > (INT_MAX - 2*(2*a + b)) / (3*a + 3*b) || /* yextent */ 2644 width > INT_MAX / 200 / height) /* max_dots */ 2645 return "Grid size must not be unreasonably large"; 2646 return NULL; 2647} 2648 2649static void grid_size_greatdodecagonal(int width, int height, 2650 int *tilesize, int *xextent, int *yextent) 2651{ 2652 int a = DODEC_A; 2653 int b = DODEC_B; 2654 2655 *tilesize = DODEC_TILESIZE; 2656 *xextent = (6*a + 2*b) * (width-1) + 2*(2*a + b) + 3*a + b; 2657 *yextent = (3*a + 3*b) * (height-1) + 2*(2*a + b); 2658} 2659 2660static grid *grid_new_greatdodecagonal(int width, int height, const char *desc) 2661{ 2662 int x, y; 2663 /* Vector for side of triangle - ratio is close to sqrt(3) */ 2664 int a = DODEC_A; 2665 int b = DODEC_B; 2666 2667 tree234 *points; 2668 2669 grid *g = grid_empty(); 2670 g->tilesize = DODEC_TILESIZE; 2671 2672 points = newtree234(grid_point_cmp_fn); 2673 2674 for (y = 0; y < height; y++) { 2675 for (x = 0; x < width; x++) { 2676 grid_dot *d; 2677 /* centre of dodecagon */ 2678 int px = (6*a + 2*b) * x; 2679 int py = (3*a + 3*b) * y; 2680 if (y % 2) 2681 px += 3*a + b; 2682 2683 /* dodecagon */ 2684 grid_face_add_new(g, 12); 2685 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2686 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); 2687 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); 2688 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); 2689 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); 2690 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); 2691 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); 2692 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); 2693 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); 2694 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); 2695 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); 2696 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); 2697 2698 /* hexagon below dodecagon */ 2699 if (y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { 2700 grid_face_add_new(g, 6); 2701 d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); 2702 d = grid_get_dot(g, points, px + 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 1); 2703 d = grid_get_dot(g, points, px + a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 2); 2704 d = grid_get_dot(g, points, px - a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 3); 2705 d = grid_get_dot(g, points, px - 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 4); 2706 d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 5); 2707 } 2708 2709 /* hexagon above dodecagon */ 2710 if (y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { 2711 grid_face_add_new(g, 6); 2712 d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0); 2713 d = grid_get_dot(g, points, px - 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); 2714 d = grid_get_dot(g, points, px - a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 2); 2715 d = grid_get_dot(g, points, px + a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 3); 2716 d = grid_get_dot(g, points, px + 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 4); 2717 d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 5); 2718 } 2719 2720 /* square on right of dodecagon */ 2721 if (x < width - 1) { 2722 grid_face_add_new(g, 4); 2723 d = grid_get_dot(g, points, px + 2*a + b, py - a); grid_face_set_dot(g, d, 0); 2724 d = grid_get_dot(g, points, px + 4*a + b, py - a); grid_face_set_dot(g, d, 1); 2725 d = grid_get_dot(g, points, px + 4*a + b, py + a); grid_face_set_dot(g, d, 2); 2726 d = grid_get_dot(g, points, px + 2*a + b, py + a); grid_face_set_dot(g, d, 3); 2727 } 2728 2729 /* square on top right of dodecagon */ 2730 if (y && (x < width - 1 || !(y % 2))) { 2731 grid_face_add_new(g, 4); 2732 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2733 d = grid_get_dot(g, points, px + (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); 2734 d = grid_get_dot(g, points, px + (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 2); 2735 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 3); 2736 } 2737 2738 /* square on top left of dodecagon */ 2739 if (y && (x || (y % 2))) { 2740 grid_face_add_new(g, 4); 2741 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 0); 2742 d = grid_get_dot(g, points, px - (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 1); 2743 d = grid_get_dot(g, points, px - (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 2); 2744 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 3); 2745 } 2746 } 2747 } 2748 2749 freetree234(points); 2750 2751 grid_make_consistent(g); 2752 return g; 2753} 2754 2755static const char *grid_validate_params_greatgreatdodecagonal( 2756 int width, int height) 2757{ 2758 int a = DODEC_A; 2759 int b = DODEC_B; 2760 2761 if (width-1 > (INT_MAX - (2*(2*a + b) + 2*a + 2*b)) / (4*a + 4*b) || 2762 height-1 > (INT_MAX - 2*(2*a + b)) / (6*a + 2*b) || /* yextent */ 2763 width > INT_MAX / 300 / height) /* max_dots */ 2764 return "Grid size must not be unreasonably large"; 2765 return NULL; 2766} 2767 2768static void grid_size_greatgreatdodecagonal(int width, int height, 2769 int *tilesize, int *xextent, int *yextent) 2770{ 2771 int a = DODEC_A; 2772 int b = DODEC_B; 2773 2774 *tilesize = DODEC_TILESIZE; 2775 *xextent = (4*a + 4*b) * (width-1) + 2*(2*a + b) + 2*a + 2*b; 2776 *yextent = (6*a + 2*b) * (height-1) + 2*(2*a + b); 2777} 2778 2779static grid *grid_new_greatgreatdodecagonal(int width, int height, const char *desc) 2780{ 2781 int x, y; 2782 /* Vector for side of triangle - ratio is close to sqrt(3) */ 2783 int a = DODEC_A; 2784 int b = DODEC_B; 2785 2786 tree234 *points; 2787 2788 grid *g = grid_empty(); 2789 g->tilesize = DODEC_TILESIZE; 2790 2791 points = newtree234(grid_point_cmp_fn); 2792 2793 for (y = 0; y < height; y++) { 2794 for (x = 0; x < width; x++) { 2795 grid_dot *d; 2796 /* centre of dodecagon */ 2797 int px = (4*a + 4*b) * x; 2798 int py = (6*a + 2*b) * y; 2799 if (y % 2) 2800 px += 2*a + 2*b; 2801 2802 /* dodecagon */ 2803 grid_face_add_new(g, 12); 2804 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2805 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); 2806 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); 2807 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); 2808 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); 2809 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); 2810 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); 2811 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); 2812 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); 2813 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); 2814 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); 2815 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); 2816 2817 /* hexagon on top right of dodecagon */ 2818 if (y && (x < width - 1 || !(y % 2))) { 2819 grid_face_add_new(g, 6); 2820 d = grid_get_dot(g, points, px + (a + 2*b), py - (4*a + b)); grid_face_set_dot(g, d, 0); 2821 d = grid_get_dot(g, points, px + (a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 1); 2822 d = grid_get_dot(g, points, px + (a + b), py - ( a + b)); grid_face_set_dot(g, d, 2); 2823 d = grid_get_dot(g, points, px + (a ), py - (2*a + b)); grid_face_set_dot(g, d, 3); 2824 d = grid_get_dot(g, points, px + (a ), py - (4*a + b)); grid_face_set_dot(g, d, 4); 2825 d = grid_get_dot(g, points, px + (a + b), py - (5*a + b)); grid_face_set_dot(g, d, 5); 2826 } 2827 2828 /* hexagon on right of dodecagon*/ 2829 if (x < width - 1) { 2830 grid_face_add_new(g, 6); 2831 d = grid_get_dot(g, points, px + (2*a + 3*b), py - a); grid_face_set_dot(g, d, 0); 2832 d = grid_get_dot(g, points, px + (2*a + 3*b), py + a); grid_face_set_dot(g, d, 1); 2833 d = grid_get_dot(g, points, px + (2*a + 2*b), py + 2*a); grid_face_set_dot(g, d, 2); 2834 d = grid_get_dot(g, points, px + (2*a + b), py + a); grid_face_set_dot(g, d, 3); 2835 d = grid_get_dot(g, points, px + (2*a + b), py - a); grid_face_set_dot(g, d, 4); 2836 d = grid_get_dot(g, points, px + (2*a + 2*b), py - 2*a); grid_face_set_dot(g, d, 5); 2837 } 2838 2839 /* hexagon on bottom right of dodecagon */ 2840 if ((y < height - 1) && (x < width - 1 || !(y % 2))) { 2841 grid_face_add_new(g, 6); 2842 d = grid_get_dot(g, points, px + (a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); 2843 d = grid_get_dot(g, points, px + (a + 2*b), py + (4*a + b)); grid_face_set_dot(g, d, 1); 2844 d = grid_get_dot(g, points, px + (a + b), py + (5*a + b)); grid_face_set_dot(g, d, 2); 2845 d = grid_get_dot(g, points, px + (a ), py + (4*a + b)); grid_face_set_dot(g, d, 3); 2846 d = grid_get_dot(g, points, px + (a ), py + (2*a + b)); grid_face_set_dot(g, d, 4); 2847 d = grid_get_dot(g, points, px + (a + b), py + ( a + b)); grid_face_set_dot(g, d, 5); 2848 } 2849 2850 /* square on top right of dodecagon */ 2851 if (y && (x < width - 1 )) { 2852 grid_face_add_new(g, 4); 2853 d = grid_get_dot(g, points, px + ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2854 d = grid_get_dot(g, points, px + (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 1); 2855 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); 2856 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 3); 2857 } 2858 2859 /* square on bottom right of dodecagon */ 2860 if ((y < height - 1) && (x < width - 1 )) { 2861 grid_face_add_new(g, 4); 2862 d = grid_get_dot(g, points, px + (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 0); 2863 d = grid_get_dot(g, points, px + ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 1); 2864 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 2); 2865 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); 2866 } 2867 2868 /* square below dodecagon */ 2869 if ((y < height - 1) && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { 2870 grid_face_add_new(g, 4); 2871 d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); 2872 d = grid_get_dot(g, points, px + a, py + (4*a + b)); grid_face_set_dot(g, d, 1); 2873 d = grid_get_dot(g, points, px - a, py + (4*a + b)); grid_face_set_dot(g, d, 2); 2874 d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 3); 2875 } 2876 2877 /* square on bottom left of dodecagon */ 2878 if (x && (y < height - 1)) { 2879 grid_face_add_new(g, 4); 2880 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 0); 2881 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 1); 2882 d = grid_get_dot(g, points, px - ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 2); 2883 d = grid_get_dot(g, points, px - (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 3); 2884 } 2885 2886 /* square on top left of dodecagon */ 2887 if (x && y) { 2888 grid_face_add_new(g, 4); 2889 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 0); 2890 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 1); 2891 d = grid_get_dot(g, points, px - (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 2); 2892 d = grid_get_dot(g, points, px - ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 3); 2893 2894 } 2895 2896 /* square above dodecagon */ 2897 if (y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { 2898 grid_face_add_new(g, 4); 2899 d = grid_get_dot(g, points, px + a, py - (4*a + b)); grid_face_set_dot(g, d, 0); 2900 d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 1); 2901 d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 2); 2902 d = grid_get_dot(g, points, px - a, py - (4*a + b)); grid_face_set_dot(g, d, 3); 2903 } 2904 2905 /* upper triangle (v) */ 2906 if (y && (x < width - 1)) { 2907 grid_face_add_new(g, 3); 2908 d = grid_get_dot(g, points, px + (3*a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2909 d = grid_get_dot(g, points, px + (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 1); 2910 d = grid_get_dot(g, points, px + ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 2); 2911 } 2912 2913 /* lower triangle (^) */ 2914 if ((y < height - 1) && (x < width - 1)) { 2915 grid_face_add_new(g, 3); 2916 d = grid_get_dot(g, points, px + (3*a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); 2917 d = grid_get_dot(g, points, px + ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 1); 2918 d = grid_get_dot(g, points, px + (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 2); 2919 } 2920 } 2921 } 2922 2923 freetree234(points); 2924 2925 grid_make_consistent(g); 2926 return g; 2927} 2928 2929static const char *grid_validate_params_compassdodecagonal( 2930 int width, int height) 2931{ 2932 int a = DODEC_A; 2933 int b = DODEC_B; 2934 2935 if (width > INT_MAX / (4*a + 2*b) || /* xextent */ 2936 height > INT_MAX / (4*a + 2*b) || /* yextent */ 2937 width > INT_MAX / 18 / height) /* max_dots */ 2938 return "Grid must not be unreasonably large"; 2939 return NULL; 2940} 2941 2942static void grid_size_compassdodecagonal(int width, int height, 2943 int *tilesize, int *xextent, int *yextent) 2944{ 2945 int a = DODEC_A; 2946 int b = DODEC_B; 2947 2948 *tilesize = DODEC_TILESIZE; 2949 *xextent = (4*a + 2*b) * width; 2950 *yextent = (4*a + 2*b) * height; 2951} 2952 2953static grid *grid_new_compassdodecagonal(int width, int height, const char *desc) 2954{ 2955 int x, y; 2956 /* Vector for side of triangle - ratio is close to sqrt(3) */ 2957 int a = DODEC_A; 2958 int b = DODEC_B; 2959 2960 tree234 *points; 2961 2962 grid *g = grid_empty(); 2963 g->tilesize = DODEC_TILESIZE; 2964 2965 points = newtree234(grid_point_cmp_fn); 2966 2967 for (y = 0; y < height; y++) { 2968 for (x = 0; x < width; x++) { 2969 grid_dot *d; 2970 /* centre of dodecagon */ 2971 int px = (4*a + 2*b) * x; 2972 int py = (4*a + 2*b) * y; 2973 2974 /* dodecagon */ 2975 grid_face_add_new(g, 12); 2976 d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); 2977 d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); 2978 d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); 2979 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); 2980 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); 2981 d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); 2982 d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); 2983 d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); 2984 d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); 2985 d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); 2986 d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); 2987 d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); 2988 2989 if (x < width - 1 && y < height - 1) { 2990 /* north triangle */ 2991 grid_face_add_new(g, 3); 2992 d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 0); 2993 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 1); 2994 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 2); 2995 2996 /* east triangle */ 2997 grid_face_add_new(g, 3); 2998 d = grid_get_dot(g, points, px + (3*a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); 2999 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1); 3000 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 2); 3001 3002 /* south triangle */ 3003 grid_face_add_new(g, 3); 3004 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 0); 3005 d = grid_get_dot(g, points, px + (2*a + b), py + (3*a + 2*b)); grid_face_set_dot(g, d, 1); 3006 d = grid_get_dot(g, points, px + ( a + b), py + (3*a + b)); grid_face_set_dot(g, d, 2); 3007 3008 /* west triangle */ 3009 grid_face_add_new(g, 3); 3010 d = grid_get_dot(g, points, px + (a + b), py + ( a + b)); grid_face_set_dot(g, d, 0); 3011 d = grid_get_dot(g, points, px + (a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1); 3012 d = grid_get_dot(g, points, px + (a ), py + (2*a + b)); grid_face_set_dot(g, d, 2); 3013 3014 /* square in center */ 3015 grid_face_add_new(g, 4); 3016 d = grid_get_dot(g, points, px + (3*a + b), py + ( a + b)); grid_face_set_dot(g, d, 0); 3017 d = grid_get_dot(g, points, px + (3*a + b), py + (3*a + b)); grid_face_set_dot(g, d, 1); 3018 d = grid_get_dot(g, points, px + ( a + b), py + (3*a + b)); grid_face_set_dot(g, d, 2); 3019 d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 3); 3020 } 3021 } 3022 } 3023 3024 freetree234(points); 3025 3026 grid_make_consistent(g); 3027 return g; 3028} 3029 3030/* 3031 * Penrose tilings. For historical reasons, we support two totally 3032 * different generation algorithms: the legacy one is only supported 3033 * by grid_new_penrose, for backwards compatibility with game 3034 * descriptions generated before we switched. New grid generation uses 3035 * only the new system. 3036 */ 3037 3038#define PENROSE_TILESIZE 100 3039 3040static const char *grid_validate_params_penrose(int width, int height) 3041{ 3042 int l = PENROSE_TILESIZE; 3043 3044 if (width > INT_MAX / l || /* xextent */ 3045 height > INT_MAX / l || /* yextent */ 3046 width > INT_MAX / (3 * 3 * 4 * height)) /* max_dots */ 3047 return "Grid must not be unreasonably large"; 3048 return NULL; 3049} 3050 3051static void grid_size_penrose(int width, int height, 3052 int *tilesize, int *xextent, int *yextent) 3053{ 3054 int l = PENROSE_TILESIZE; 3055 3056 *tilesize = l; 3057 *xextent = l * width; 3058 *yextent = l * height; 3059} 3060 3061/* 3062 * Legacy generation by selecting a patch of tiling from the expansion 3063 * of a big triangle. 3064 */ 3065 3066typedef struct penrose_legacy_set_faces_ctx { 3067 int xmin, xmax, ymin, ymax; 3068 3069 grid *g; 3070 tree234 *points; 3071} penrose_legacy_set_faces_ctx; 3072 3073static double round_int_nearest_away(double r) 3074{ 3075 return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); 3076} 3077 3078static int penrose_legacy_set_faces(penrose_legacy_state *state, vector *vs, 3079 int n, int depth) 3080{ 3081 penrose_legacy_set_faces_ctx *sf_ctx = 3082 (penrose_legacy_set_faces_ctx *)state->ctx; 3083 int i; 3084 int xs[4], ys[4]; 3085 3086 if (depth < state->max_depth) return 0; 3087#ifdef DEBUG_PENROSE 3088 if (n != 4) return 0; /* triangles are sent as debugging. */ 3089#endif 3090 3091 for (i = 0; i < n; i++) { 3092 double tx = penrose_legacy_vx(vs, i), ty = penrose_legacy_vy(vs, i); 3093 3094 xs[i] = (int)round_int_nearest_away(tx); 3095 ys[i] = (int)round_int_nearest_away(ty); 3096 3097 if (xs[i] < sf_ctx->xmin || xs[i] > sf_ctx->xmax) return 0; 3098 if (ys[i] < sf_ctx->ymin || ys[i] > sf_ctx->ymax) return 0; 3099 } 3100 3101 grid_face_add_new(sf_ctx->g, n); 3102 debug(("penrose: new face l=%f gen=%d...", 3103 penrose_legacy_side_length(state->start_size, depth), depth)); 3104 for (i = 0; i < n; i++) { 3105 grid_dot *d = grid_get_dot(sf_ctx->g, sf_ctx->points, 3106 xs[i], ys[i]); 3107 grid_face_set_dot(sf_ctx->g, d, i); 3108 debug((" ... dot 0x%x (%d,%d) (was %2.2f,%2.2f)", 3109 d, d->x, d->y, penrose_legacy_vx(vs, i), 3110 penrose_legacy_vy(vs, i))); 3111 } 3112 3113 return 0; 3114} 3115 3116static grid *grid_new_penrose_legacy(int width, int height, int which, 3117 const char *desc); 3118 3119static const char *grid_validate_desc_penrose_legacy( 3120 grid_type type, int width, int height, const char *desc) 3121{ 3122 int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff, inner_radius; 3123 double outer_radius; 3124 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3); 3125 grid *g; 3126 3127 if (!desc) 3128 return "Missing grid description string."; 3129 3130 penrose_legacy_calculate_size(which, tilesize, width, height, 3131 &outer_radius, &startsz, &depth); 3132 inner_radius = (int)(outer_radius - sqrt(width*width + height*height)); 3133 3134 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3) 3135 return "Invalid format grid description string."; 3136 3137 if (sqrt(xoff*xoff + yoff*yoff) > inner_radius) 3138 return "Patch offset out of bounds."; 3139 if ((aoff % 36) != 0 || aoff < 0 || aoff >= 360) 3140 return "Angle offset out of bounds."; 3141 3142 /* 3143 * Test-generate to ensure these parameters don't end us up with 3144 * no grid at all. 3145 */ 3146 g = grid_new_penrose_legacy(width, height, which, desc); 3147 if (!g) 3148 return "Patch coordinates do not identify a usable grid fragment"; 3149 grid_free(g); 3150 3151 return NULL; 3152} 3153 3154static grid *grid_new_penrose_legacy(int width, int height, int which, 3155 const char *desc) 3156{ 3157 int tilesize = PENROSE_TILESIZE; 3158 int xsz, ysz, xoff, yoff, aoff; 3159 double rradius; 3160 3161 tree234 *points; 3162 grid *g; 3163 3164 penrose_legacy_state ps; 3165 penrose_legacy_set_faces_ctx sf_ctx; 3166 3167 penrose_legacy_calculate_size(which, tilesize, width, height, 3168 &rradius, &ps.start_size, &ps.max_depth); 3169 3170 debug(("penrose: w%d h%d, tile size %d, start size %d, depth %d", 3171 width, height, tilesize, ps.start_size, ps.max_depth)); 3172 3173 ps.new_tile = penrose_legacy_set_faces; 3174 ps.ctx = &sf_ctx; 3175 3176 g = grid_empty(); 3177 g->tilesize = tilesize; 3178 3179 points = newtree234(grid_point_cmp_fn); 3180 3181 memset(&sf_ctx, 0, sizeof(sf_ctx)); 3182 sf_ctx.g = g; 3183 sf_ctx.points = points; 3184 3185 if (desc != NULL) { 3186 if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3) 3187 assert(!"Invalid grid description."); 3188 } else { 3189 xoff = yoff = aoff = 0; 3190 } 3191 3192 xsz = width * tilesize; 3193 ysz = height * tilesize; 3194 3195 sf_ctx.xmin = xoff - xsz/2; 3196 sf_ctx.xmax = xoff + xsz/2; 3197 sf_ctx.ymin = yoff - ysz/2; 3198 sf_ctx.ymax = yoff + ysz/2; 3199 3200 debug(("penrose: centre (%f, %f) xsz %f ysz %f", 3201 0.0, 0.0, xsz, ysz)); 3202 debug(("penrose: x range (%f --> %f), y range (%f --> %f)", 3203 sf_ctx.xmin, sf_ctx.xmax, sf_ctx.ymin, sf_ctx.ymax)); 3204 3205 penrose_legacy(&ps, which, aoff); 3206 3207 freetree234(points); 3208 3209 debug(("penrose: %d faces total (equivalent to %d wide by %d high)", 3210 g->num_faces, g->num_faces/height, g->num_faces/width)); 3211 3212 /* 3213 * Return NULL if we ended up with an empty grid, either because 3214 * the initial generation was over too small a rectangle to 3215 * encompass any face or because grid_trim_vigorously ended up 3216 * removing absolutely everything. 3217 */ 3218 if (g->num_faces == 0 || g->num_dots == 0) { 3219 grid_free(g); 3220 return NULL; 3221 } 3222 grid_trim_vigorously(g); 3223 if (g->num_faces == 0 || g->num_dots == 0) { 3224 grid_free(g); 3225 return NULL; 3226 } 3227 3228 grid_make_consistent(g); 3229 3230 /* 3231 * Centre the grid in its originally promised rectangle. 3232 */ 3233 g->lowest_x -= ((sf_ctx.xmax - sf_ctx.xmin) - 3234 (g->highest_x - g->lowest_x)) / 2; 3235 g->highest_x = g->lowest_x + (sf_ctx.xmax - sf_ctx.xmin); 3236 g->lowest_y -= ((sf_ctx.ymax - sf_ctx.ymin) - 3237 (g->highest_y - g->lowest_y)) / 2; 3238 g->highest_y = g->lowest_y + (sf_ctx.ymax - sf_ctx.ymin); 3239 3240 return g; 3241} 3242 3243/* 3244 * Combinatorial-coordinate generation. 3245 * 3246 * We receive coordinates from the generator in the form of x,y pairs 3247 * each of which is an integer combination of 1 and sqrt(5), but those 3248 * pairs have different scale units in the x and y directions. The 3249 * scale units are 1/4 for x and sin(pi/5)/2 for y, which makes their 3250 * ratio equal to 2 sin(pi/5) ~= 1.1756. We fudge that irrational 3251 * aspect ratio into a rational approximation, by simply taking a pair 3252 * of integer scale factors for the x and y dimensions; this distorts 3253 * the output tiling slightly, but the distortion is consistent, and 3254 * doesn't accumulate over a large patch of tiling, so it won't make 3255 * anything end up totally out of place. 3256 * 3257 * (However, we compute the subsequent combination of 1 and sqrt(5) 3258 * exactly, because using an approximation to sqrt(5) _could_ mean 3259 * that in a sufficiently large patch of tiling two such combinations 3260 * ended up misordered.) 3261 * 3262 * Adding to the confusion, we also flip round the x and y 3263 * coordinates, because it's slightly nicer to have vertical edges in 3264 * the tiling rather than horizontal ones. (Both for aesthetics, and 3265 * also because if two P3 thin rhombs are separated by a horizontal 3266 * line and both contain numeric clues then the clue numbers look a 3267 * bit crowded, due to digits being taller than they are wide.) 3268 * 3269 * Finally, we have different base unit sizes for the two tiling 3270 * types, because sensible sizes for the two are actually different. 3271 * Each of P2 and P3 can be subdivided into the other, via dividing 3272 * the larger triangle type in two, so that L large and S small become 3273 * L+S large and L small. In the limit, this means that you expect the 3274 * number of triangles (hence tiles) to grow by a factor of phi in 3275 * each of those subdivisions (and hence by a factor of phi^2 in a 3276 * full subdivision of P2 to a finer P2). So a sensible size ratio 3277 * between the two tilings is one that makes them fit about the same 3278 * number of tiles into the same area - and since tile area is 3279 * proportional to _square_ of length, it follows that the P2 and P3 3280 * length unit should differ by a factor of sqrt(phi). 3281 */ 3282#define PENROSE_XUNIT_P2 37 3283#define PENROSE_YUNIT_P2 44 3284#define PENROSE_XUNIT_P3 30 3285#define PENROSE_YUNIT_P3 35 3286 3287struct size { int w, h; }; 3288static struct size api_size_penrose(int width, int height, int which) 3289{ 3290 int xunit = (which == PENROSE_P2 ? PENROSE_XUNIT_P2 : PENROSE_XUNIT_P3); 3291 int yunit = (which == PENROSE_P2 ? PENROSE_YUNIT_P2 : PENROSE_YUNIT_P3); 3292 struct size size = { 3293 width * PENROSE_TILESIZE / yunit, 3294 height * PENROSE_TILESIZE / xunit, 3295 }; 3296 return size; 3297} 3298 3299static grid *grid_new_penrose(int width, int height, int which, 3300 const char *desc); /* forward reference */ 3301 3302static char *grid_new_desc_penrose(grid_type type, int width, int height, 3303 random_state *rs) 3304{ 3305 char *buf; 3306 struct PenrosePatchParams params; 3307 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3); 3308 struct size size = api_size_penrose(width, height, which); 3309 3310 penrose_tiling_randomise(&params, which, size.h, size.w, rs); 3311 3312 buf = snewn(params.ncoords + 3, char); 3313 buf[0] = '0' + params.orientation; 3314 buf[1] = '0' + params.start_vertex; 3315 memcpy(buf + 2, params.coords, params.ncoords); 3316 buf[2 + params.ncoords] = '\0'; 3317 3318 sfree(params.coords); 3319 return buf; 3320} 3321 3322/* Shared code between validating and reading grid descs. 3323 * Always allocates params->coords, whether or not it returns an error. */ 3324static const char *grid_desc_to_penrose_params( 3325 const char *desc, int which, struct PenrosePatchParams *params) 3326{ 3327 int i; 3328 3329 if (!*desc) 3330 return "empty grid description"; 3331 3332 params->ncoords = strlen(desc) - 2; 3333 params->coords = snewn(params->ncoords, char); 3334 3335 { 3336 char c = desc[0]; 3337 if (isdigit((unsigned char)c)) 3338 params->orientation = c - '0'; 3339 else 3340 return "expected digit at start of grid description"; 3341 3342 c = desc[1]; 3343 if (c >= '0' && c < '3') 3344 params->start_vertex = c - '0'; 3345 else 3346 return "expected digit as second char of grid description"; 3347 } 3348 3349 for (i = 0; i < params->ncoords; i++) { 3350 char c = desc[i+2]; 3351 if (!penrose_valid_letter(c, which)) 3352 return "expected tile letter in grid description"; 3353 params->coords[i] = c; 3354 } 3355 3356 return NULL; 3357} 3358 3359static const char *grid_validate_desc_penrose(grid_type type, 3360 int width, int height, 3361 const char *desc) 3362{ 3363 struct PenrosePatchParams params; 3364 const char *error = NULL; 3365 int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3); 3366 3367 if (!desc) 3368 return "Missing grid description string."; 3369 3370 if (*desc == 'G') 3371 return grid_validate_desc_penrose_legacy(type, width, height, desc); 3372 3373 error = grid_desc_to_penrose_params(desc, which, &params); 3374 if (!error) 3375 error = penrose_tiling_params_invalid(&params, which); 3376 3377 sfree(params.coords); 3378 return error; 3379} 3380 3381struct penrosecontext { 3382 grid *g; 3383 tree234 *points; 3384 int xunit, yunit; 3385}; 3386 3387static void grid_penrose_callback(void *vctx, const int *coords) 3388{ 3389 struct penrosecontext *ctx = (struct penrosecontext *)vctx; 3390 size_t i; 3391 3392 grid_face_add_new(ctx->g, 4); 3393 for (i = 0; i < 4; i++) { 3394 grid_dot *d = grid_get_dot( 3395 ctx->g, ctx->points, 3396 coords[4*i+2] * ctx->yunit + n_times_root_k( 3397 coords[4*i+3] * ctx->yunit, 5), 3398 coords[4*i+0] * ctx->xunit + n_times_root_k( 3399 coords[4*i+1] * ctx->xunit, 5)); 3400 grid_face_set_dot(ctx->g, d, i); 3401 } 3402} 3403 3404static grid *grid_new_penrose(int width, int height, int which, 3405 const char *desc) 3406{ 3407 struct PenrosePatchParams params; 3408 const char *error = NULL; 3409 struct penrosecontext ctx[1]; 3410 struct size size; 3411 3412 if (*desc == 'G') 3413 return grid_new_penrose_legacy(width, height, which, desc); 3414 3415 error = grid_desc_to_penrose_params(desc, which, &params); 3416 assert(error == NULL && "grid_validate_desc_penrose should have failed"); 3417 3418 ctx->g = grid_empty(); 3419 ctx->g->tilesize = PENROSE_TILESIZE; 3420 3421 ctx->points = newtree234(grid_point_cmp_fn); 3422 3423 ctx->xunit = (which == PENROSE_P2 ? PENROSE_XUNIT_P2 : PENROSE_XUNIT_P3); 3424 ctx->yunit = (which == PENROSE_P2 ? PENROSE_YUNIT_P2 : PENROSE_YUNIT_P3); 3425 3426 size = api_size_penrose(width, height, which); 3427 penrose_tiling_generate(&params, size.h, size.w, 3428 grid_penrose_callback, ctx); 3429 3430 freetree234(ctx->points); 3431 sfree(params.coords); 3432 3433 grid_trim_vigorously(ctx->g); 3434 grid_make_consistent(ctx->g); 3435 3436 /* 3437 * Centre the grid in its originally promised rectangle. 3438 */ 3439 { 3440 int w = width * PENROSE_TILESIZE, h = height * PENROSE_TILESIZE; 3441 ctx->g->lowest_x -= (w - (ctx->g->highest_x - ctx->g->lowest_x))/2; 3442 ctx->g->lowest_y -= (h - (ctx->g->highest_y - ctx->g->lowest_y))/2; 3443 ctx->g->highest_x = ctx->g->lowest_x + w; 3444 ctx->g->highest_y = ctx->g->lowest_y + h; 3445 } 3446 3447 return ctx->g; 3448} 3449 3450static const char *grid_validate_params_penrose_p2_kite(int width, int height) 3451{ 3452 return grid_validate_params_penrose(width, height); 3453} 3454 3455static const char *grid_validate_params_penrose_p3_thick(int width, int height) 3456{ 3457 return grid_validate_params_penrose(width, height); 3458} 3459 3460static void grid_size_penrose_p2_kite(int width, int height, 3461 int *tilesize, int *xextent, int *yextent) 3462{ 3463 grid_size_penrose(width, height, tilesize, xextent, yextent); 3464} 3465 3466static void grid_size_penrose_p3_thick(int width, int height, 3467 int *tilesize, int *xextent, int *yextent) 3468{ 3469 grid_size_penrose(width, height, tilesize, xextent, yextent); 3470} 3471 3472static grid *grid_new_penrose_p2_kite(int width, int height, const char *desc) 3473{ 3474 return grid_new_penrose(width, height, PENROSE_P2, desc); 3475} 3476 3477static grid *grid_new_penrose_p3_thick(int width, int height, const char *desc) 3478{ 3479 return grid_new_penrose(width, height, PENROSE_P3, desc); 3480} 3481 3482#define HATS_TILESIZE 32 3483#define HATS_XSQUARELEN 4 3484#define HATS_YSQUARELEN 6 3485#define HATS_XUNIT 14 3486#define HATS_YUNIT 8 3487 3488static const char *grid_validate_params_hats( 3489 int width, int height) 3490{ 3491 int l = HATS_TILESIZE; 3492 3493 if (width > INT_MAX / l || /* xextent */ 3494 height > INT_MAX / l || /* yextent */ 3495 width > INT_MAX / (6 * height)) /* max_dots */ 3496 return "Grid must not be unreasonably large"; 3497 return NULL; 3498} 3499 3500static void grid_size_hats(int width, int height, 3501 int *tilesize, int *xextent, int *yextent) 3502{ 3503 *tilesize = HATS_TILESIZE; 3504 *xextent = width * HATS_XUNIT * HATS_XSQUARELEN; 3505 *yextent = height * HATS_YUNIT * HATS_YSQUARELEN; 3506} 3507 3508static char *grid_new_desc_hats( 3509 grid_type type, int width, int height, random_state *rs) 3510{ 3511 char *buf, *p; 3512 size_t bufmax, i; 3513 struct HatPatchParams hp; 3514 3515 hat_tiling_randomise(&hp, width, height, rs); 3516 3517 bufmax = 3 * hp.ncoords + 2; 3518 buf = snewn(bufmax, char); 3519 p = buf; 3520 for (i = 0; i < hp.ncoords; i++) { 3521 assert(hp.coords[i] < 100); /* at most 2 digits */ 3522 assert(p - buf <= bufmax-4); /* room for 2 digits, comma and NUL */ 3523 p += sprintf(p, "%d,", (int)hp.coords[i]); 3524 } 3525 assert(p - buf <= bufmax-2); /* room for final letter and NUL */ 3526 p[0] = hp.final_metatile; 3527 p[1] = '\0'; 3528 3529 sfree(hp.coords); 3530 return buf; 3531} 3532 3533/* Shared code between validating and reading grid descs. 3534 * Always allocates hp->coords, whether or not it returns an error. */ 3535static const char *grid_desc_to_hat_params( 3536 const char *desc, struct HatPatchParams *hp) 3537{ 3538 size_t maxcoords; 3539 const char *p = desc; 3540 3541 maxcoords = (strlen(desc) + 1) / 2; 3542 hp->coords = snewn(maxcoords, unsigned char); 3543 hp->ncoords = 0; 3544 3545 while (isdigit((unsigned char)*p)) { 3546 const char *p_orig = p; 3547 int n = atoi(p); 3548 while (*p && isdigit((unsigned char)*p)) p++; 3549 if (*p != ',') 3550 return "expected ',' in grid description"; 3551 if (p - p_orig > 2 || n > 0xFF) 3552 return "too-large coordinate in grid description"; 3553 p++; /* eat the comma */ 3554 3555 /* This assert should be guaranteed by the way we calculated 3556 * maxcoords, so a failure of this check is a bug in this 3557 * function, not an indication of an invalid input string */ 3558 assert(hp->ncoords < maxcoords); 3559 hp->coords[hp->ncoords++] = n; 3560 } 3561 3562 if (*p == 'H' || *p == 'T' || *p == 'P' || *p == 'F') 3563 hp->final_metatile = *p; 3564 else 3565 return "invalid character in grid description"; 3566 3567 return NULL; 3568} 3569 3570static const char *grid_validate_desc_hats( 3571 grid_type type, int width, int height, const char *desc) 3572{ 3573 struct HatPatchParams hp; 3574 const char *error = NULL; 3575 3576 if (!desc) 3577 return "Missing grid description string."; 3578 3579 error = grid_desc_to_hat_params(desc, &hp); 3580 if (!error) 3581 error = hat_tiling_params_invalid(&hp); 3582 3583 sfree(hp.coords); 3584 return error; 3585} 3586 3587struct hatcontext { 3588 grid *g; 3589 tree234 *points; 3590}; 3591 3592static void grid_hats_callback(void *vctx, size_t nvertices, int *coords) 3593{ 3594 struct hatcontext *ctx = (struct hatcontext *)vctx; 3595 size_t i; 3596 3597 grid_face_add_new(ctx->g, nvertices); 3598 for (i = 0; i < nvertices; i++) { 3599 grid_dot *d = grid_get_dot( 3600 ctx->g, ctx->points, 3601 coords[2*i] * HATS_XUNIT, 3602 coords[2*i+1] * HATS_YUNIT); 3603 grid_face_set_dot(ctx->g, d, i); 3604 } 3605} 3606 3607static grid *grid_new_hats(int width, int height, const char *desc) 3608{ 3609 struct HatPatchParams hp; 3610 const char *error = NULL; 3611 3612 error = grid_desc_to_hat_params(desc, &hp); 3613 assert(error == NULL && "grid_validate_desc_hats should have failed"); 3614 3615 struct hatcontext ctx[1]; 3616 3617 ctx->g = grid_empty(); 3618 ctx->g->tilesize = HATS_TILESIZE; 3619 3620 ctx->points = newtree234(grid_point_cmp_fn); 3621 3622 hat_tiling_generate(&hp, width, height, grid_hats_callback, ctx); 3623 3624 freetree234(ctx->points); 3625 sfree(hp.coords); 3626 3627 grid_trim_vigorously(ctx->g); 3628 grid_make_consistent(ctx->g); 3629 return ctx->g; 3630} 3631 3632#define SPECTRE_TILESIZE 32 3633#define SPECTRE_SQUARELEN 7 3634#define SPECTRE_UNIT 8 3635 3636static const char *grid_validate_params_spectres( 3637 int width, int height) 3638{ 3639 int l = SPECTRE_UNIT * SPECTRE_SQUARELEN; 3640 3641 if (width > INT_MAX / l || /* xextent */ 3642 height > INT_MAX / l || /* yextent */ 3643 width > (INT_MAX / SPECTRE_SQUARELEN / 3644 SPECTRE_SQUARELEN / height)) /* max_faces */ 3645 return "Grid must not be unreasonably large"; 3646 return NULL; 3647} 3648 3649static void grid_size_spectres(int width, int height, 3650 int *tilesize, int *xextent, int *yextent) 3651{ 3652 *tilesize = SPECTRE_TILESIZE; 3653 *xextent = width * SPECTRE_UNIT * SPECTRE_SQUARELEN; 3654 *yextent = height * SPECTRE_UNIT * SPECTRE_SQUARELEN; 3655} 3656 3657static char *grid_new_desc_spectres( 3658 grid_type type, int width, int height, random_state *rs) 3659{ 3660 char *buf; 3661 size_t i; 3662 struct SpectrePatchParams sp; 3663 3664 spectre_tiling_randomise(&sp, width * SPECTRE_SQUARELEN, 3665 height * SPECTRE_SQUARELEN, rs); 3666 3667 buf = snewn(sp.ncoords + 3, char); 3668 buf[0] = (sp.orientation < 10 ? '0' + sp.orientation : 3669 'A' + sp.orientation - 10); 3670 for (i = 0; i < sp.ncoords; i++) { 3671 assert(sp.coords[i] < 10); /* all indices are 1 digit */ 3672 buf[i+1] = '0' + sp.coords[i]; 3673 } 3674 buf[sp.ncoords+1] = sp.final_hex; 3675 buf[sp.ncoords+2] = '\0'; 3676 3677 sfree(sp.coords); 3678 return buf; 3679} 3680 3681/* Shared code between validating and reading grid descs. 3682 * Always allocates sp->coords, whether or not it returns an error. */ 3683static const char *grid_desc_to_spectre_params( 3684 const char *desc, struct SpectrePatchParams *sp) 3685{ 3686 size_t i; 3687 3688 if (!*desc) 3689 return "empty grid description"; 3690 3691 sp->ncoords = strlen(desc) - 2; 3692 sp->coords = snewn(sp->ncoords, unsigned char); 3693 3694 { 3695 char c = desc[0]; 3696 if (isdigit((unsigned char)c)) 3697 sp->orientation = c - '0'; 3698 else if (c == 'A' || c == 'B') 3699 sp->orientation = 10 + c - 'A'; 3700 else 3701 return "expected digit or A,B at start of grid description"; 3702 } 3703 3704 for (i = 0; i < sp->ncoords; i++) { 3705 char c = desc[i+1]; 3706 if (!isdigit((unsigned char)c)) 3707 return "expected digit in grid description"; 3708 sp->coords[i] = c - '0'; 3709 } 3710 3711 sp->final_hex = desc[sp->ncoords+1]; 3712 3713 return NULL; 3714} 3715 3716static const char *grid_validate_desc_spectres( 3717 grid_type type, int width, int height, const char *desc) 3718{ 3719 struct SpectrePatchParams sp; 3720 const char *error = NULL; 3721 3722 if (!desc) 3723 return "Missing grid description string."; 3724 3725 error = grid_desc_to_spectre_params(desc, &sp); 3726 if (!error) 3727 error = spectre_tiling_params_invalid(&sp); 3728 3729 sfree(sp.coords); 3730 return error; 3731} 3732 3733struct spectrecontext { 3734 grid *g; 3735 tree234 *points; 3736}; 3737 3738static void grid_spectres_callback(void *vctx, const int *coords) 3739{ 3740 struct spectrecontext *ctx = (struct spectrecontext *)vctx; 3741 size_t i; 3742 3743 grid_face_add_new(ctx->g, SPECTRE_NVERTICES); 3744 for (i = 0; i < SPECTRE_NVERTICES; i++) { 3745 grid_dot *d = grid_get_dot( 3746 ctx->g, ctx->points, 3747 (coords[4*i+0] * SPECTRE_UNIT + 3748 n_times_root_k(coords[4*i+1] * SPECTRE_UNIT, 3)), 3749 (coords[4*i+2] * SPECTRE_UNIT + 3750 n_times_root_k(coords[4*i+3] * SPECTRE_UNIT, 3))); 3751 grid_face_set_dot(ctx->g, d, i); 3752 } 3753} 3754 3755static grid *grid_new_spectres(int width, int height, const char *desc) 3756{ 3757 struct SpectrePatchParams sp; 3758 const char *error = NULL; 3759 int width2 = width * SPECTRE_SQUARELEN; 3760 int height2 = height * SPECTRE_SQUARELEN; 3761 3762 error = grid_desc_to_spectre_params(desc, &sp); 3763 assert(error == NULL && "grid_validate_desc_spectres should have failed"); 3764 3765 struct spectrecontext ctx[1]; 3766 3767 ctx->g = grid_empty(); 3768 ctx->g->tilesize = SPECTRE_TILESIZE; 3769 3770 ctx->points = newtree234(grid_point_cmp_fn); 3771 3772 spectre_tiling_generate(&sp, width2, height2, grid_spectres_callback, ctx); 3773 3774 freetree234(ctx->points); 3775 sfree(sp.coords); 3776 3777 grid_trim_vigorously(ctx->g); 3778 grid_make_consistent(ctx->g); 3779 3780 /* 3781 * As with the Penrose tiling, we're likely to have different 3782 * sized margins due to the lack of a neat grid that this tiling 3783 * fits on. So now we know what tiles we're left with, recentre 3784 * them. 3785 */ 3786 { 3787 int w = width2 * SPECTRE_UNIT, h = height2 * SPECTRE_UNIT; 3788 ctx->g->lowest_x -= (w - (ctx->g->highest_x - ctx->g->lowest_x))/2; 3789 ctx->g->lowest_y -= (h - (ctx->g->highest_y - ctx->g->lowest_y))/2; 3790 ctx->g->highest_x = ctx->g->lowest_x + w; 3791 ctx->g->highest_y = ctx->g->lowest_y + h; 3792 } 3793 3794 return ctx->g; 3795} 3796 3797/* ----------- End of grid generators ------------- */ 3798 3799#define FNVAL(upper,lower) &grid_validate_params_ ## lower, 3800#define FNNEW(upper,lower) &grid_new_ ## lower, 3801#define FNSZ(upper,lower) &grid_size_ ## lower, 3802 3803static const char *(*(grid_validate_paramses[]))(int, int) = 3804 { GRIDGEN_LIST(FNVAL) }; 3805static grid *(*(grid_news[]))(int, int, const char*) = { GRIDGEN_LIST(FNNEW) }; 3806static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) }; 3807 3808/* Work out if a grid can be made, and complain if not. */ 3809 3810const char *grid_validate_params(grid_type type, int width, int height) 3811{ 3812 if (width <= 0 || height <= 0) 3813 return "Width and height must both be positive"; 3814 return grid_validate_paramses[type](width, height); 3815} 3816 3817char *grid_new_desc(grid_type type, int width, int height, random_state *rs) 3818{ 3819 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { 3820 return grid_new_desc_penrose(type, width, height, rs); 3821 } else if (type == GRID_HATS) { 3822 return grid_new_desc_hats(type, width, height, rs); 3823 } else if (type == GRID_SPECTRES) { 3824 return grid_new_desc_spectres(type, width, height, rs); 3825 } else if (type == GRID_TRIANGULAR) { 3826 return dupstr("0"); /* up-to-date version of triangular grid */ 3827 } else { 3828 return NULL; 3829 } 3830} 3831 3832const char *grid_validate_desc(grid_type type, int width, int height, 3833 const char *desc) 3834{ 3835 if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { 3836 return grid_validate_desc_penrose(type, width, height, desc); 3837 } else if (type == GRID_HATS) { 3838 return grid_validate_desc_hats(type, width, height, desc); 3839 } else if (type == GRID_SPECTRES) { 3840 return grid_validate_desc_spectres(type, width, height, desc); 3841 } else if (type == GRID_TRIANGULAR) { 3842 return grid_validate_desc_triangular(type, width, height, desc); 3843 } else { 3844 if (desc != NULL) 3845 return "Grid description strings not used with this grid type"; 3846 return NULL; 3847 } 3848} 3849 3850grid *grid_new(grid_type type, int width, int height, const char *desc) 3851{ 3852 const char *err = grid_validate_desc(type, width, height, desc); 3853 if (err) assert(!"Invalid grid description."); 3854 3855 return grid_news[type](width, height, desc); 3856} 3857 3858void grid_compute_size(grid_type type, int width, int height, 3859 int *tilesize, int *xextent, int *yextent) 3860{ 3861 grid_sizes[type](width, height, tilesize, xextent, yextent); 3862} 3863 3864/* ----------- End of grid helpers ------------- */ 3865 3866/* vim: set shiftwidth=4 tabstop=8: */