Patch from Chris Moore to improve the generality of
[sgt/puzzles] / grid.c
1 /*
2 * (c) Lambros Lambrou 2008
3 *
4 * Code for working with general grids, which can be any planar graph
5 * with faces, edges and vertices (dots). Includes generators for a few
6 * types of grid, including square, hexagonal, triangular and others.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <assert.h>
13 #include <ctype.h>
14 #include <math.h>
15
16 #include "puzzles.h"
17 #include "tree234.h"
18 #include "grid.h"
19
20 /* Debugging options */
21
22 /*
23 #define DEBUG_GRID
24 */
25
26 /* ----------------------------------------------------------------------
27 * Deallocate or dereference a grid
28 */
29 void grid_free(grid *g)
30 {
31 assert(g->refcount);
32
33 g->refcount--;
34 if (g->refcount == 0) {
35 int i;
36 for (i = 0; i < g->num_faces; i++) {
37 sfree(g->faces[i].dots);
38 sfree(g->faces[i].edges);
39 }
40 for (i = 0; i < g->num_dots; i++) {
41 sfree(g->dots[i].faces);
42 sfree(g->dots[i].edges);
43 }
44 sfree(g->faces);
45 sfree(g->edges);
46 sfree(g->dots);
47 sfree(g);
48 }
49 }
50
51 /* Used by the other grid generators. Create a brand new grid with nothing
52 * initialised (all lists are NULL) */
53 static grid *grid_new(void)
54 {
55 grid *g = snew(grid);
56 g->faces = NULL;
57 g->edges = NULL;
58 g->dots = NULL;
59 g->num_faces = g->num_edges = g->num_dots = 0;
60 g->middle_face = NULL;
61 g->refcount = 1;
62 g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0;
63 return g;
64 }
65
66 /* Helper function to calculate perpendicular distance from
67 * a point P to a line AB. A and B mustn't be equal here.
68 *
69 * Well-known formula for area A of a triangle:
70 * / 1 1 1 \
71 * 2A = determinant of matrix | px ax bx |
72 * \ py ay by /
73 *
74 * Also well-known: 2A = base * height
75 * = perpendicular distance * line-length.
76 *
77 * Combining gives: distance = determinant / line-length(a,b)
78 */
79 static double point_line_distance(long px, long py,
80 long ax, long ay,
81 long bx, long by)
82 {
83 long det = ax*by - bx*ay + bx*py - px*by + px*ay - ax*py;
84 double len;
85 det = max(det, -det);
86 len = sqrt(SQ(ax - bx) + SQ(ay - by));
87 return det / len;
88 }
89
90 /* Determine nearest edge to where the user clicked.
91 * (x, y) is the clicked location, converted to grid coordinates.
92 * Returns the nearest edge, or NULL if no edge is reasonably
93 * near the position.
94 *
95 * This algorithm is nice and generic, and doesn't depend on any particular
96 * geometric layout of the grid:
97 * Start at any dot (pick one next to middle_face).
98 * Walk along a path by choosing, from all nearby dots, the one that is
99 * nearest the target (x,y). Hopefully end up at the dot which is closest
100 * to (x,y). Should work, as long as faces aren't too badly shaped.
101 * Then examine each edge around this dot, and pick whichever one is
102 * closest (perpendicular distance) to (x,y).
103 * Using perpendicular distance is not quite right - the edge might be
104 * "off to one side". So we insist that the triangle with (x,y) has
105 * acute angles at the edge's dots.
106 *
107 * edge1
108 * *---------*------
109 * |
110 * | *(x,y)
111 * edge2 |
112 * | edge2 is OK, but edge1 is not, even though
113 * | edge1 is perpendicularly closer to (x,y)
114 * *
115 *
116 */
117 grid_edge *grid_nearest_edge(grid *g, int x, int y)
118 {
119 grid_dot *cur;
120 grid_edge *best_edge;
121 double best_distance = 0;
122 int i;
123
124 cur = g->middle_face->dots[0];
125
126 for (;;) {
127 /* Target to beat */
128 long dist = SQ((long)cur->x - (long)x) + SQ((long)cur->y - (long)y);
129 /* Look for nearer dot - if found, store in 'new'. */
130 grid_dot *new = cur;
131 int i;
132 /* Search all dots in all faces touching this dot. Some shapes
133 * (such as in Cairo) don't quite work properly if we only search
134 * the dot's immediate neighbours. */
135 for (i = 0; i < cur->order; i++) {
136 grid_face *f = cur->faces[i];
137 int j;
138 if (!f) continue;
139 for (j = 0; j < f->order; j++) {
140 long new_dist;
141 grid_dot *d = f->dots[j];
142 if (d == cur) continue;
143 new_dist = SQ((long)d->x - (long)x) + SQ((long)d->y - (long)y);
144 if (new_dist < dist) { /* found closer dot */
145 new = d;
146 dist = new_dist;
147 }
148 }
149 }
150
151 if (new == cur) {
152 /* Didn't find a closer dot among the neighbours of 'cur' */
153 break;
154 } else {
155 cur = new;
156 }
157 }
158 /* 'cur' is nearest dot, so find which of the dot's edges is closest. */
159 best_edge = NULL;
160
161 for (i = 0; i < cur->order; i++) {
162 grid_edge *e = cur->edges[i];
163 long e2; /* squared length of edge */
164 long a2, b2; /* squared lengths of other sides */
165 double dist;
166
167 /* See if edge e is eligible - the triangle must have acute angles
168 * at the edge's dots.
169 * Pythagoras formula h^2 = a^2 + b^2 detects right-angles,
170 * so detect acute angles by testing for h^2 < a^2 + b^2 */
171 e2 = SQ((long)e->dot1->x - (long)e->dot2->x) + SQ((long)e->dot1->y - (long)e->dot2->y);
172 a2 = SQ((long)e->dot1->x - (long)x) + SQ((long)e->dot1->y - (long)y);
173 b2 = SQ((long)e->dot2->x - (long)x) + SQ((long)e->dot2->y - (long)y);
174 if (a2 >= e2 + b2) continue;
175 if (b2 >= e2 + a2) continue;
176
177 /* e is eligible so far. Now check the edge is reasonably close
178 * to where the user clicked. Don't want to toggle an edge if the
179 * click was way off the grid.
180 * There is room for experimentation here. We could check the
181 * perpendicular distance is within a certain fraction of the length
182 * of the edge. That amounts to testing a rectangular region around
183 * the edge.
184 * Alternatively, we could check that the angle at the point is obtuse.
185 * That would amount to testing a circular region with the edge as
186 * diameter. */
187 dist = point_line_distance((long)x, (long)y,
188 (long)e->dot1->x, (long)e->dot1->y,
189 (long)e->dot2->x, (long)e->dot2->y);
190 /* Is dist more than half edge length ? */
191 if (4 * SQ(dist) > e2)
192 continue;
193
194 if (best_edge == NULL || dist < best_distance) {
195 best_edge = e;
196 best_distance = dist;
197 }
198 }
199 return best_edge;
200 }
201
202 /* ----------------------------------------------------------------------
203 * Grid generation
204 */
205
206 #ifdef DEBUG_GRID
207 /* Show the basic grid information, before doing grid_make_consistent */
208 static void grid_print_basic(grid *g)
209 {
210 /* TODO: Maybe we should generate an SVG image of the dots and lines
211 * of the grid here, before grid_make_consistent.
212 * Would help with debugging grid generation. */
213 int i;
214 printf("--- Basic Grid Data ---\n");
215 for (i = 0; i < g->num_faces; i++) {
216 grid_face *f = g->faces + i;
217 printf("Face %d: dots[", i);
218 int j;
219 for (j = 0; j < f->order; j++) {
220 grid_dot *d = f->dots[j];
221 printf("%s%d", j ? "," : "", (int)(d - g->dots));
222 }
223 printf("]\n");
224 }
225 printf("Middle face: %d\n", (int)(g->middle_face - g->faces));
226 }
227 /* Show the derived grid information, computed by grid_make_consistent */
228 static void grid_print_derived(grid *g)
229 {
230 /* edges */
231 int i;
232 printf("--- Derived Grid Data ---\n");
233 for (i = 0; i < g->num_edges; i++) {
234 grid_edge *e = g->edges + i;
235 printf("Edge %d: dots[%d,%d] faces[%d,%d]\n",
236 i, (int)(e->dot1 - g->dots), (int)(e->dot2 - g->dots),
237 e->face1 ? (int)(e->face1 - g->faces) : -1,
238 e->face2 ? (int)(e->face2 - g->faces) : -1);
239 }
240 /* faces */
241 for (i = 0; i < g->num_faces; i++) {
242 grid_face *f = g->faces + i;
243 int j;
244 printf("Face %d: faces[", i);
245 for (j = 0; j < f->order; j++) {
246 grid_edge *e = f->edges[j];
247 grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1;
248 printf("%s%d", j ? "," : "", f2 ? (int)(f2 - g->faces) : -1);
249 }
250 printf("]\n");
251 }
252 /* dots */
253 for (i = 0; i < g->num_dots; i++) {
254 grid_dot *d = g->dots + i;
255 int j;
256 printf("Dot %d: dots[", i);
257 for (j = 0; j < d->order; j++) {
258 grid_edge *e = d->edges[j];
259 grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1;
260 printf("%s%d", j ? "," : "", (int)(d2 - g->dots));
261 }
262 printf("] faces[");
263 for (j = 0; j < d->order; j++) {
264 grid_face *f = d->faces[j];
265 printf("%s%d", j ? "," : "", f ? (int)(f - g->faces) : -1);
266 }
267 printf("]\n");
268 }
269 }
270 #endif /* DEBUG_GRID */
271
272 /* Helper function for building incomplete-edges list in
273 * grid_make_consistent() */
274 static int grid_edge_bydots_cmpfn(void *v1, void *v2)
275 {
276 grid_edge *a = v1;
277 grid_edge *b = v2;
278 grid_dot *da, *db;
279
280 /* Pointer subtraction is valid here, because all dots point into the
281 * same dot-list (g->dots).
282 * Edges are not "normalised" - the 2 dots could be stored in any order,
283 * so we need to take this into account when comparing edges. */
284
285 /* Compare first dots */
286 da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2;
287 db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2;
288 if (da != db)
289 return db - da;
290 /* Compare last dots */
291 da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1;
292 db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1;
293 if (da != db)
294 return db - da;
295
296 return 0;
297 }
298
299 /* Input: grid has its dots and faces initialised:
300 * - dots have (optionally) x and y coordinates, but no edges or faces
301 * (pointers are NULL).
302 * - edges not initialised at all
303 * - faces initialised and know which dots they have (but no edges yet). The
304 * dots around each face are assumed to be clockwise.
305 *
306 * Output: grid is complete and valid with all relationships defined.
307 */
308 static void grid_make_consistent(grid *g)
309 {
310 int i;
311 tree234 *incomplete_edges;
312 grid_edge *next_new_edge; /* Where new edge will go into g->edges */
313
314 #ifdef DEBUG_GRID
315 grid_print_basic(g);
316 #endif
317
318 /* ====== Stage 1 ======
319 * Generate edges
320 */
321
322 /* We know how many dots and faces there are, so we can find the exact
323 * number of edges from Euler's polyhedral formula: F + V = E + 2 .
324 * We use "-1", not "-2" here, because Euler's formula includes the
325 * infinite face, which we don't count. */
326 g->num_edges = g->num_faces + g->num_dots - 1;
327 g->edges = snewn(g->num_edges, grid_edge);
328 next_new_edge = g->edges;
329
330 /* Iterate over faces, and over each face's dots, generating edges as we
331 * go. As we find each new edge, we can immediately fill in the edge's
332 * dots, but only one of the edge's faces. Later on in the iteration, we
333 * will find the same edge again (unless it's on the border), but we will
334 * know the other face.
335 * For efficiency, maintain a list of the incomplete edges, sorted by
336 * their dots. */
337 incomplete_edges = newtree234(grid_edge_bydots_cmpfn);
338 for (i = 0; i < g->num_faces; i++) {
339 grid_face *f = g->faces + i;
340 int j;
341 for (j = 0; j < f->order; j++) {
342 grid_edge e; /* fake edge for searching */
343 grid_edge *edge_found;
344 int j2 = j + 1;
345 if (j2 == f->order)
346 j2 = 0;
347 e.dot1 = f->dots[j];
348 e.dot2 = f->dots[j2];
349 /* Use del234 instead of find234, because we always want to
350 * remove the edge if found */
351 edge_found = del234(incomplete_edges, &e);
352 if (edge_found) {
353 /* This edge already added, so fill out missing face.
354 * Edge is already removed from incomplete_edges. */
355 edge_found->face2 = f;
356 } else {
357 assert(next_new_edge - g->edges < g->num_edges);
358 next_new_edge->dot1 = e.dot1;
359 next_new_edge->dot2 = e.dot2;
360 next_new_edge->face1 = f;
361 next_new_edge->face2 = NULL; /* potentially infinite face */
362 add234(incomplete_edges, next_new_edge);
363 ++next_new_edge;
364 }
365 }
366 }
367 freetree234(incomplete_edges);
368
369 /* ====== Stage 2 ======
370 * For each face, build its edge list.
371 */
372
373 /* Allocate space for each edge list. Can do this, because each face's
374 * edge-list is the same size as its dot-list. */
375 for (i = 0; i < g->num_faces; i++) {
376 grid_face *f = g->faces + i;
377 int j;
378 f->edges = snewn(f->order, grid_edge*);
379 /* Preload with NULLs, to help detect potential bugs. */
380 for (j = 0; j < f->order; j++)
381 f->edges[j] = NULL;
382 }
383
384 /* Iterate over each edge, and over both its faces. Add this edge to
385 * the face's edge-list, after finding where it should go in the
386 * sequence. */
387 for (i = 0; i < g->num_edges; i++) {
388 grid_edge *e = g->edges + i;
389 int j;
390 for (j = 0; j < 2; j++) {
391 grid_face *f = j ? e->face2 : e->face1;
392 int k, k2;
393 if (f == NULL) continue;
394 /* Find one of the dots around the face */
395 for (k = 0; k < f->order; k++) {
396 if (f->dots[k] == e->dot1)
397 break; /* found dot1 */
398 }
399 assert(k != f->order); /* Must find the dot around this face */
400
401 /* Labelling scheme: as we walk clockwise around the face,
402 * starting at dot0 (f->dots[0]), we hit:
403 * (dot0), edge0, dot1, edge1, dot2,...
404 *
405 * 0
406 * 0-----1
407 * |
408 * |1
409 * |
410 * 3-----2
411 * 2
412 *
413 * Therefore, edgeK joins dotK and dot{K+1}
414 */
415
416 /* Around this face, either the next dot or the previous dot
417 * must be e->dot2. Otherwise the edge is wrong. */
418 k2 = k + 1;
419 if (k2 == f->order)
420 k2 = 0;
421 if (f->dots[k2] == e->dot2) {
422 /* dot1(k) and dot2(k2) go clockwise around this face, so add
423 * this edge at position k (see diagram). */
424 assert(f->edges[k] == NULL);
425 f->edges[k] = e;
426 continue;
427 }
428 /* Try previous dot */
429 k2 = k - 1;
430 if (k2 == -1)
431 k2 = f->order - 1;
432 if (f->dots[k2] == e->dot2) {
433 /* dot1(k) and dot2(k2) go anticlockwise around this face. */
434 assert(f->edges[k2] == NULL);
435 f->edges[k2] = e;
436 continue;
437 }
438 assert(!"Grid broken: bad edge-face relationship");
439 }
440 }
441
442 /* ====== Stage 3 ======
443 * For each dot, build its edge-list and face-list.
444 */
445
446 /* We don't know how many edges/faces go around each dot, so we can't
447 * allocate the right space for these lists. Pre-compute the sizes by
448 * iterating over each edge and recording a tally against each dot. */
449 for (i = 0; i < g->num_dots; i++) {
450 g->dots[i].order = 0;
451 }
452 for (i = 0; i < g->num_edges; i++) {
453 grid_edge *e = g->edges + i;
454 ++(e->dot1->order);
455 ++(e->dot2->order);
456 }
457 /* Now we have the sizes, pre-allocate the edge and face lists. */
458 for (i = 0; i < g->num_dots; i++) {
459 grid_dot *d = g->dots + i;
460 int j;
461 assert(d->order >= 2); /* sanity check */
462 d->edges = snewn(d->order, grid_edge*);
463 d->faces = snewn(d->order, grid_face*);
464 for (j = 0; j < d->order; j++) {
465 d->edges[j] = NULL;
466 d->faces[j] = NULL;
467 }
468 }
469 /* For each dot, need to find a face that touches it, so we can seed
470 * the edge-face-edge-face process around each dot. */
471 for (i = 0; i < g->num_faces; i++) {
472 grid_face *f = g->faces + i;
473 int j;
474 for (j = 0; j < f->order; j++) {
475 grid_dot *d = f->dots[j];
476 d->faces[0] = f;
477 }
478 }
479 /* Each dot now has a face in its first slot. Generate the remaining
480 * faces and edges around the dot, by searching both clockwise and
481 * anticlockwise from the first face. Need to do both directions,
482 * because of the possibility of hitting the infinite face, which
483 * blocks progress. But there's only one such face, so we will
484 * succeed in finding every edge and face this way. */
485 for (i = 0; i < g->num_dots; i++) {
486 grid_dot *d = g->dots + i;
487 int current_face1 = 0; /* ascends clockwise */
488 int current_face2 = 0; /* descends anticlockwise */
489
490 /* Labelling scheme: as we walk clockwise around the dot, starting
491 * at face0 (d->faces[0]), we hit:
492 * (face0), edge0, face1, edge1, face2,...
493 *
494 * 0
495 * |
496 * 0 | 1
497 * |
498 * -----d-----1
499 * |
500 * | 2
501 * |
502 * 2
503 *
504 * So, for example, face1 should be joined to edge0 and edge1,
505 * and those edges should appear in an anticlockwise sense around
506 * that face (see diagram). */
507
508 /* clockwise search */
509 while (TRUE) {
510 grid_face *f = d->faces[current_face1];
511 grid_edge *e;
512 int j;
513 assert(f != NULL);
514 /* find dot around this face */
515 for (j = 0; j < f->order; j++) {
516 if (f->dots[j] == d)
517 break;
518 }
519 assert(j != f->order); /* must find dot */
520
521 /* Around f, required edge is anticlockwise from the dot. See
522 * the other labelling scheme higher up, for why we subtract 1
523 * from j. */
524 j--;
525 if (j == -1)
526 j = f->order - 1;
527 e = f->edges[j];
528 d->edges[current_face1] = e; /* set edge */
529 current_face1++;
530 if (current_face1 == d->order)
531 break;
532 else {
533 /* set face */
534 d->faces[current_face1] =
535 (e->face1 == f) ? e->face2 : e->face1;
536 if (d->faces[current_face1] == NULL)
537 break; /* cannot progress beyond infinite face */
538 }
539 }
540 /* If the clockwise search made it all the way round, don't need to
541 * bother with the anticlockwise search. */
542 if (current_face1 == d->order)
543 continue; /* this dot is complete, move on to next dot */
544
545 /* anticlockwise search */
546 while (TRUE) {
547 grid_face *f = d->faces[current_face2];
548 grid_edge *e;
549 int j;
550 assert(f != NULL);
551 /* find dot around this face */
552 for (j = 0; j < f->order; j++) {
553 if (f->dots[j] == d)
554 break;
555 }
556 assert(j != f->order); /* must find dot */
557
558 /* Around f, required edge is clockwise from the dot. */
559 e = f->edges[j];
560
561 current_face2--;
562 if (current_face2 == -1)
563 current_face2 = d->order - 1;
564 d->edges[current_face2] = e; /* set edge */
565
566 /* set face */
567 if (current_face2 == current_face1)
568 break;
569 d->faces[current_face2] =
570 (e->face1 == f) ? e->face2 : e->face1;
571 /* There's only 1 infinite face, so we must get all the way
572 * to current_face1 before we hit it. */
573 assert(d->faces[current_face2]);
574 }
575 }
576
577 /* ====== Stage 4 ======
578 * Compute other grid settings
579 */
580
581 /* Bounding rectangle */
582 for (i = 0; i < g->num_dots; i++) {
583 grid_dot *d = g->dots + i;
584 if (i == 0) {
585 g->lowest_x = g->highest_x = d->x;
586 g->lowest_y = g->highest_y = d->y;
587 } else {
588 g->lowest_x = min(g->lowest_x, d->x);
589 g->highest_x = max(g->highest_x, d->x);
590 g->lowest_y = min(g->lowest_y, d->y);
591 g->highest_y = max(g->highest_y, d->y);
592 }
593 }
594
595 #ifdef DEBUG_GRID
596 grid_print_derived(g);
597 #endif
598 }
599
600 /* Helpers for making grid-generation easier. These functions are only
601 * intended for use during grid generation. */
602
603 /* Comparison function for the (tree234) sorted dot list */
604 static int grid_point_cmp_fn(void *v1, void *v2)
605 {
606 grid_dot *p1 = v1;
607 grid_dot *p2 = v2;
608 if (p1->y != p2->y)
609 return p2->y - p1->y;
610 else
611 return p2->x - p1->x;
612 }
613 /* Add a new face to the grid, with its dot list allocated.
614 * Assumes there's enough space allocated for the new face in grid->faces */
615 static void grid_face_add_new(grid *g, int face_size)
616 {
617 int i;
618 grid_face *new_face = g->faces + g->num_faces;
619 new_face->order = face_size;
620 new_face->dots = snewn(face_size, grid_dot*);
621 for (i = 0; i < face_size; i++)
622 new_face->dots[i] = NULL;
623 new_face->edges = NULL;
624 g->num_faces++;
625 }
626 /* Assumes dot list has enough space */
627 static grid_dot *grid_dot_add_new(grid *g, int x, int y)
628 {
629 grid_dot *new_dot = g->dots + g->num_dots;
630 new_dot->order = 0;
631 new_dot->edges = NULL;
632 new_dot->faces = NULL;
633 new_dot->x = x;
634 new_dot->y = y;
635 g->num_dots++;
636 return new_dot;
637 }
638 /* Retrieve a dot with these (x,y) coordinates. Either return an existing dot
639 * in the dot_list, or add a new dot to the grid (and the dot_list) and
640 * return that.
641 * Assumes g->dots has enough capacity allocated */
642 static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y)
643 {
644 grid_dot test, *ret;
645
646 test.order = 0;
647 test.edges = NULL;
648 test.faces = NULL;
649 test.x = x;
650 test.y = y;
651 ret = find234(dot_list, &test, NULL);
652 if (ret)
653 return ret;
654
655 ret = grid_dot_add_new(g, x, y);
656 add234(dot_list, ret);
657 return ret;
658 }
659
660 /* Sets the last face of the grid to include this dot, at this position
661 * around the face. Assumes num_faces is at least 1 (a new face has
662 * previously been added, with the required number of dots allocated) */
663 static void grid_face_set_dot(grid *g, grid_dot *d, int position)
664 {
665 grid_face *last_face = g->faces + g->num_faces - 1;
666 last_face->dots[position] = d;
667 }
668
669 /* ------ Generate various types of grid ------ */
670
671 /* General method is to generate faces, by calculating their dot coordinates.
672 * As new faces are added, we keep track of all the dots so we can tell when
673 * a new face reuses an existing dot. For example, two squares touching at an
674 * edge would generate six unique dots: four dots from the first face, then
675 * two additional dots for the second face, because we detect the other two
676 * dots have already been taken up. This list is stored in a tree234
677 * called "points". No extra memory-allocation needed here - we store the
678 * actual grid_dot* pointers, which all point into the g->dots list.
679 * For this reason, we have to calculate coordinates in such a way as to
680 * eliminate any rounding errors, so we can detect when a dot on one
681 * face precisely lands on a dot of a different face. No floating-point
682 * arithmetic here!
683 */
684
685 grid *grid_new_square(int width, int height)
686 {
687 int x, y;
688 /* Side length */
689 int a = 20;
690
691 /* Upper bounds - don't have to be exact */
692 int max_faces = width * height;
693 int max_dots = (width + 1) * (height + 1);
694
695 tree234 *points;
696
697 grid *g = grid_new();
698 g->tilesize = a;
699 g->faces = snewn(max_faces, grid_face);
700 g->dots = snewn(max_dots, grid_dot);
701
702 points = newtree234(grid_point_cmp_fn);
703
704 /* generate square faces */
705 for (y = 0; y < height; y++) {
706 for (x = 0; x < width; x++) {
707 grid_dot *d;
708 /* face position */
709 int px = a * x;
710 int py = a * y;
711
712 grid_face_add_new(g, 4);
713 d = grid_get_dot(g, points, px, py);
714 grid_face_set_dot(g, d, 0);
715 d = grid_get_dot(g, points, px + a, py);
716 grid_face_set_dot(g, d, 1);
717 d = grid_get_dot(g, points, px + a, py + a);
718 grid_face_set_dot(g, d, 2);
719 d = grid_get_dot(g, points, px, py + a);
720 grid_face_set_dot(g, d, 3);
721 }
722 }
723
724 freetree234(points);
725 assert(g->num_faces <= max_faces);
726 assert(g->num_dots <= max_dots);
727 g->middle_face = g->faces + (height/2) * width + (width/2);
728
729 grid_make_consistent(g);
730 return g;
731 }
732
733 grid *grid_new_honeycomb(int width, int height)
734 {
735 int x, y;
736 /* Vector for side of hexagon - ratio is close to sqrt(3) */
737 int a = 15;
738 int b = 26;
739
740 /* Upper bounds - don't have to be exact */
741 int max_faces = width * height;
742 int max_dots = 2 * (width + 1) * (height + 1);
743
744 tree234 *points;
745
746 grid *g = grid_new();
747 g->tilesize = 3 * a;
748 g->faces = snewn(max_faces, grid_face);
749 g->dots = snewn(max_dots, grid_dot);
750
751 points = newtree234(grid_point_cmp_fn);
752
753 /* generate hexagonal faces */
754 for (y = 0; y < height; y++) {
755 for (x = 0; x < width; x++) {
756 grid_dot *d;
757 /* face centre */
758 int cx = 3 * a * x;
759 int cy = 2 * b * y;
760 if (x % 2)
761 cy += b;
762 grid_face_add_new(g, 6);
763
764 d = grid_get_dot(g, points, cx - a, cy - b);
765 grid_face_set_dot(g, d, 0);
766 d = grid_get_dot(g, points, cx + a, cy - b);
767 grid_face_set_dot(g, d, 1);
768 d = grid_get_dot(g, points, cx + 2*a, cy);
769 grid_face_set_dot(g, d, 2);
770 d = grid_get_dot(g, points, cx + a, cy + b);
771 grid_face_set_dot(g, d, 3);
772 d = grid_get_dot(g, points, cx - a, cy + b);
773 grid_face_set_dot(g, d, 4);
774 d = grid_get_dot(g, points, cx - 2*a, cy);
775 grid_face_set_dot(g, d, 5);
776 }
777 }
778
779 freetree234(points);
780 assert(g->num_faces <= max_faces);
781 assert(g->num_dots <= max_dots);
782 g->middle_face = g->faces + (height/2) * width + (width/2);
783
784 grid_make_consistent(g);
785 return g;
786 }
787
788 /* Doesn't use the previous method of generation, it pre-dates it!
789 * A triangular grid is just about simple enough to do by "brute force" */
790 grid *grid_new_triangular(int width, int height)
791 {
792 int x,y;
793
794 /* Vector for side of triangle - ratio is close to sqrt(3) */
795 int vec_x = 15;
796 int vec_y = 26;
797
798 int index;
799
800 /* convenient alias */
801 int w = width + 1;
802
803 grid *g = grid_new();
804 g->tilesize = 18; /* adjust to your taste */
805
806 g->num_faces = width * height * 2;
807 g->num_dots = (width + 1) * (height + 1);
808 g->faces = snewn(g->num_faces, grid_face);
809 g->dots = snewn(g->num_dots, grid_dot);
810
811 /* generate dots */
812 index = 0;
813 for (y = 0; y <= height; y++) {
814 for (x = 0; x <= width; x++) {
815 grid_dot *d = g->dots + index;
816 /* odd rows are offset to the right */
817 d->order = 0;
818 d->edges = NULL;
819 d->faces = NULL;
820 d->x = x * 2 * vec_x + ((y % 2) ? vec_x : 0);
821 d->y = y * vec_y;
822 index++;
823 }
824 }
825
826 /* generate faces */
827 index = 0;
828 for (y = 0; y < height; y++) {
829 for (x = 0; x < width; x++) {
830 /* initialise two faces for this (x,y) */
831 grid_face *f1 = g->faces + index;
832 grid_face *f2 = f1 + 1;
833 f1->edges = NULL;
834 f1->order = 3;
835 f1->dots = snewn(f1->order, grid_dot*);
836 f2->edges = NULL;
837 f2->order = 3;
838 f2->dots = snewn(f2->order, grid_dot*);
839
840 /* face descriptions depend on whether the row-number is
841 * odd or even */
842 if (y % 2) {
843 f1->dots[0] = g->dots + y * w + x;
844 f1->dots[1] = g->dots + (y + 1) * w + x + 1;
845 f1->dots[2] = g->dots + (y + 1) * w + x;
846 f2->dots[0] = g->dots + y * w + x;
847 f2->dots[1] = g->dots + y * w + x + 1;
848 f2->dots[2] = g->dots + (y + 1) * w + x + 1;
849 } else {
850 f1->dots[0] = g->dots + y * w + x;
851 f1->dots[1] = g->dots + y * w + x + 1;
852 f1->dots[2] = g->dots + (y + 1) * w + x;
853 f2->dots[0] = g->dots + y * w + x + 1;
854 f2->dots[1] = g->dots + (y + 1) * w + x + 1;
855 f2->dots[2] = g->dots + (y + 1) * w + x;
856 }
857 index += 2;
858 }
859 }
860
861 /* "+ width" takes us to the middle of the row, because each row has
862 * (2*width) faces. */
863 g->middle_face = g->faces + (height / 2) * 2 * width + width;
864
865 grid_make_consistent(g);
866 return g;
867 }
868
869 grid *grid_new_snubsquare(int width, int height)
870 {
871 int x, y;
872 /* Vector for side of triangle - ratio is close to sqrt(3) */
873 int a = 15;
874 int b = 26;
875
876 /* Upper bounds - don't have to be exact */
877 int max_faces = 3 * width * height;
878 int max_dots = 2 * (width + 1) * (height + 1);
879
880 tree234 *points;
881
882 grid *g = grid_new();
883 g->tilesize = 18;
884 g->faces = snewn(max_faces, grid_face);
885 g->dots = snewn(max_dots, grid_dot);
886
887 points = newtree234(grid_point_cmp_fn);
888
889 for (y = 0; y < height; y++) {
890 for (x = 0; x < width; x++) {
891 grid_dot *d;
892 /* face position */
893 int px = (a + b) * x;
894 int py = (a + b) * y;
895
896 /* generate square faces */
897 grid_face_add_new(g, 4);
898 if ((x + y) % 2) {
899 d = grid_get_dot(g, points, px + a, py);
900 grid_face_set_dot(g, d, 0);
901 d = grid_get_dot(g, points, px + a + b, py + a);
902 grid_face_set_dot(g, d, 1);
903 d = grid_get_dot(g, points, px + b, py + a + b);
904 grid_face_set_dot(g, d, 2);
905 d = grid_get_dot(g, points, px, py + b);
906 grid_face_set_dot(g, d, 3);
907 } else {
908 d = grid_get_dot(g, points, px + b, py);
909 grid_face_set_dot(g, d, 0);
910 d = grid_get_dot(g, points, px + a + b, py + b);
911 grid_face_set_dot(g, d, 1);
912 d = grid_get_dot(g, points, px + a, py + a + b);
913 grid_face_set_dot(g, d, 2);
914 d = grid_get_dot(g, points, px, py + a);
915 grid_face_set_dot(g, d, 3);
916 }
917
918 /* generate up/down triangles */
919 if (x > 0) {
920 grid_face_add_new(g, 3);
921 if ((x + y) % 2) {
922 d = grid_get_dot(g, points, px + a, py);
923 grid_face_set_dot(g, d, 0);
924 d = grid_get_dot(g, points, px, py + b);
925 grid_face_set_dot(g, d, 1);
926 d = grid_get_dot(g, points, px - a, py);
927 grid_face_set_dot(g, d, 2);
928 } else {
929 d = grid_get_dot(g, points, px, py + a);
930 grid_face_set_dot(g, d, 0);
931 d = grid_get_dot(g, points, px + a, py + a + b);
932 grid_face_set_dot(g, d, 1);
933 d = grid_get_dot(g, points, px - a, py + a + b);
934 grid_face_set_dot(g, d, 2);
935 }
936 }
937
938 /* generate left/right triangles */
939 if (y > 0) {
940 grid_face_add_new(g, 3);
941 if ((x + y) % 2) {
942 d = grid_get_dot(g, points, px + a, py);
943 grid_face_set_dot(g, d, 0);
944 d = grid_get_dot(g, points, px + a + b, py - a);
945 grid_face_set_dot(g, d, 1);
946 d = grid_get_dot(g, points, px + a + b, py + a);
947 grid_face_set_dot(g, d, 2);
948 } else {
949 d = grid_get_dot(g, points, px, py - a);
950 grid_face_set_dot(g, d, 0);
951 d = grid_get_dot(g, points, px + b, py);
952 grid_face_set_dot(g, d, 1);
953 d = grid_get_dot(g, points, px, py + a);
954 grid_face_set_dot(g, d, 2);
955 }
956 }
957 }
958 }
959
960 freetree234(points);
961 assert(g->num_faces <= max_faces);
962 assert(g->num_dots <= max_dots);
963 g->middle_face = g->faces + (height/2) * width + (width/2);
964
965 grid_make_consistent(g);
966 return g;
967 }
968
969 grid *grid_new_cairo(int width, int height)
970 {
971 int x, y;
972 /* Vector for side of pentagon - ratio is close to (4+sqrt(7))/3 */
973 int a = 14;
974 int b = 31;
975
976 /* Upper bounds - don't have to be exact */
977 int max_faces = 2 * width * height;
978 int max_dots = 3 * (width + 1) * (height + 1);
979
980 tree234 *points;
981
982 grid *g = grid_new();
983 g->tilesize = 40;
984 g->faces = snewn(max_faces, grid_face);
985 g->dots = snewn(max_dots, grid_dot);
986
987 points = newtree234(grid_point_cmp_fn);
988
989 for (y = 0; y < height; y++) {
990 for (x = 0; x < width; x++) {
991 grid_dot *d;
992 /* cell position */
993 int px = 2 * b * x;
994 int py = 2 * b * y;
995
996 /* horizontal pentagons */
997 if (y > 0) {
998 grid_face_add_new(g, 5);
999 if ((x + y) % 2) {
1000 d = grid_get_dot(g, points, px + a, py - b);
1001 grid_face_set_dot(g, d, 0);
1002 d = grid_get_dot(g, points, px + 2*b - a, py - b);
1003 grid_face_set_dot(g, d, 1);
1004 d = grid_get_dot(g, points, px + 2*b, py);
1005 grid_face_set_dot(g, d, 2);
1006 d = grid_get_dot(g, points, px + b, py + a);
1007 grid_face_set_dot(g, d, 3);
1008 d = grid_get_dot(g, points, px, py);
1009 grid_face_set_dot(g, d, 4);
1010 } else {
1011 d = grid_get_dot(g, points, px, py);
1012 grid_face_set_dot(g, d, 0);
1013 d = grid_get_dot(g, points, px + b, py - a);
1014 grid_face_set_dot(g, d, 1);
1015 d = grid_get_dot(g, points, px + 2*b, py);
1016 grid_face_set_dot(g, d, 2);
1017 d = grid_get_dot(g, points, px + 2*b - a, py + b);
1018 grid_face_set_dot(g, d, 3);
1019 d = grid_get_dot(g, points, px + a, py + b);
1020 grid_face_set_dot(g, d, 4);
1021 }
1022 }
1023 /* vertical pentagons */
1024 if (x > 0) {
1025 grid_face_add_new(g, 5);
1026 if ((x + y) % 2) {
1027 d = grid_get_dot(g, points, px, py);
1028 grid_face_set_dot(g, d, 0);
1029 d = grid_get_dot(g, points, px + b, py + a);
1030 grid_face_set_dot(g, d, 1);
1031 d = grid_get_dot(g, points, px + b, py + 2*b - a);
1032 grid_face_set_dot(g, d, 2);
1033 d = grid_get_dot(g, points, px, py + 2*b);
1034 grid_face_set_dot(g, d, 3);
1035 d = grid_get_dot(g, points, px - a, py + b);
1036 grid_face_set_dot(g, d, 4);
1037 } else {
1038 d = grid_get_dot(g, points, px, py);
1039 grid_face_set_dot(g, d, 0);
1040 d = grid_get_dot(g, points, px + a, py + b);
1041 grid_face_set_dot(g, d, 1);
1042 d = grid_get_dot(g, points, px, py + 2*b);
1043 grid_face_set_dot(g, d, 2);
1044 d = grid_get_dot(g, points, px - b, py + 2*b - a);
1045 grid_face_set_dot(g, d, 3);
1046 d = grid_get_dot(g, points, px - b, py + a);
1047 grid_face_set_dot(g, d, 4);
1048 }
1049 }
1050 }
1051 }
1052
1053 freetree234(points);
1054 assert(g->num_faces <= max_faces);
1055 assert(g->num_dots <= max_dots);
1056 g->middle_face = g->faces + (height/2) * width + (width/2);
1057
1058 grid_make_consistent(g);
1059 return g;
1060 }
1061
1062 grid *grid_new_greathexagonal(int width, int height)
1063 {
1064 int x, y;
1065 /* Vector for side of triangle - ratio is close to sqrt(3) */
1066 int a = 15;
1067 int b = 26;
1068
1069 /* Upper bounds - don't have to be exact */
1070 int max_faces = 6 * (width + 1) * (height + 1);
1071 int max_dots = 6 * width * height;
1072
1073 tree234 *points;
1074
1075 grid *g = grid_new();
1076 g->tilesize = 18;
1077 g->faces = snewn(max_faces, grid_face);
1078 g->dots = snewn(max_dots, grid_dot);
1079
1080 points = newtree234(grid_point_cmp_fn);
1081
1082 for (y = 0; y < height; y++) {
1083 for (x = 0; x < width; x++) {
1084 grid_dot *d;
1085 /* centre of hexagon */
1086 int px = (3*a + b) * x;
1087 int py = (2*a + 2*b) * y;
1088 if (x % 2)
1089 py += a + b;
1090
1091 /* hexagon */
1092 grid_face_add_new(g, 6);
1093 d = grid_get_dot(g, points, px - a, py - b);
1094 grid_face_set_dot(g, d, 0);
1095 d = grid_get_dot(g, points, px + a, py - b);
1096 grid_face_set_dot(g, d, 1);
1097 d = grid_get_dot(g, points, px + 2*a, py);
1098 grid_face_set_dot(g, d, 2);
1099 d = grid_get_dot(g, points, px + a, py + b);
1100 grid_face_set_dot(g, d, 3);
1101 d = grid_get_dot(g, points, px - a, py + b);
1102 grid_face_set_dot(g, d, 4);
1103 d = grid_get_dot(g, points, px - 2*a, py);
1104 grid_face_set_dot(g, d, 5);
1105
1106 /* square below hexagon */
1107 if (y < height - 1) {
1108 grid_face_add_new(g, 4);
1109 d = grid_get_dot(g, points, px - a, py + b);
1110 grid_face_set_dot(g, d, 0);
1111 d = grid_get_dot(g, points, px + a, py + b);
1112 grid_face_set_dot(g, d, 1);
1113 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1114 grid_face_set_dot(g, d, 2);
1115 d = grid_get_dot(g, points, px - a, py + 2*a + b);
1116 grid_face_set_dot(g, d, 3);
1117 }
1118
1119 /* square below right */
1120 if ((x < width - 1) && (((x % 2) == 0) || (y < height - 1))) {
1121 grid_face_add_new(g, 4);
1122 d = grid_get_dot(g, points, px + 2*a, py);
1123 grid_face_set_dot(g, d, 0);
1124 d = grid_get_dot(g, points, px + 2*a + b, py + a);
1125 grid_face_set_dot(g, d, 1);
1126 d = grid_get_dot(g, points, px + a + b, py + a + b);
1127 grid_face_set_dot(g, d, 2);
1128 d = grid_get_dot(g, points, px + a, py + b);
1129 grid_face_set_dot(g, d, 3);
1130 }
1131
1132 /* square below left */
1133 if ((x > 0) && (((x % 2) == 0) || (y < height - 1))) {
1134 grid_face_add_new(g, 4);
1135 d = grid_get_dot(g, points, px - 2*a, py);
1136 grid_face_set_dot(g, d, 0);
1137 d = grid_get_dot(g, points, px - a, py + b);
1138 grid_face_set_dot(g, d, 1);
1139 d = grid_get_dot(g, points, px - a - b, py + a + b);
1140 grid_face_set_dot(g, d, 2);
1141 d = grid_get_dot(g, points, px - 2*a - b, py + a);
1142 grid_face_set_dot(g, d, 3);
1143 }
1144
1145 /* Triangle below right */
1146 if ((x < width - 1) && (y < height - 1)) {
1147 grid_face_add_new(g, 3);
1148 d = grid_get_dot(g, points, px + a, py + b);
1149 grid_face_set_dot(g, d, 0);
1150 d = grid_get_dot(g, points, px + a + b, py + a + b);
1151 grid_face_set_dot(g, d, 1);
1152 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1153 grid_face_set_dot(g, d, 2);
1154 }
1155
1156 /* Triangle below left */
1157 if ((x > 0) && (y < height - 1)) {
1158 grid_face_add_new(g, 3);
1159 d = grid_get_dot(g, points, px - a, py + b);
1160 grid_face_set_dot(g, d, 0);
1161 d = grid_get_dot(g, points, px - a, py + 2*a + b);
1162 grid_face_set_dot(g, d, 1);
1163 d = grid_get_dot(g, points, px - a - b, py + a + b);
1164 grid_face_set_dot(g, d, 2);
1165 }
1166 }
1167 }
1168
1169 freetree234(points);
1170 assert(g->num_faces <= max_faces);
1171 assert(g->num_dots <= max_dots);
1172 g->middle_face = g->faces + (height/2) * width + (width/2);
1173
1174 grid_make_consistent(g);
1175 return g;
1176 }
1177
1178 grid *grid_new_octagonal(int width, int height)
1179 {
1180 int x, y;
1181 /* b/a approx sqrt(2) */
1182 int a = 29;
1183 int b = 41;
1184
1185 /* Upper bounds - don't have to be exact */
1186 int max_faces = 2 * width * height;
1187 int max_dots = 4 * (width + 1) * (height + 1);
1188
1189 tree234 *points;
1190
1191 grid *g = grid_new();
1192 g->tilesize = 40;
1193 g->faces = snewn(max_faces, grid_face);
1194 g->dots = snewn(max_dots, grid_dot);
1195
1196 points = newtree234(grid_point_cmp_fn);
1197
1198 for (y = 0; y < height; y++) {
1199 for (x = 0; x < width; x++) {
1200 grid_dot *d;
1201 /* cell position */
1202 int px = (2*a + b) * x;
1203 int py = (2*a + b) * y;
1204 /* octagon */
1205 grid_face_add_new(g, 8);
1206 d = grid_get_dot(g, points, px + a, py);
1207 grid_face_set_dot(g, d, 0);
1208 d = grid_get_dot(g, points, px + a + b, py);
1209 grid_face_set_dot(g, d, 1);
1210 d = grid_get_dot(g, points, px + 2*a + b, py + a);
1211 grid_face_set_dot(g, d, 2);
1212 d = grid_get_dot(g, points, px + 2*a + b, py + a + b);
1213 grid_face_set_dot(g, d, 3);
1214 d = grid_get_dot(g, points, px + a + b, py + 2*a + b);
1215 grid_face_set_dot(g, d, 4);
1216 d = grid_get_dot(g, points, px + a, py + 2*a + b);
1217 grid_face_set_dot(g, d, 5);
1218 d = grid_get_dot(g, points, px, py + a + b);
1219 grid_face_set_dot(g, d, 6);
1220 d = grid_get_dot(g, points, px, py + a);
1221 grid_face_set_dot(g, d, 7);
1222
1223 /* diamond */
1224 if ((x > 0) && (y > 0)) {
1225 grid_face_add_new(g, 4);
1226 d = grid_get_dot(g, points, px, py - a);
1227 grid_face_set_dot(g, d, 0);
1228 d = grid_get_dot(g, points, px + a, py);
1229 grid_face_set_dot(g, d, 1);
1230 d = grid_get_dot(g, points, px, py + a);
1231 grid_face_set_dot(g, d, 2);
1232 d = grid_get_dot(g, points, px - a, py);
1233 grid_face_set_dot(g, d, 3);
1234 }
1235 }
1236 }
1237
1238 freetree234(points);
1239 assert(g->num_faces <= max_faces);
1240 assert(g->num_dots <= max_dots);
1241 g->middle_face = g->faces + (height/2) * width + (width/2);
1242
1243 grid_make_consistent(g);
1244 return g;
1245 }
1246
1247 grid *grid_new_kites(int width, int height)
1248 {
1249 int x, y;
1250 /* b/a approx sqrt(3) */
1251 int a = 15;
1252 int b = 26;
1253
1254 /* Upper bounds - don't have to be exact */
1255 int max_faces = 6 * width * height;
1256 int max_dots = 6 * (width + 1) * (height + 1);
1257
1258 tree234 *points;
1259
1260 grid *g = grid_new();
1261 g->tilesize = 40;
1262 g->faces = snewn(max_faces, grid_face);
1263 g->dots = snewn(max_dots, grid_dot);
1264
1265 points = newtree234(grid_point_cmp_fn);
1266
1267 for (y = 0; y < height; y++) {
1268 for (x = 0; x < width; x++) {
1269 grid_dot *d;
1270 /* position of order-6 dot */
1271 int px = 4*b * x;
1272 int py = 6*a * y;
1273 if (y % 2)
1274 px += 2*b;
1275
1276 /* kite pointing up-left */
1277 grid_face_add_new(g, 4);
1278 d = grid_get_dot(g, points, px, py);
1279 grid_face_set_dot(g, d, 0);
1280 d = grid_get_dot(g, points, px + 2*b, py);
1281 grid_face_set_dot(g, d, 1);
1282 d = grid_get_dot(g, points, px + 2*b, py + 2*a);
1283 grid_face_set_dot(g, d, 2);
1284 d = grid_get_dot(g, points, px + b, py + 3*a);
1285 grid_face_set_dot(g, d, 3);
1286
1287 /* kite pointing up */
1288 grid_face_add_new(g, 4);
1289 d = grid_get_dot(g, points, px, py);
1290 grid_face_set_dot(g, d, 0);
1291 d = grid_get_dot(g, points, px + b, py + 3*a);
1292 grid_face_set_dot(g, d, 1);
1293 d = grid_get_dot(g, points, px, py + 4*a);
1294 grid_face_set_dot(g, d, 2);
1295 d = grid_get_dot(g, points, px - b, py + 3*a);
1296 grid_face_set_dot(g, d, 3);
1297
1298 /* kite pointing up-right */
1299 grid_face_add_new(g, 4);
1300 d = grid_get_dot(g, points, px, py);
1301 grid_face_set_dot(g, d, 0);
1302 d = grid_get_dot(g, points, px - b, py + 3*a);
1303 grid_face_set_dot(g, d, 1);
1304 d = grid_get_dot(g, points, px - 2*b, py + 2*a);
1305 grid_face_set_dot(g, d, 2);
1306 d = grid_get_dot(g, points, px - 2*b, py);
1307 grid_face_set_dot(g, d, 3);
1308
1309 /* kite pointing down-right */
1310 grid_face_add_new(g, 4);
1311 d = grid_get_dot(g, points, px, py);
1312 grid_face_set_dot(g, d, 0);
1313 d = grid_get_dot(g, points, px - 2*b, py);
1314 grid_face_set_dot(g, d, 1);
1315 d = grid_get_dot(g, points, px - 2*b, py - 2*a);
1316 grid_face_set_dot(g, d, 2);
1317 d = grid_get_dot(g, points, px - b, py - 3*a);
1318 grid_face_set_dot(g, d, 3);
1319
1320 /* kite pointing down */
1321 grid_face_add_new(g, 4);
1322 d = grid_get_dot(g, points, px, py);
1323 grid_face_set_dot(g, d, 0);
1324 d = grid_get_dot(g, points, px - b, py - 3*a);
1325 grid_face_set_dot(g, d, 1);
1326 d = grid_get_dot(g, points, px, py - 4*a);
1327 grid_face_set_dot(g, d, 2);
1328 d = grid_get_dot(g, points, px + b, py - 3*a);
1329 grid_face_set_dot(g, d, 3);
1330
1331 /* kite pointing down-left */
1332 grid_face_add_new(g, 4);
1333 d = grid_get_dot(g, points, px, py);
1334 grid_face_set_dot(g, d, 0);
1335 d = grid_get_dot(g, points, px + b, py - 3*a);
1336 grid_face_set_dot(g, d, 1);
1337 d = grid_get_dot(g, points, px + 2*b, py - 2*a);
1338 grid_face_set_dot(g, d, 2);
1339 d = grid_get_dot(g, points, px + 2*b, py);
1340 grid_face_set_dot(g, d, 3);
1341 }
1342 }
1343
1344 freetree234(points);
1345 assert(g->num_faces <= max_faces);
1346 assert(g->num_dots <= max_dots);
1347 g->middle_face = g->faces + 6 * ((height/2) * width + (width/2));
1348
1349 grid_make_consistent(g);
1350 return g;
1351 }
1352
1353 /* ----------- End of grid generators ------------- */