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