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