From 87db81dcfe9503684ad6f71d13a4ae6bac7914ea Mon Sep 17 00:00:00 2001 From: Antonio Carzaniga Date: Wed, 1 Dec 2021 20:18:19 +0100 Subject: [PATCH] modularization of c_index, basic balls data. --- Makefile | 7 +- balls.c | 270 +----------------------------------------------------- balls.h | 27 ++++++ c_index.c | 170 ++++++++++++++++++++++++++++++++++ c_index.h | 11 +++ 5 files changed, 217 insertions(+), 268 deletions(-) create mode 100644 balls.h create mode 100644 c_index.c create mode 100644 c_index.h diff --git a/Makefile b/Makefile index 24b4dc3..bbb4902 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ CFLAGS=-Wall -g -O2 $(PROFILING_CFLAGS) $(GTK_CFLAGS) LIBS=$(GTK_LIBS) -lm PROGS=balls +OBJS=balls.o c_index.o .PHONY: default default: all @@ -19,9 +20,9 @@ run: balls .PHONY: all all: $(PROGS) -balls: balls.o - $(CC) $(CFLAGS) $(LDFLAGS) $< $(LIBS) -o $@ +balls: $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ .PHONY: clean clean: - rm -f *.o $(PROGS) + rm -f *.o $(PROGS) $(OBJS) diff --git a/balls.c b/balls.c index ead451e..343a86f 100644 --- a/balls.c +++ b/balls.c @@ -10,21 +10,8 @@ #define DEFAULT_WIDTH 800 #define DEFAULT_HEIGHT 800 -struct ball_face; - -struct ball { - double x; - double y; - unsigned int radius; - - double v_x; - double v_y; - - double angle; - double v_angle; - - struct ball_face * face; -}; +#include "balls.h" +#include "c_index.h" double delta = 0.01; /* seconds */ @@ -78,7 +65,7 @@ void balls_init_state () { } } -void ball_collision (struct ball * p, struct ball * q) { +void ball_elastic_collision (struct ball * p, struct ball * q) { double dx = q->x - p->x; double dy = q->y - p->y; double d2 = dx*dx + dy*dy; @@ -103,71 +90,6 @@ void ball_collision (struct ball * p, struct ball * q) { } } -#if 0 -static void tangential_friction1(double u, double p, double r, double * v, double * q) { - static const double a = 0.0; - - /* - * 2 2 2 2 2 2 - * sqrt((6 - 2 a ) u + 4 a p r u + (3 - 2 a ) p r ) + a u - a p r - * v = ----------------------------------------------------------------- - * 3 - * - * 2 2 2 2 2 2 - * sqrt((6 - 2 a ) u + 4 a p r u + (3 - 2 a ) p r ) - 2 a u + 2 a p r - * q = --------------------------------------------------------------------- - * 3 r - */ - double a2 = a*a; - double u2 = u*u; - double p2 = p*p; - double r2 = r*r; - double sr = sqrt((6 - 2*a2)*u2 + 4*a2*p*r*u + (3 - 2*a2)*p2*r2); - *v = (sr + a*u - a*p*r)/3; - *q = (sr - 2*a*u + 2*a*p*r)/(3*r); -} - -static void tangential_friction2(double u, double p, double r, double * v, double * q) { - static const double a = 1.0; - - /* - * 2 2 2 2 2 2 - * sqrt((6 - 2 a ) u + 4 a p r u + (3 - 2 a ) p r ) + a u + a p r - * v = ----------------------------------------------------------------- - * 3 - * - * 2 2 2 2 2 2 - * sqrt((6 - 2 a ) u + 4 a p r u + (3 - 2 a ) p r ) - 2 a u - 2 a p r - * q = --------------------------------------------------------------------- - * 3 r - */ - double a2 = a*a; - double u2 = u*u; - double p2 = p*p; - double r2 = r*r; - double sr = sqrt((6 - 2*a2)*u2 + 4*a2*p*r*u + (3 - 2*a2)*p2*r2); - *v = (sr + a*u + a*p*r)/3; - *q = (sr - 2*a*u - 2*a*p*r)/(3*r); -} - -static void tangential_friction3(double u, double p, double r, double * v_ptr, double * q_ptr) { - static const double a = 0.9; - double v, q; - v = (1-a)*u + a*p*r; - /* 2 2 2 2 2 2 - * sqrt((4 a - 2 a ) u + (4 a - 4 a) p r u + (1 - 2 a ) p r ) - * q = ------------------------------------------------------------- - * r - */ - q = sqrt(2*a*(2 - a)*u*u + 4*a*(a - 1)*p*r*u + (1 - 2*a*a)*p*p*r*r)/r; - if (p*r > v) - q = -q; - - *v_ptr = v; - *q_ptr = q; -} -#endif - void ball_update_state (struct ball * p) { p->x += delta*p->v_x + delta*delta*g_x/2.0; p->v_x += delta*g_x; @@ -179,19 +101,11 @@ void ball_update_state (struct ball * p) { if (p->v_x > 0) { p->x -= p->x + p->radius - width; p->v_x = -p->v_x; -#if 0 - /* tangential friction */ - tangential_friction(p->v_y, -p->v_angle, p->radius, &(p->v_y), &(p->v_angle)); -#endif } } else if (p->x < p->radius) { /* left wall */ if (p->v_x < 0) { p->x += p->radius - p->x; p->v_x = -p->v_x; -#if 0 - /* tangential friction */ - tangential_friction(p->v_y, p->v_angle, p->radius, &(p->v_y), &(p->v_angle)); -#endif } } @@ -199,20 +113,11 @@ void ball_update_state (struct ball * p) { if (p->v_y > 0) { p->y -= p->y + p->radius - height; p->v_y = -p->v_y; -#if 0 - /* tangential friction */ - tangential_friction3(p->v_x, p->v_angle, p->radius, &(p->v_x), &(p->v_angle)); -#endif } } else if (p->y < p->radius) { /* top wall */ if (p->v_y < 0) { p->y += p->radius - p->y; p->v_y = -p->v_y; -#if 0 - /* tangential friction */ - tangential_friction(p->v_x, -p->v_angle, p->radius, &(p->v_x), &(p->v_angle)); - p->v_angle = -p->v_angle; -#endif } } p->angle += delta*p->v_angle; @@ -241,183 +146,18 @@ void movement_and_borders () { ball_update_state(balls + i); } -/* Collision check with index -*/ -struct rectangle { - double min_x; /* left */ - double min_y; /* bottom */ - double max_x; /* right */ - double max_y; /* top */ -}; - -struct bt_node { - struct ball * ball; - struct rectangle r; - struct bt_node * left; - struct bt_node * right; -}; - -struct bt_node * c_index = 0; - -static struct bt_node * c_index_init_node(struct bt_node * n, struct ball * b) { - n->ball = b; - n->r.min_x = b->x - b->radius; - n->r.min_y = b->y - b->radius; - n->r.max_x = b->x + b->radius; - n->r.max_y = b->y + b->radius; - n->left = 0; - n->right = 0; - return n; -} - -static void c_index_add_ball(struct bt_node * n, const struct ball * b) { - if (n->r.min_x > b->x - b->radius) - n->r.min_x = b->x - b->radius; - if (n->r.min_y > b->y - b->radius) - n->r.min_y = b->y - b->radius; - if (n->r.max_x < b->x + b->radius) - n->r.max_x = b->x + b->radius; - if (n->r.max_y < b->y + b->radius) - n->r.max_y = b->y + b->radius; -} - -static void c_index_insert(struct bt_node * t, struct bt_node * n, struct ball * b) { - double w = width; - double h = height; - double ref_x = 0.0; - double ref_y = 0.0; - c_index_init_node(n, b); - for (;;) { - c_index_add_ball(t, b); - if (w > h) { /* horizontal split */ - if (b->x <= t->ball->x) { - if (t->left) { - w = t->ball->x - ref_x; - t = t->left; - } else { - t->left = n; - return; - } - } else { - if (t->right) { - w -= t->ball->x - ref_x; - ref_x = t->ball->x; - t = t->right; - } else { - t->right = n; - return; - } - } - } else { /* vertical split */ - if (b->y <= t->ball->y) { - if (t->left) { - h = t->ball->y - ref_y; - t = t->left; - } else { - t->left = n; - return; - } - } else { - if (t->right) { - h -= t->ball->y - ref_y; - ref_y = t->ball->y; - t = t->right; - } else { - t->right = n; - return; - } - } - } - } -} - -void c_index_build() { - c_index_init_node(c_index, balls); - for(int i = 1; i < n_balls; ++i) - c_index_insert(c_index, c_index + i, balls + i); -} - -struct bt_node ** c_index_stack = 0; -unsigned int c_index_stack_top = 0; - -static void c_index_stack_clear() { - c_index_stack_top = 0; -} - -static void c_index_stack_push(struct bt_node * n) { - c_index_stack[c_index_stack_top++] = n; -} - -static struct bt_node * c_index_stack_pop() { - if (c_index_stack_top > 0) - return c_index_stack[--c_index_stack_top]; - else - return 0; -} - -static int c_index_ball_in_rectangle(const struct bt_node * n, const struct ball * b) { - return n->r.min_x <= b->x + b->radius - && n->r.max_x >= b->x - b->radius - && n->r.min_y <= b->y + b->radius - && n->r.max_y >= b->y - b->radius; -} - -static int c_index_must_check(const struct bt_node * n, const struct ball * b) { - return n != 0 && n->ball < b && c_index_ball_in_rectangle(n, b); -} - -void c_index_check_collisions() { - for(struct ball * b = balls + 1; b < balls + n_balls; ++b) { - c_index_stack_clear(); - struct bt_node * n = c_index; - do { - ball_collision(n->ball, b); - if (c_index_must_check(n->left, b)) { - if (c_index_must_check(n->right, b)) - c_index_stack_push(n->right); - n = n->left; - } else if (c_index_must_check(n->right, b)) { - n = n->right; - } else { - n = c_index_stack_pop(); - } - } while (n); - } -} - -int c_index_init() { - if (!c_index) - c_index = malloc(sizeof(struct bt_node) * n_balls); - if (!c_index) - return 0; - if (!c_index_stack) - c_index_stack = malloc(sizeof(struct bt_node *) * n_balls); - if (!c_index_stack) - return 0; - return 1; -} - -void c_index_destroy() { - if (c_index) - free(c_index); - if (c_index_stack) - free(c_index_stack); - c_index = 0; - c_index_stack = 0; -} - /* Trivial collision check */ void check_collisions_simple () { for(int i = 0; i < n_balls; ++i) for(int j = i + 1; j < n_balls; ++j) - ball_collision(balls + i, balls + j); + ball_elastic_collision(balls + i, balls + j); } void check_collisions_with_index () { c_index_build(); - c_index_check_collisions(); + c_index_check_collisions(ball_elastic_collision); } void (*check_collisions)() = 0; diff --git a/balls.h b/balls.h new file mode 100644 index 0000000..14f2ad6 --- /dev/null +++ b/balls.h @@ -0,0 +1,27 @@ +#ifndef BALLS_H_INCLUDED +#define BALLS_H_INCLUDED + +struct ball_face; + +struct ball { + double x; + double y; + unsigned int radius; + + double v_x; + double v_y; + + double angle; + double v_angle; + + struct ball_face * face; +}; + +extern unsigned int width; +extern unsigned int height; + +extern struct ball * balls; +extern unsigned int n_balls; + + +#endif diff --git a/c_index.c b/c_index.c new file mode 100644 index 0000000..5831960 --- /dev/null +++ b/c_index.c @@ -0,0 +1,170 @@ +#include + +#include "balls.h" +#include "c_index.h" + +/* Collision check with index +*/ +struct rectangle { + double min_x; /* left */ + double min_y; /* bottom */ + double max_x; /* right */ + double max_y; /* top */ +}; + +struct bt_node { + struct ball * ball; + struct rectangle r; + struct bt_node * left; + struct bt_node * right; +}; + +struct bt_node * c_index = 0; + +static struct bt_node * c_index_init_node(struct bt_node * n, struct ball * b) { + n->ball = b; + n->r.min_x = b->x - b->radius; + n->r.min_y = b->y - b->radius; + n->r.max_x = b->x + b->radius; + n->r.max_y = b->y + b->radius; + n->left = 0; + n->right = 0; + return n; +} + +static void c_index_add_ball(struct bt_node * n, const struct ball * b) { + if (n->r.min_x > b->x - b->radius) + n->r.min_x = b->x - b->radius; + if (n->r.min_y > b->y - b->radius) + n->r.min_y = b->y - b->radius; + if (n->r.max_x < b->x + b->radius) + n->r.max_x = b->x + b->radius; + if (n->r.max_y < b->y + b->radius) + n->r.max_y = b->y + b->radius; +} + +static void c_index_insert(struct bt_node * t, struct bt_node * n, struct ball * b) { + double w = width; + double h = height; + double ref_x = 0.0; + double ref_y = 0.0; + c_index_init_node(n, b); + for (;;) { + c_index_add_ball(t, b); + if (w > h) { /* horizontal split */ + if (b->x <= t->ball->x) { + if (t->left) { + w = t->ball->x - ref_x; + t = t->left; + } else { + t->left = n; + return; + } + } else { + if (t->right) { + w -= t->ball->x - ref_x; + ref_x = t->ball->x; + t = t->right; + } else { + t->right = n; + return; + } + } + } else { /* vertical split */ + if (b->y <= t->ball->y) { + if (t->left) { + h = t->ball->y - ref_y; + t = t->left; + } else { + t->left = n; + return; + } + } else { + if (t->right) { + h -= t->ball->y - ref_y; + ref_y = t->ball->y; + t = t->right; + } else { + t->right = n; + return; + } + } + } + } +} + +void c_index_build() { + c_index_init_node(c_index, balls); + for(int i = 1; i < n_balls; ++i) + c_index_insert(c_index, c_index + i, balls + i); +} + +struct bt_node ** c_index_stack = 0; +unsigned int c_index_stack_top = 0; + +static void c_index_stack_clear() { + c_index_stack_top = 0; +} + +static void c_index_stack_push(struct bt_node * n) { + c_index_stack[c_index_stack_top++] = n; +} + +static struct bt_node * c_index_stack_pop() { + if (c_index_stack_top > 0) + return c_index_stack[--c_index_stack_top]; + else + return 0; +} + +static int c_index_ball_in_rectangle(const struct bt_node * n, const struct ball * b) { + return n->r.min_x <= b->x + b->radius + && n->r.max_x >= b->x - b->radius + && n->r.min_y <= b->y + b->radius + && n->r.max_y >= b->y - b->radius; +} + +static int c_index_must_check(const struct bt_node * n, const struct ball * b) { + return n != 0 && n->ball < b && c_index_ball_in_rectangle(n, b); +} + +void c_index_check_collisions(void (*collision)(struct ball *, struct ball *)) { + for(struct ball * b = balls + 1; b < balls + n_balls; ++b) { + c_index_stack_clear(); + struct bt_node * n = c_index; + do { + (*collision)(n->ball, b); + if (c_index_must_check(n->left, b)) { + if (c_index_must_check(n->right, b)) + c_index_stack_push(n->right); + n = n->left; + } else if (c_index_must_check(n->right, b)) { + n = n->right; + } else { + n = c_index_stack_pop(); + } + } while (n); + } +} + +int c_index_init() { + if (!c_index) + c_index = malloc(sizeof(struct bt_node) * n_balls); + if (!c_index) + return 0; + if (!c_index_stack) + c_index_stack = malloc(sizeof(struct bt_node *) * n_balls); + if (!c_index_stack) + return 0; + return 1; +} + +void c_index_destroy() { + if (c_index) + free(c_index); + if (c_index_stack) + free(c_index_stack); + c_index = 0; + c_index_stack = 0; +} + diff --git a/c_index.h b/c_index.h new file mode 100644 index 0000000..fb979f9 --- /dev/null +++ b/c_index.h @@ -0,0 +1,11 @@ +#ifndef C_INDEX_H_INCLUDED +#define C_INDEX_H_INCLUDED + +#include "balls.h" + +void c_index_build(); +void c_index_check_collisions(void (*collision)(struct ball *, struct ball *)); +int c_index_init(); +void c_index_destroy(); + +#endif