mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 23:51:29 -07:00
Hats tiling: make hat-test draw each hat in one go.
By introducing a second callback between the client of hat.c and the maybe_report_hat function, I enable the test main() to provide a different version of that callback, so that instead of enumerating each kite, it can directly generate a Postscript path per actual hat. This should make it more useful to people wanting to generate hat patterns for any other purpose. The internal callback gets more details than the external one; in particular, it receives a HatCoords, so that it can colour hats based on their position in the hierarchical structure.
This commit is contained in:
150
hat.c
150
hat.c
@ -959,9 +959,14 @@ const char *hat_tiling_params_invalid(const struct HatPatchParams *hp)
|
||||
* kites inside the rectangle, so its kite #0 will certainly be caught
|
||||
* by this iteration.)
|
||||
*/
|
||||
|
||||
typedef void (*internal_hat_callback_fn)(void *ctx, Kite kite0, HatCoords *hc,
|
||||
int *coords);
|
||||
|
||||
static void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
|
||||
hat_tile_callback_fn cb, void *cbctx)
|
||||
internal_hat_callback_fn cb, void *cbctx)
|
||||
{
|
||||
Kite kite0;
|
||||
Point vertices[14];
|
||||
size_t i, j;
|
||||
bool reversed = false;
|
||||
@ -970,6 +975,7 @@ static void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
|
||||
/* Only iterate from kite #0 of a hat */
|
||||
if (hc->c[0].index != 0)
|
||||
return;
|
||||
kite0 = kite;
|
||||
|
||||
/*
|
||||
* Identify reflected hats: they are always hat #3 of an H
|
||||
@ -1032,7 +1038,17 @@ static void maybe_report_hat(int w, int h, Kite kite, HatCoords *hc,
|
||||
coords[2*i+1] = y;
|
||||
}
|
||||
|
||||
cb(cbctx, 14, coords);
|
||||
cb(cbctx, kite0, hc, coords);
|
||||
}
|
||||
|
||||
struct internal_ctx {
|
||||
hat_tile_callback_fn external_cb;
|
||||
void *external_cbctx;
|
||||
};
|
||||
static void report_hat(void *vctx, Kite kite0, HatCoords *hc, int *coords)
|
||||
{
|
||||
struct internal_ctx *ctx = (struct internal_ctx *)vctx;
|
||||
ctx->external_cb(ctx->external_cbctx, 14, coords);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1045,6 +1061,10 @@ void hat_tiling_generate(const struct HatPatchParams *hp, int w, int h,
|
||||
HatCoords *coords[KE_NKEEP];
|
||||
KiteEnum s[1];
|
||||
size_t i;
|
||||
struct internal_ctx report_hat_ctx[1];
|
||||
|
||||
report_hat_ctx->external_cb = cb;
|
||||
report_hat_ctx->external_cbctx = cbctx;
|
||||
|
||||
init_coords_params(ctx, hp);
|
||||
for (i = 0; i < lenof(coords); i++)
|
||||
@ -1052,13 +1072,15 @@ void hat_tiling_generate(const struct HatPatchParams *hp, int w, int h,
|
||||
|
||||
first_kite(s, w, h);
|
||||
coords[s->curr_index] = initial_coords(ctx);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index], cb, cbctx);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
report_hat, report_hat_ctx);
|
||||
|
||||
while (next_kite(s)) {
|
||||
hc_free(coords[s->curr_index]);
|
||||
coords[s->curr_index] = step_coords(
|
||||
ctx, coords[s->last_index], s->last_step);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index], cb, cbctx);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
report_hat, report_hat_ctx);
|
||||
}
|
||||
|
||||
cleanup_coords(ctx);
|
||||
@ -1216,12 +1238,6 @@ typedef struct pspoint {
|
||||
float x, y;
|
||||
} pspoint;
|
||||
|
||||
static inline pspoint pscoords(Point p)
|
||||
{
|
||||
pspoint q = { p.x + p.y / 2.0F, p.y * sqrt(0.75) };
|
||||
return q;
|
||||
}
|
||||
|
||||
typedef struct psbbox {
|
||||
bool started;
|
||||
pspoint bl, tr;
|
||||
@ -1256,84 +1272,46 @@ static void header(psbbox *bbox)
|
||||
ox + scale * bbox->tr.x + 20, oy + scale * bbox->tr.y + 20);
|
||||
|
||||
printf("%f %f translate %f dup scale\n", ox, oy, scale);
|
||||
printf("%f setlinewidth\n", 0.1);
|
||||
printf("/thick { %f setlinewidth } def\n", 0.7);
|
||||
printf("%f setlinewidth\n", scale * 0.03);
|
||||
printf("0 setgray 1 setlinejoin 1 setlinecap\n");
|
||||
}
|
||||
|
||||
static void bbox_add_kite(Kite k, psbbox *bbox)
|
||||
static void bbox_add_hat(void *vctx, Kite kite0, HatCoords *hc, int *coords)
|
||||
{
|
||||
pspoint p[4];
|
||||
psbbox *bbox = (psbbox *)vctx;
|
||||
pspoint p;
|
||||
size_t i;
|
||||
|
||||
p[0] = pscoords(k.centre);
|
||||
p[1] = pscoords(k.left);
|
||||
p[2] = pscoords(k.outer);
|
||||
p[3] = pscoords(k.right);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
psbbox_add(bbox, p[i]);
|
||||
for (i = 0; i < 14; i++) {
|
||||
p.x = coords[2*i] * 1.5;
|
||||
p.y = coords[2*i+1] * sqrt(0.75);
|
||||
psbbox_add(bbox, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_kite(Kite k, HatCoords *hc)
|
||||
static void draw_hat(void *vctx, Kite kite0, HatCoords *hc, int *coords)
|
||||
{
|
||||
pspoint p[4];
|
||||
pspoint p;
|
||||
size_t i;
|
||||
|
||||
p[0] = pscoords(k.centre);
|
||||
p[1] = pscoords(k.left);
|
||||
p[2] = pscoords(k.outer);
|
||||
p[3] = pscoords(k.right);
|
||||
const char *colour;
|
||||
|
||||
printf("newpath");
|
||||
for (i = 0; i < 4; i++)
|
||||
printf(" %f %f %s", p[i].x, p[i].y, i ? "lineto" : "moveto");
|
||||
for (i = 0; i < 14; i++) {
|
||||
p.x = coords[2*i] * 1.5;
|
||||
p.y = coords[2*i+1] * sqrt(0.75);
|
||||
printf(" %f %f %s", p.x, p.y, i ? "lineto" : "moveto");
|
||||
}
|
||||
printf(" closepath gsave");
|
||||
if (hc) {
|
||||
const char *colour = "0 setgray";
|
||||
if (hc->c[2].type == TT_H) {
|
||||
colour = (hc->c[1].index == 3 ? "0 0.5 0.8 setrgbcolor" :
|
||||
"0.6 0.8 1 setrgbcolor");
|
||||
} else if (hc->c[2].type == TT_F) {
|
||||
colour = "0.7 setgray";
|
||||
} else {
|
||||
colour = "1 setgray";
|
||||
}
|
||||
printf(" %s fill grestore\n", colour);
|
||||
if (hc->c[2].type == TT_H) {
|
||||
colour = (hc->c[1].index == 3 ? "0 0.5 0.8 setrgbcolor" :
|
||||
"0.6 0.8 1 setrgbcolor");
|
||||
} else if (hc->c[2].type == TT_F) {
|
||||
colour = "0.7 setgray";
|
||||
} else {
|
||||
colour = "1 setgray";
|
||||
}
|
||||
}
|
||||
|
||||
static void stroke_kite(Kite k, HatCoords *hc)
|
||||
{
|
||||
pspoint p[4];
|
||||
size_t i;
|
||||
|
||||
p[0] = pscoords(k.centre);
|
||||
p[1] = pscoords(k.left);
|
||||
p[2] = pscoords(k.outer);
|
||||
p[3] = pscoords(k.right);
|
||||
|
||||
printf("newpath");
|
||||
for (i = 0; i < 4; i++)
|
||||
printf(" %f %f %s", p[i].x, p[i].y, i ? "lineto" : "moveto");
|
||||
printf(" closepath");
|
||||
printf(" %s fill grestore", colour);
|
||||
printf(" stroke\n");
|
||||
|
||||
if (hc->c[2].type == TT_H && hc->c[1].index == 3) {
|
||||
pspoint t = p[1]; p[1] = p[3]; p[3] = t;
|
||||
}
|
||||
#define LINE(a,b) printf("gsave newpath %f %f moveto %f %f lineto thick " \
|
||||
"stroke grestore\n", p[a].x, p[a].y, p[b].x, p[b].y)
|
||||
switch (hc->c[0].index) {
|
||||
case 0: LINE(1, 2); LINE(2, 3); LINE(3, 0); break;
|
||||
case 1: LINE(0, 1); break;
|
||||
case 2: LINE(0, 1); break;
|
||||
case 3: LINE(2, 3); LINE(3, 0); break;
|
||||
case 4: LINE(0, 1); LINE(1, 2); break;
|
||||
case 6: LINE(1, 2); LINE(2, 3); break;
|
||||
case 7: LINE(1, 2); LINE(2, 3); LINE(3, 0); break;
|
||||
}
|
||||
#undef LINE
|
||||
}
|
||||
|
||||
static void trailer(void)
|
||||
@ -1366,12 +1344,14 @@ int main(int argc, char **argv)
|
||||
|
||||
first_kite(s, w, h);
|
||||
coords[s->curr_index] = initial_coords(ctx);
|
||||
bbox_add_kite(*s->curr, bbox);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
bbox_add_hat, bbox);
|
||||
while (next_kite(s)) {
|
||||
hc_free(coords[s->curr_index]);
|
||||
coords[s->curr_index] = step_coords(
|
||||
ctx, coords[s->last_index], s->last_step);
|
||||
bbox_add_kite(*s->curr, bbox);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
bbox_add_hat, bbox);
|
||||
}
|
||||
for (i = 0; i < lenof(coords); i++) {
|
||||
hc_free(coords[i]);
|
||||
@ -1382,26 +1362,14 @@ int main(int argc, char **argv)
|
||||
|
||||
first_kite(s, w, h);
|
||||
coords[s->curr_index] = initial_coords(ctx);
|
||||
fill_kite(*s->curr, coords[s->curr_index]);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
draw_hat, NULL);
|
||||
while (next_kite(s)) {
|
||||
hc_free(coords[s->curr_index]);
|
||||
coords[s->curr_index] = step_coords(
|
||||
ctx, coords[s->last_index], s->last_step);
|
||||
fill_kite(*s->curr, coords[s->curr_index]);
|
||||
}
|
||||
for (i = 0; i < lenof(coords); i++) {
|
||||
hc_free(coords[i]);
|
||||
coords[i] = NULL;
|
||||
}
|
||||
|
||||
first_kite(s, w, h);
|
||||
coords[s->curr_index] = initial_coords(ctx);
|
||||
stroke_kite(*s->curr, coords[s->curr_index]);
|
||||
while (next_kite(s)) {
|
||||
hc_free(coords[s->curr_index]);
|
||||
coords[s->curr_index] = step_coords(
|
||||
ctx, coords[s->last_index], s->last_step);
|
||||
stroke_kite(*s->curr, coords[s->curr_index]);
|
||||
maybe_report_hat(w, h, *s->curr, coords[s->curr_index],
|
||||
draw_hat, NULL);
|
||||
}
|
||||
for (i = 0; i < lenof(coords); i++) {
|
||||
hc_free(coords[i]);
|
||||
|
Reference in New Issue
Block a user