#include "web_svg.h" #include "board.h" #include "comp.h" #include #include #include #include #define NUM_SECTORS 20 #define SECTOR_WIDTH 18.0 #define C_BLACK "#272b2c" #define C_WHITE "#fbe3ba" #define C_RED "#f6302f" #define C_GREEN "#22912d" #define C_WIRE "#909ca0" #define C_WIRE_INNER "#d8e6ec" struct elem { char *ns, *name, *content; int n_attrs, size_attrs; char **attr_names, **attr_vals; }; struct elem *elem_init(char *ns, char *name, int size_attrs) { struct elem *e = malloc(sizeof(*e)); e->ns = ns ? strdup(ns) : NULL; e->name = strdup(name); e->n_attrs = 0; e->size_attrs = size_attrs; e->attr_names = malloc(size_attrs * sizeof(*(e->attr_names))); e->attr_vals = malloc(size_attrs * sizeof(*(e->attr_vals))); e->content = NULL; return e; } static inline struct elem *svg_elem_init(char *name, int size_attrs) { return elem_init("http://www.w3.org/2000/svg", name, size_attrs); } void elem_free(struct elem *e) { for(int i = 0; i < e->n_attrs; ++i) { free(e->attr_names[i]); free(e->attr_vals[i]); } free(e->content); free(e->attr_names); free(e->attr_vals); free(e->name); free(e); } void elem_add_attr(struct elem *e, char *name, char *val) { if (e->n_attrs == e->size_attrs) { e->size_attrs *= 2; e->attr_names = realloc(e->attr_names, e->size_attrs * sizeof(*(e->attr_names))); e->attr_vals = realloc(e->attr_vals, e->size_attrs * sizeof(*(e->attr_vals))); } e->attr_names[e->n_attrs] = strdup(name); e->attr_vals[e->n_attrs++] = strdup(val); } void elem_add_attr_double(struct elem *e, char *name, double val) { char str[512]; sprintf(str, "%f", val); elem_add_attr(e, name, str); } // draws a ring if angles are equal struct elem *gen_arc(double a1, double a2, double r1, double r2, char *col) { struct ccoords cc1 = pol_to_cart((struct pcoords){ .a = (a1 == a2 ? 1 : a2), .r = r1 }); struct ccoords cc2 = pol_to_cart((struct pcoords){ .a = (a1 == a2 ? 0 : a1), .r = r1 }); struct ccoords cc3 = pol_to_cart((struct pcoords){ .a = (a1 == a2 ? 0 : a1), .r = r2 }); struct ccoords cc4 = pol_to_cart((struct pcoords){ .a = (a1 == a2 ? 1 : a2), .r = r2 }); struct elem *e = svg_elem_init("path", 2); elem_add_attr(e, "fill", col); char buf[512]; int buflen = 0; buflen += sprintf(buf + buflen, "M%f %f", cc1.x, cc1.y); buflen += sprintf(buf + buflen, "A%f %f 0 0 0 %f %f", r1, r1, cc2.x, cc2.y); if (a1 == a2) buflen += sprintf(buf + buflen, "A%f %f 0 1 0 %f %f", r1, r1, cc1.x, cc1.y); buflen += sprintf(buf + buflen, "L%f %f", cc3.x, cc3.y); buflen += sprintf(buf + buflen, "A%f %f 0 0 1 %f %f", r2, r2, cc4.x, cc4.y); if (a1 == a2) buflen += sprintf(buf + buflen, "A%f %f 0 1 1 %f %f", r2, r2, cc3.x, cc3.y); buf[buflen++] = 'Z'; buf[buflen++] = 0; elem_add_attr(e, "d", buf); return e; } struct elem *gen_segment(double a, double r1, double r2, char *col) { return gen_arc(a - SECTOR_WIDTH/2, a + SECTOR_WIDTH/2, r1, r2, col); } struct elem *gen_ring(double r, double w, char *col) { return gen_arc(0, 0, r - w/2, r + w/2, col); } struct elem *gen_circle(double r, char *col) { struct elem *e = svg_elem_init("circle", 2); elem_add_attr(e, "fill", col); elem_add_attr_double(e, "r", r); return e; } struct elem *gen_line(double a, double r1, double r2, double w, char *col) { struct ccoords cc1 = pol_to_cart((struct pcoords){ .a = a, .r = r1 }); struct ccoords cc2 = pol_to_cart((struct pcoords){ .a = a, .r = r2 }); struct elem *e = svg_elem_init("line", 6); elem_add_attr(e, "stroke", col); elem_add_attr_double(e, "x1", cc1.x); elem_add_attr_double(e, "y1", cc1.y); elem_add_attr_double(e, "x2", cc2.x); elem_add_attr_double(e, "y2", cc2.y); elem_add_attr_double(e, "stroke-width", w); return e; } int draw_spider(int elemc, struct elem **elemv) { for (int i = 5; i > 1; --i) { elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); } for (int i = 0; i < NUM_SECTORS; ++i) { double a = 90 - i*SECTOR_WIDTH - SECTOR_WIDTH/2; if (a < 0) a += 360; elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, WIRE_WIDTH, C_WIRE); elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, WIRE_WIDTH/2, C_WIRE_INNER); } for (int i = 1; i >= 0; --i) { elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); } return elemc; } int draw_numbers(int elemc, struct elem **elemv) { elemv[elemc++] = gen_ring(DIAMETER/2 - WIRE_WIDTH*4, WIRE_WIDTH, "#ddd"); int r = DIAMETER/2 - 33/2; for (int i = 0; i < 20; ++i) { struct elem *e = elemv[elemc++] = svg_elem_init("text", 5); elem_add_attr(e, "font-size", "33"); elem_add_attr(e, "fill", "#fff"); elem_add_attr(e, "text-anchor", "middle"); elem_add_attr(e, "dominant-baseline", "central"); char buf[512]; double a = 90 - i*SECTOR_WIDTH; if (a < 0) a += 360; struct ccoords cc = pol_to_cart((struct pcoords){ .a = a, .r = r }); sprintf(buf, "scale(1 -1) translate(%f %f) rotate(%f)", cc.x, -cc.y, a <= 180 ? 90 -a : 270 -a); elem_add_attr(e, "transform", buf); e->content = malloc(3); sprintf(e->content, "%d", SECTORS[i]); } return elemc; } void append_elemv(char *sel, int elemc, struct elem **elemv) { EM_ASM({elemAppendElemv($0, $1, $2, $3, $4, $5, $6, $7, $8)}, sel, elemc, elemv, offsetof(struct elem, ns), offsetof(struct elem, name), offsetof(struct elem, content), offsetof(struct elem, n_attrs), offsetof(struct elem, attr_names), offsetof(struct elem, attr_vals)); } void svg_draw_board() { struct elem **elemv = malloc(200 * sizeof(*elemv)); int elemc = 0; elemv[elemc++] = gen_circle(DIAMETER/2, C_BLACK); for (int i = 5; i > 1; --i) { for (int j = 0; j < NUM_SECTORS; ++j) { double a = 90 - j*SECTOR_WIDTH; if (a < 0) a += 360; elemv[elemc++] = gen_segment(a, OUTER_DISTS[i-1], OUTER_DISTS[i], i%2 ? (j%2 ? C_GREEN : C_RED) : (j%2 ? C_WHITE : C_BLACK)); } } elemv[elemc++] = gen_circle(OUTER_DISTS[1], C_GREEN); elemv[elemc++] = gen_circle(OUTER_DISTS[0], C_RED); elemc = draw_spider(elemc, elemv); elemc = draw_numbers(elemc, elemv); append_elemv("#dartboard .base", elemc, elemv); for (int i = 0; i < elemc; ++i) free(elemv[i]); free(elemv); } void svg_draw_point(double x, double y) { struct elem *e = gen_circle(8, "#33f"); elem_add_attr(e, "stroke", "#ff0"); elem_add_attr(e, "stroke-width", "2"); elem_add_attr_double(e, "cx", x); elem_add_attr_double(e, "cy", y); append_elemv("#dartboard .overlay", 1, &e); elem_free(e); } void svg_clear_points() { EM_ASM({elemSetContent($0, $1)}, "#dartboard .overlay", NULL); }