diff --git a/src/Graphics.c b/src/Graphics.c index f65d459afcf73b6fc0982530225950dec4b348c7..b090a2382e6f24e746087e68bbaa6e1d9b69925a 100644 --- a/src/Graphics.c +++ b/src/Graphics.c @@ -11,7 +11,6 @@ #include <stdlib.h> #include "Point.h" -#include "utils.h" /// Create a fullscreen graphic window. /// @param title Title of the window. @@ -106,79 +105,40 @@ SDL_Keycode gfx_keypressed() { // -------------- +void gfx_draw_line(Graphics *graphics, Point p0, Point p1, uint32_t color) { + int dx = abs(p1.x - p0.x); + int sx = p0.x < p1.x ? 1 : -1; -// void gfx_draw_line(Graphics *graphics, Point p0, Point p1, uint32_t color) { -// int dx = abs(p1.x - p0.x); -// int sx = p0.x < p1.x ? 1 : -1; - -// int dy = -abs(p1.y - p0.y); -// int sy = p0.y < p1.y ? 1 : -1; - -// int error = dx + dy; - -// while (true) { -// gfx_putpixel(graphics, p0.x, p0.y, color); - -// if (p0.x == p1.x && p0.y == p1.y) { -// break; -// } - -// int e2 = 2 * error; - -// if (e2 >= dy) { -// if (p0.x == p1.x) { -// break; -// } - -// error += dy; -// p0.x += sx; -// } - -// if (e2 <= dx) { -// if (p0.y == p1.y) { -// break; -// } - -// error += dx; -// p0.y += sy; -// } -// } -// } - -void gfx_draw_line(Graphics *graphics, coordinates_t p0, coordinates_t p1, uint32_t color) { - int dx = abs(p1.column - p0.column); - int sx = p0.column < p1.column ? 1 : -1; - - int dy = -abs(p1.row - p0.row); - int sy = p0.row < p1.row ? 1 : -1; + int dy = -abs(p1.y - p0.y); + int sy = p0.y < p1.y ? 1 : -1; int error = dx + dy; while (true) { - gfx_putpixel(graphics, p0.column, p0.row, color); + gfx_putpixel(graphics, p0.x, p0.y, color); - if (p0.column == p1.column && p0.row == p1.row) { + if (p0.x == p1.x && p0.y == p1.y) { break; } int e2 = 2 * error; if (e2 >= dy) { - if (p0.column == p1.column) { + if (p0.x == p1.x) { break; } error += dy; - p0.column += sx; + p0.x += sx; } if (e2 <= dx) { - if (p0.row == p1.row) { + if (p0.y == p1.y) { break; } error += dx; - p0.row += sy; + p0.y += sy; } } } diff --git a/src/Graphics.h b/src/Graphics.h index 0e79513f48484aa584d876cb869b919bb67be724..4fde5484f5ea7d086e2bebadfe06d72487bde752 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -6,7 +6,6 @@ #include <stdint.h> #include "Point.h" -#include "utils.h" #define MAKE_COLOR(r, g, b) \ ((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16)) @@ -40,7 +39,7 @@ extern void gfx_destroy(struct gfx_context_t *ctxt); extern void gfx_present(struct gfx_context_t *ctxt); extern SDL_Keycode gfx_keypressed(); -void gfx_draw_line(Graphics *graphics, coordinates_t p0, coordinates_t p1, uint32_t color); +void gfx_draw_line(Graphics *graphics, Point p0, Point p1, uint32_t color); void gfx_draw_circle(Graphics *graphics, Point c, uint32_t r, uint32_t color); #endif diff --git a/src/Makefile b/src/Makefile index 312961bd91804e14951ef144eed01ea381c6bba5..648b396998247a878b1f874ae47f6fad1277c11f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,48 +1,30 @@ TARGET = program LIBS = -lm CC = gcc -CFLAGS = -g -Ofast -Wall -Wextra +CFLAGS = -g -Wall -Wextra -pedantic -Ofast ifeq ($(OS),Windows_NT) LIBS += -lmingw32 -lSDL2main -lSDL2 else LIBS += -lSDL2 + CFLAGS += -fsanitize=address -fsanitize=leak endif -default: $(TARGET) - -Charge.o: Charge.c Charge.h - $(CC) ${CFLAGS} -c $< - -constants.o: constants.c constants.h - $(CC) ${CFLAGS} -c $< - -Graphics.o: Graphics.c Graphics.h - $(CC) ${CFLAGS} -c $< +.PHONY: default all clean -main.o: main.c - $(CC) ${CFLAGS} -c $< - -Point.o: Point.c Point.h - $(CC) ${CFLAGS} -c $< - -random_number.o: random_number.c random_number.h - $(CC) ${CFLAGS} -c $< - -Rectangle.o: Rectangle.c Rectangle.h - $(CC) ${CFLAGS} -c $< +default: $(TARGET) +all: default -Simulation.o: Simulation.c Simulation.h - $(CC) ${CFLAGS} -c $< +OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) +HEADERS = $(wildcard *.h) -utils.o: utils.c utils.h - $(CC) ${CFLAGS} -c $< +%.o: %.c $(HEADERS) + $(CC) $(CFLAGS) -c $< -o $@ -Vector2.o: Vector2.c Vector2.h - $(CC) ${CFLAGS} -c $< +.PRECIOUS: $(TARGET) $(OBJECTS) -$(TARGET): Charge.o constants.o Graphics.o main.o Point.o random_number.o Rectangle.o Simulation.o utils.o Vector2.o - $(CC) -Wall -o $@ $^ $(LIBS) +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) ${CFLAGS} $(LIBS) -o $@ clean: rm -f *.o ${TARGET}* diff --git a/src/Point.c b/src/Point.c index 01760731af34c6c68ffb1d4473ab8c6cec5dbc8e..13f1881d17133f6e0086ea23c62f940d50ae264b 100644 --- a/src/Point.c +++ b/src/Point.c @@ -1,5 +1,18 @@ #include "Point.h" +#include <math.h> + +#include "Rectangle.h" +#include "Vector2.h" + Point point_init(int x, int y) { return (Point){.x = x, .y = y}; } + +Point position_to_point(Vector2 position, Rectangle *universe, int width, int height) { + double dx = universe->bottom_right.x - universe->top_left.x; + double dy = universe->bottom_right.y - universe->top_left.y; + int x = (int)round(width * (position.x - universe->top_left.x) / dx); + int y = (int)round(height * (position.y - universe->top_left.y) / dy); + return point_init(x, y); +} diff --git a/src/Point.h b/src/Point.h index abe7b02b7231271425eec4584ed2b4a28fa97c32..0f99e2419eb44d2ff4fb4394f9a174f3240668b5 100644 --- a/src/Point.h +++ b/src/Point.h @@ -1,11 +1,15 @@ #ifndef POINT_H #define POINT_H +#include "Rectangle.h" +#include "Vector2.h" + typedef struct Point { int x; int y; } Point; Point point_init(int x, int y); +Point position_to_point(Vector2 position, Rectangle *universe, int width, int height); #endif diff --git a/src/Simulation.c b/src/Simulation.c index b75f1a2ca8f48ec9e079799a3a603cf96baff3fc..3eb8282596cf8b3ff29a1706545e463b040c24b5 100644 --- a/src/Simulation.c +++ b/src/Simulation.c @@ -7,7 +7,8 @@ #include "Vector2.h" #include "constants.h" #include "random_number.h" -#include "utils.h" + +static bool is_out_of_bounds(Rectangle *universe, Vector2 point); static Charge generate_random_charge() { Vector2 position = vector2_init(random_number_between_0_and_1(), random_number_between_0_and_1()); @@ -15,13 +16,35 @@ static Charge generate_random_charge() { return charge_init(ELEMENTARY_CHARGE * sign, position); } -static Charge *generate_random_charges(int *charges_length) { +static Charge *generate_random_charges(Rectangle *universe, int *charges_length) { *charges_length = random_number_between(MIN_CHARGES, MAX_CHARGES); Charge *charges = (Charge *)malloc(sizeof(Charge) * *charges_length); for (int i = 0; i < *charges_length; i++) { - charges[i] = generate_random_charge(); - // TODO : check if charge is not close to border or close to another charge + while (true) { + Charge charge = generate_random_charge(); + + Vector2 position = charge.position; + double eps = (double)CHARGE_CIRCLE_RADIUS / SCREEN_WIDTH; + if (is_out_of_bounds(universe, vector2_add(position, vector2_init(0, -eps)))) { + continue; + } + if (is_out_of_bounds(universe, vector2_add(position, vector2_init(eps, 0)))) { + continue; + } + if (is_out_of_bounds(universe, vector2_add(position, vector2_init(0, eps)))) { + continue; + } + if (is_out_of_bounds(universe, vector2_add(position, vector2_init(-eps, 0)))) { + continue; + } + + // TODO : avoid two charge to bee to close. + // TODO : eps as const + + charges[i] = charge; + break; + } } return charges; @@ -48,7 +71,7 @@ static bool compute_e(Charge charge, Vector2 point, double eps, Vector2 *e) { static bool compute_total_normalized_e(int charges_length, Charge *charges, Vector2 point, double eps, Vector2 *e) { *e = vector2_init_zero(); - for (int i = 0; i < charges_length; i += 1) { + for (int i = 0; i < charges_length; i++) { Vector2 e_i; if (!compute_e(charges[i], point, eps, &e_i)) { return false; @@ -65,70 +88,79 @@ static bool is_out_of_bounds(Rectangle *universe, Vector2 point) { return point.x < universe->top_left.x || point.x > universe->bottom_right.x || point.y < universe->top_left.y || point.y > universe->bottom_right.y; } -static bool compute_next_point(Rectangle *universe, int charges_length, Charge *charges, Vector2 current_point, double eps, double dx, int direction, Vector2 *next_point) { - Vector2 electric_field; - if (!compute_total_normalized_e(charges_length, charges, current_point, eps, &electric_field)) { +static bool compute_next_point(Simulation *simulation, int direction, Vector2 current_point, double eps, Vector2 *next_point) { + Vector2 electric_field_normalized; + if (!compute_total_normalized_e(simulation->charges_length, simulation->charges, current_point, eps, &electric_field_normalized)) { return false; } - *next_point = vector2_add(current_point, vector2_multiply(vector2_multiply(electric_field, dx), direction)); + *next_point = vector2_multiply(vector2_multiply(electric_field_normalized, simulation->delta_x), direction); + *next_point = vector2_add(current_point, *next_point); - if (is_out_of_bounds(universe, *next_point)) { + if (is_out_of_bounds(simulation->universe, *next_point)) { return false; } return true; } -static void draw_field_line_with_direction(Graphics *graphics, Rectangle *universe, int charges_length, Charge *charges, double dx, Vector2 starting_point, int direction) { +static void draw_field_line_with_direction(Simulation *simulation, Graphics *graphics, Vector2 starting_point, int direction) { Vector2 current_point = starting_point; + // Represents the acceptable distance between the last point and the charge, this distance is calculated with + // the radius of the charge display circle and the width of the window. + double eps = (double)CHARGE_CIRCLE_RADIUS / SCREEN_WIDTH; while (true) { Vector2 next_point; - if (!compute_next_point(universe, charges_length, charges, current_point, (double)CHARGE_CIRCLE_RADIUS / SCREEN_WIDTH, dx, direction, &next_point)) { + if (!compute_next_point(simulation, direction, current_point, eps, &next_point)) { break; } - coordinates_t current_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, current_point); - coordinates_t next_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, next_point); - gfx_draw_line(graphics, current_coordinates, next_coordinates, COLOR_WHITE); + Point p0 = position_to_point(current_point, simulation->universe, SCREEN_WIDTH, SCREEN_HEIGHT); + Point p1 = position_to_point(next_point, simulation->universe, SCREEN_WIDTH, SCREEN_HEIGHT); + gfx_draw_line(graphics, p0, p1, COLOR_WHITE); current_point = next_point; } } -static void draw_field_line(Graphics *graphics, Rectangle *universe, int charges_length, Charge *charges, double dx, Vector2 starting_point) { - draw_field_line_with_direction(graphics, universe, charges_length, charges, dx, starting_point, -1); - draw_field_line_with_direction(graphics, universe, charges_length, charges, dx, starting_point, 1); +static void draw_field_line(Simulation *simulation, Graphics *graphics, Vector2 starting_point) { + draw_field_line_with_direction(simulation, graphics, starting_point, -1); + draw_field_line_with_direction(simulation, graphics, starting_point, 1); } -// Visible functions. - Simulation *simulation_init(Rectangle *universe, double delta_x) { Simulation *simulation = (Simulation *)malloc(sizeof(Simulation)); simulation->universe = universe; - simulation->charges = generate_random_charges(&simulation->charges_length); + simulation->charges = generate_random_charges(simulation->universe, &simulation->charges_length); simulation->delta_x = delta_x; return simulation; } +void simulation_destroy(Simulation **simulation) { + free((*simulation)->charges); + free(*simulation); + *simulation = NULL; +} + void simulation_draw(Simulation *simulation, Graphics *graphics) { draw_charges(simulation, graphics); // // Drawing of field lines from randomly placed points. - // int number_random_points = 100; - // for (int i = 0; i < number_random_points; i += 1) { - // draw_field_line(canvas, charges, charges_length, delta_x, vector2_init(random_number_between_0_and_1(), random_number_between_0_and_1()), x0, x1, y0, y1); + // int number_of_random_points = 100; + // for (int i = 0; i < number_of_random_points; i++) { + // Vector2 starting_point = vector2_init(random_number_between_0_and_1(), random_number_between_0_and_1()); + // draw_field_line(simulation, graphics, starting_point); // } // Drawing of the field lines from points placed around each of the particles (the display is more homogeneous with this technique). - for (int32_t i = 0; i < simulation->charges_length; i += 1) { - Vector2 pos = simulation->charges[i].position; + for (int32_t i = 0; i < simulation->charges_length; i++) { + Vector2 position = simulation->charges[i].position; double angle = 0; while (angle < 2 * M_PI) { angle += 2 * M_PI / 64; - Vector2 starting_point = vector2_add(pos, vector2_init(cos(angle) * 0.1, sin(angle) * 0.1)); - draw_field_line(graphics, simulation->universe, simulation->charges_length, simulation->charges, simulation->delta_x, starting_point); + Vector2 starting_point = vector2_add(position, vector2_init(cos(angle) * 0.1, sin(angle) * 0.1)); + draw_field_line(simulation, graphics, starting_point); } } } diff --git a/src/charge.c b/src/charge.c index 1ec39cd807e2646c5d97061b5610e9666ac270a3..09ce11d87637dc4cde793f8c4bc5b339b31948e5 100644 --- a/src/charge.c +++ b/src/charge.c @@ -1,27 +1,26 @@ #include "Charge.h" #include "Graphics.h" +#include "Point.h" #include "Rectangle.h" #include "Vector2.h" #include "constants.h" -#include "utils.h" -#include "Point.h" Charge charge_init(double q, Vector2 position) { return (Charge){.q = q, .position = position}; } void charge_draw(Charge charge, Graphics *graphics, Rectangle *universe) { - coordinates_t c = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, charge.position); + Point center = position_to_point(charge.position, universe, SCREEN_WIDTH, SCREEN_HEIGHT); int radius = CHARGE_CIRCLE_RADIUS; - gfx_draw_circle(graphics, point_init(c.column, c.row), radius, COLOR_WHITE); + gfx_draw_circle(graphics, center, radius, COLOR_WHITE); int color = charge.q > 0 ? COLOR_RED : COLOR_BLUE; int half_length = (int)(radius * .6); - gfx_draw_line(graphics, coordinates_create(c.row, c.column - half_length), coordinates_create(c.row, c.column + half_length), color); + gfx_draw_line(graphics, point_init(center.x - half_length, center.y), point_init(center.x + half_length, center.y), color); if (charge.q > 0) { - gfx_draw_line(graphics, coordinates_create(c.row - half_length, c.column), coordinates_create(c.row + half_length, c.column), color); + gfx_draw_line(graphics, point_init(center.x, center.y - half_length), point_init(center.x, center.y + half_length), color); } } diff --git a/src/main.c b/src/main.c index f4e38d9aa2a8073249a49b8dbcea83708f42c751..4f4075894005ee7d7059c3532b833f11af37da75 100644 --- a/src/main.c +++ b/src/main.c @@ -6,7 +6,6 @@ #include "Rectangle.h" #include "Simulation.h" #include "constants.h" -#include "utils.h" // https://stackoverflow.com/questions/3417837/what-is-the-best-way-to-suppress-a-unused-variable-x-warning #ifdef UNUSED @@ -24,8 +23,9 @@ double compute_delta_x(int width, int height) { int main(int UNUSED(argc), char *UNUSED(argv[])) { Graphics *graphics = gfx_create("Field Lines Simulation", SCREEN_WIDTH, SCREEN_HEIGHT); - // srand(time(NULL)); - srand(0); + srand(time(NULL)); + // srand(10); + // srand(11); if (graphics == NULL) { fprintf(stderr, "Graphic initialization failed!\n"); @@ -36,6 +36,8 @@ int main(int UNUSED(argc), char *UNUSED(argv[])) { Rectangle *universe = rectangle_init(UNIVERSE_X0, UNIVERSE_Y0, UNIVERSE_X1, UNIVERSE_Y1); Simulation *simulation = simulation_init(universe, compute_delta_x(SCREEN_WIDTH, SCREEN_HEIGHT)); simulation_draw(simulation, graphics); + simulation_destroy(&simulation); + rectangle_destroy(&universe); gfx_present(graphics); while (true) { diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index f5e5f59751b38f1548ee300b4e47065d69ac881d..0000000000000000000000000000000000000000 --- a/src/utils.c +++ /dev/null @@ -1,18 +0,0 @@ -#include "utils.h" - -#include <math.h> -#include <stdlib.h> - -#include "Rectangle.h" -#include "Vector2.h" - -coordinates_t coordinates_create(int row_, int column_) { - coordinates_t c = {.row = row_, .column = column_}; - return c; -} - -coordinates_t position_to_coordinates(int width, int height, Rectangle *universe, Vector2 pos) { - double dx = universe->bottom_right.x - universe->top_left.x; - double dy = universe->bottom_right.y - universe->top_left.y; - return coordinates_create((int)round(height * (pos.y - universe->top_left.y) / dy), (int)round(width * (pos.x - universe->top_left.x) / dx)); -} diff --git a/src/utils.h b/src/utils.h deleted file mode 100644 index 48d4b1340a09f5d6f66ca56c4f273377ae338ff0..0000000000000000000000000000000000000000 --- a/src/utils.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef UTILS_H -#define UTILS_H - -#include <stdint.h> - -#include "Rectangle.h" -#include "Vector2.h" - -typedef struct _coordinates_t { - int32_t row; - int32_t column; -} coordinates_t; - -coordinates_t coordinates_create(int row_, int column_); -coordinates_t position_to_coordinates(int width, int height, Rectangle *universe, Vector2 pos); - -#endif diff --git a/src/vector2.c b/src/vector2.c index af41282bb0e5ab5dfa250eb2b2bd258ac50c7b3a..a59e50d48b7e2a69135456684dd84bb2e745dfeb 100644 --- a/src/vector2.c +++ b/src/vector2.c @@ -1,9 +1,6 @@ #include "Vector2.h" #include <math.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> Vector2 vector2_init(double x, double y) { return (Vector2){.x = x, .y = y}; diff --git a/src/vector2.h b/src/vector2.h index 05eedb51d26b65e98943faba8cdce7779d2b5583..1aa1b7b504eaf187abc15c51e9da245532557b4a 100644 --- a/src/vector2.h +++ b/src/vector2.h @@ -1,9 +1,6 @@ #ifndef VECTOR2_H #define VECTOR2_H -#include <stdbool.h> -#include <stdint.h> - typedef struct Vector2 { double x; double y;