From 20d5b6d5be279652b53d3064470b810a2fa8560a Mon Sep 17 00:00:00 2001 From: "S. Gilles" Date: Sat, 3 Dec 2016 14:38:06 -0500 Subject: [PATCH] Allow dragging nodes --- clav.c | 10 ++-- quiver.c | 104 ++++++++++++++++++++---------------------- ui-sdl.c | 156 +++++++++++++++++++++++++++++++++------------------------------ 3 files changed, 138 insertions(+), 132 deletions(-) diff --git a/clav.c b/clav.c index 0ff2724..badab5b 100644 --- a/clav.c +++ b/clav.c @@ -67,11 +67,7 @@ static int state_transition(struct ui_event *e) int main(int argc, char **argv) { int ret; - uint_fast8_t more_evs = 0; - struct ui_event e = { 0 }; struct quiver q = { 0 }; - size_t v0, vinf, v1, v2, v1b, v2b, v12, v21, v23, v32, v30, v03, v10, - v01; UNUSED(argc); UNUSED(argv); @@ -83,6 +79,9 @@ int main(int argc, char **argv) { /* XXX: rem (this is C2 U_{02} C2) */ + size_t v0, vinf, v1, v2, v1b, v2b, v12, v21, v23, v32, v30, v03, + v10, v01; + quiver_add_vertex(&q, &v0, "0", 1, 0, -170, 0); quiver_add_vertex(&q, &vinf, "\u221e", 2, 0, 170, 0); quiver_add_vertex(&q, &v1, "1", 2, 100, 100, 0); @@ -146,6 +145,9 @@ int main(int argc, char **argv) goto done; } + uint_fast8_t more_evs = 0; + struct ui_event e = { 0 }; + while (state != ST_SHOULD_QUIT) { /* includes framelimiting delay */ if ((ret = ui_finish_frame())) { diff --git a/quiver.c b/quiver.c index b3eb783..af6179e 100644 --- a/quiver.c +++ b/quiver.c @@ -43,11 +43,8 @@ static int gcd(uint_fast8_t x, uint_fast8_t y) static int reduce_fraction(int_fast32_t n, uint_fast32_t d, struct rational *out, const char **out_errstr) { - size_t j = 0; - uint32_t p = 0; - - for (j = 0; j < ((sizeof primes) / (sizeof primes[0])); ++j) { - p = primes[j]; + for (size_t j = 0; j < ((sizeof primes) / (sizeof primes[0])); ++j) { + uint32_t p = primes[j]; if (j && p * 2 > d) { @@ -90,9 +87,6 @@ int quiver_add_to_edge(struct quiver *q, size_t i, size_t j, int_fast8_t a, uint_fast8_t b, const char **out_errstr) { int ret = 0; - struct rational *eij = 0; - struct rational *eji = 0; - uint_fast8_t d = 1; if (!q) { IF_NZ_SET(out_errstr, L("nonexistant quiver")); @@ -107,23 +101,21 @@ int quiver_add_to_edge(struct quiver *q, size_t i, size_t j, int_fast8_t a, return EINVAL; } - eij = &(q->e[i * q->v_len + j]); - eji = &(q->e[j * q->v_len + i]); - d = gcd(q->v[i].fatness, q->v[j].fatness); + struct rational *eij = &(q->e[i * q->v_len + j]); + struct rational *eji = &(q->e[j * q->v_len + i]); + uint_fast8_t d = gcd(q->v[i].fatness, q->v[j].fatness); if ((ret = add_to_fraction(a * q->v[j].fatness, b * d, eij, out_errstr))) { - goto done; + return ret; } if ((ret = add_to_fraction(-1 * a * q->v[i].fatness, b * d, eji, out_errstr))) { - goto done; + return ret; } -done: - - return ret; + return 0; } /* Add a vertex with a name and weight */ @@ -132,12 +124,7 @@ int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name, char **out_errstr) { void *newmem = 0; - int sv_err = 0; - size_t l = strlen(name); char *newname; - size_t j; - size_t k; - size_t newlen; if (!q) { IF_NZ_SET(out_errstr, L("invalid quiver")); @@ -145,40 +132,54 @@ int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name, return EINVAL; } - if (!(newname = malloc(l + 1))) { - sv_err = errno; - IF_NZ_SET(out_errstr, L("malloc")); + if (!name) { + if (!(newname = malloc(snprintf(0, 0, "%zu", q->v_num) + 1))) { + int sv_err = errno; - return sv_err; - } + IF_NZ_SET(out_errstr, L("malloc")); + + return sv_err; + } + + sprintf(newname, "%zu", q->v_num); + } else { + if (!(newname = malloc(strlen(name) + 1))) { + int sv_err = errno; - strcpy(newname, name); + IF_NZ_SET(out_errstr, L("malloc")); + + return sv_err; + } + + strcpy(newname, name); + } if (q->v_num >= q->v_len) { - newlen = q->v_len + 8; + size_t newlen = q->v_len + 8; /* XXX: check for overflow here */ if (!(newmem = malloc(newlen * newlen * sizeof (*q->e)))) { - sv_err = errno; + int sv_err = errno; + IF_NZ_SET(out_errstr, L("too many vertices")); return sv_err; } - for (j = 0; j < q->v_num; ++j) { - for (k = 0; k < q->v_num; ++k) { + for (size_t j = 0; j < q->v_num; ++j) { + for (size_t k = 0; k < q->v_num; ++k) { ((struct rational *) newmem)[j * newlen + k] = q->e[j * q->v_len + k]; } - for (k = q->v_num; k < newlen; ++k) { + for (size_t k = q->v_num; k < newlen; ++k) { ((struct rational *) newmem)[j * newlen + k] = (struct rational) { .p = 0, .q = 1 }; } } - for (j = q->v_num; j < newlen; ++j) { - for (k = 0; k < newlen; ++k) { + for (size_t j = q->v_num; j < newlen; ++j) { + for (size_t k = 0; k < newlen; ++k) { ((struct rational *) newmem)[j * newlen + k] = (struct rational) { .p = 0, .q = 1 }; } @@ -187,7 +188,8 @@ int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name, q->e = newmem; if (!(newmem = (realloc(q->v, newlen * sizeof (*q->v))))) { - sv_err = errno; + int sv_err = errno; + IF_NZ_SET(out_errstr, L("too many vertices")); return sv_err; @@ -197,7 +199,7 @@ int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name, q->v_len = newlen; } - for (k = 0; k <= q->v_num; ++k) { + for (size_t k = 0; k <= q->v_num; ++k) { q->e[k * q->v_len + q->v_num] = (struct rational) { .p = 0, .q = 1 }; q->e[q->v_num * q->v_len + k] = (struct rational) { .p = 0, .q = @@ -215,11 +217,6 @@ int quiver_add_vertex(struct quiver *q, size_t *out_i, const char *name, /* Mutate the quiver at vertex k */ int quiver_mutate(struct quiver *q, size_t k, const char **out_errstr) { - size_t i = 0; - size_t j = 0; - struct rational *eik; - struct rational *eij; - struct rational *ekj; int ret = 0; if (!q) { @@ -229,21 +226,21 @@ int quiver_mutate(struct quiver *q, size_t k, const char **out_errstr) } /* Step one: complete all triangles */ - for (i = 0; i < q->v_num; ++i) { + for (size_t i = 0; i < q->v_num; ++i) { if (i == k) { continue; } - eik = &(q->e[i * q->v_len + k]); + struct rational *eik = &(q->e[i * q->v_len + k]); - for (j = 0; j < q->v_num; ++j) { + for (size_t j = 0; j < q->v_num; ++j) { if (j == k || j == i) { continue; } - eij = &(q->e[i * q->v_len + j]); - ekj = &(q->e[k * q->v_len + j]); + struct rational *eij = &(q->e[i * q->v_len + j]); + struct rational *ekj = &(q->e[k * q->v_len + j]); if (eik->p * ekj->p <= 0) { continue; @@ -252,24 +249,23 @@ int quiver_mutate(struct quiver *q, size_t k, const char **out_errstr) if ((ret = add_to_fraction(abs(eik->p) * ekj->p, eik->q * ekj->q, eij, out_errstr))) { - goto done; + return ret; } } } /* Step two: invert all edges that touch k */ - for (i = 0; i < q->v_num; ++i) { + for (size_t i = 0; i < q->v_num; ++i) { if (i == k) { continue; } - eik = &(q->e[i * q->v_len + k]); - eik->p = -eik->p; - eik = &(q->e[k * q->v_len + i]); + struct rational *eik = &(q->e[i * q->v_len + k]); + struct rational *eki = &(q->e[k * q->v_len + i]); + eik->p = -eik->p; + eki->p = -eki->p; } -done: - - return ret; + return 0; } diff --git a/ui-sdl.c b/ui-sdl.c index 7c92515..99aaaee 100644 --- a/ui-sdl.c +++ b/ui-sdl.c @@ -105,11 +105,14 @@ static int arrow_length = 7; static double arrow_angle = 6.5 * M_PI / 8.0; /* If we're interacting with a vertex, which one */ -/* static size_t selected_vertex = (size_t) -1; */ +static size_t selected_vertex = (size_t) -1; + /* If we're interacting with an edge, the i */ -/* static size_t selected_edge_i */ +static size_t selected_edge_i = (size_t) -1; + /* If we're interacting with an edge, the j */ -/* static size_t selected_edge_j */ +static size_t selected_edge_j = (size_t) -1; + /* x-coordinate of last mouse position */ static int last_mouse_x = -1; @@ -125,14 +128,12 @@ static double precalc_coss[TRIG_PRECALC_NUM]; /* Precalculate sines and cosines */ static void precalc_trig(void) { - size_t j = 0; - double theta; - precalc_coss[0] = 0.0; precalc_sins[0] = 1.0; - for (j = 1; j < TRIG_PRECALC_NUM - 1; ++j) { - theta = (M_PI * j) / (2 * (TRIG_PRECALC_NUM - 1)); + for (size_t j = 1; j < TRIG_PRECALC_NUM - 1; ++j) { + double theta = (M_PI * j) / (2 * (TRIG_PRECALC_NUM - 1)); + precalc_sins[j] = sin(theta); precalc_coss[j] = cos(theta); } @@ -206,12 +207,8 @@ done: /* Render vertex names as textures */ static int render_vertex_names(void) { - size_t j; - int sv_err = 0; - SDL_Surface *surf = 0; - if (vertex_names) { - for (j = 0; j < vertex_names_len; ++j) { + for (size_t j = 0; j < vertex_names_len; ++j) { SDL_DestroyTexture(vertex_names[j]); vertex_names[j] = 0; } @@ -219,7 +216,8 @@ static int render_vertex_names(void) if (!(vertex_names = realloc(vertex_names, q->v_num * sizeof(*vertex_names)))) { - sv_err = errno; + int sv_err = errno; + perror(L("realloc()")); vertex_names_len = 0; @@ -228,11 +226,13 @@ static int render_vertex_names(void) vertex_names_len = q->v_num; - for (j = 0; j < vertex_names_len; ++j) { + for (size_t j = 0; j < vertex_names_len; ++j) { vertex_names[j] = 0; } - for (j = 0; j < vertex_names_len; ++j) { + for (size_t j = 0; j < vertex_names_len; ++j) { + SDL_Surface *surf = 0; + if (!(surf = TTF_RenderUTF8_Shaded(normal_font, q->v[j].name, color_font, color_v))) { fprintf(stderr, @@ -261,25 +261,18 @@ static int render_vertex_names(void) } /* Convert `internal coordinates' to pixel coordinates */ -static int internal_to_pixel_xy(int in_x, int in_y, int *out_x, int *out_y) +static void internal_to_pixel_xy(int in_x, int in_y, int *out_x, int *out_y) { *out_x = in_x + offset_x; *out_y = in_y + offset_y; - - return 0; } /* Convert pixel coordinates to `internal coordinates' */ - -/* - static int pixel_to_internal_xy(int in_x, int in_y, float *out_x, float *out_y) - { - * out_x = (in_x - 0.5f - offset_x) / ic_to_pix; - * out_y = (in_y - 0.5f - offset_y) / ic_to_pix; - - return 0; - } - */ +static void pixel_to_internal_xy(int in_x, int in_y, int *out_x, int *out_y) +{ + *out_x = in_x - offset_x; + *out_y = in_y - offset_y; +} /* Get information about the window */ static void react_to_window_resized(void) @@ -315,10 +308,9 @@ static void eq_pop(struct ui_event *out) /* Push into queue */ static int eq_push(struct ui_event *in) { - void *newmem; - int sv_err; - if (((eq_tail + 1) % eq_len) == eq_head) { + void *newmem; + if ((eq_len * sizeof *in) >= ((size_t) -1) / 2) { fprintf(stderr, L( "eq_push: Impossibly large buffer\n")); @@ -328,7 +320,8 @@ static int eq_push(struct ui_event *in) if (!(newmem = realloc(eq_buf, (eq_len * 2) * sizeof *eq_buf))) { - sv_err = errno; + int sv_err = errno; + perror(L("realloc")); return sv_err; @@ -456,17 +449,6 @@ int ui_teardown(void) int ui_start_frame(void) { int ret = 0; - struct vertex *v; - struct rational *eij; - struct rational *eji; - int cx = 0; - int cy = 0; - int cx2 = 0; - int cy2 = 0; - double theta = 0; - int d = 0; - size_t j = 0; - size_t i = 0; int rho = 0; SDL_Rect r = { 0 }; Uint32 dummy_format; @@ -481,19 +463,23 @@ int ui_start_frame(void) color_bg.a); SDL_RenderClear(sdl_renderer); - for (j = 0; j < q->v_num; ++j) { - for (i = 0; i < j; ++i) { + for (size_t j = 0; j < q->v_num; ++j) { + for (size_t i = 0; i < j; ++i) { /* First, determine if we're looking at a half-edge or a full-edge */ - eij = &(q->e[i * q->v_len + j]); - eji = &(q->e[j * q->v_len + i]); + int d = gcd(q->v[i].fatness, q->v[j].fatness); + struct rational *eij = &(q->e[i * q->v_len + j]); + struct rational *eji = &(q->e[j * q->v_len + i]); + int cx = 0; + int cy = 0; + int cx2 = 0; + int cy2 = 0; + double theta = 0.0; if (!eij->p && !eji->p) { continue; } - d = gcd(q->v[i].fatness, q->v[j].fatness); - /* This is the (eij)/dj = -(eji)/di condition */ if (eij->p * q->v[i].fatness * eji->q != -eji->p * q->v[j].fatness * eij->q) { @@ -531,20 +517,13 @@ int ui_start_frame(void) goto done; } - if ((ret = internal_to_pixel_xy(q->v[i].x, q->v[i].y, - &cx, &cy))) { - goto done; - } - - if ((ret = internal_to_pixel_xy(q->v[j].x, q->v[j].y, - &cx2, &cy2))) { - goto done; - } + internal_to_pixel_xy(q->v[i].x, q->v[i].y, &cx, &cy); + internal_to_pixel_xy(q->v[j].x, q->v[j].y, &cx2, &cy2); if ((ret = SDL_RenderDrawLine(sdl_renderer, cx, cy, cx2, cy2))) { fprintf(stderr, L("SDL_RenderDrawLine(): %s\n"), - SDL_GetError()); + SDL_GetError()); goto done; } @@ -566,7 +545,7 @@ int ui_start_frame(void) if ((ret = SDL_RenderDrawLine(sdl_renderer, cx, cy, cx2, cy2))) { fprintf(stderr, L("SDL_RenderDrawLine(): %s\n"), - SDL_GetError()); + SDL_GetError()); goto done; } @@ -578,18 +557,18 @@ int ui_start_frame(void) arrow_angle)))) { fprintf(stderr, L("SDL_RenderDrawLine(): %s\n"), - SDL_GetError()); + SDL_GetError()); goto done; } } } - for (j = 0; j < q->v_num; ++j) { - v = &(q->v[j]); + for (size_t j = 0; j < q->v_num; ++j) { + struct vertex *v = &(q->v[j]); + int cx = 0; + int cy = 0; - if ((ret = internal_to_pixel_xy(v->x, v->y, &cx, &cy))) { - goto done; - } + internal_to_pixel_xy(v->x, v->y, &cx, &cy); /* Central square */ SDL_SetRenderDrawBlendMode(sdl_renderer, SDL_BLENDMODE_NONE); @@ -659,11 +638,10 @@ done: /* Draw a frame, possibly sleeping for framelimit */ int ui_finish_frame(void) { + int ret = 0; struct ui_event ui_e = { 0 }; SDL_Event sdl_e = { 0 }; - Uint32 elapsed_time = 0; Uint32 now = 0; - int ret = 0; SDL_RenderPresent(sdl_renderer); @@ -706,16 +684,46 @@ int ui_finish_frame(void) case SDL_MOUSEMOTION: if (sdl_e.motion.state & SDL_BUTTON_LMASK) { + int x = sdl_e.motion.x; + int y = sdl_e.motion.y; + if (last_mouse_x >= 0 && last_mouse_y >= 0) { - offset_x += (sdl_e.motion.x - - last_mouse_x); - offset_y += (sdl_e.motion.y - - last_mouse_y); + if (selected_vertex != (size_t) -1) { + q->v[selected_vertex].x += (x - + last_mouse_x); + q->v[selected_vertex].y += (y - + last_mouse_y); + } else { + offset_x += (x - last_mouse_x); + offset_y += (y - last_mouse_y); + } } last_mouse_x = sdl_e.motion.x; last_mouse_y = sdl_e.motion.y; + } else { + int x = 0; + int y = 0; + + pixel_to_internal_xy(sdl_e.motion.x, + sdl_e.motion.y, &x, &y); + selected_vertex = (size_t) -1; + selected_edge_i = (size_t) -1; + selected_edge_j = (size_t) -1; + + for (size_t j = 0; j < q->v_num; ++j) { + struct vertex *v = &(q->v[j]); + int r = v->fatness * node_radius; + + if (x > v->x - r && + x < v->x + r && + y > v->y - r && + y < v->y + r) { + selected_vertex = j; + break; + } + } } break; @@ -739,7 +747,7 @@ int ui_finish_frame(void) now = SDL_GetTicks(); if (frame_start_ticks < now) { - elapsed_time = now - frame_start_ticks; + Uint32 elapsed_time = now - frame_start_ticks; if (elapsed_time < TICKS_PER_FRAME) { SDL_Delay(TICKS_PER_FRAME - elapsed_time); -- 2.11.4.GIT