Skip to content
Snippets Groups Projects
Commit dae08843 authored by Florian Burgener's avatar Florian Burgener
Browse files

Refactoring 4

parent 406f5005
Branches
No related tags found
No related merge requests found
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <stdlib.h> #include <stdlib.h>
#include "Point.h" #include "Point.h"
#include "utils.h"
/// Create a fullscreen graphic window. /// Create a fullscreen graphic window.
/// @param title Title of the window. /// @param title Title of the window.
...@@ -106,79 +105,40 @@ SDL_Keycode gfx_keypressed() { ...@@ -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 dy = -abs(p1.y - p0.y);
// int dx = abs(p1.x - p0.x); int sy = p0.y < p1.y ? 1 : -1;
// 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 error = dx + dy; int error = dx + dy;
while (true) { 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; break;
} }
int e2 = 2 * error; int e2 = 2 * error;
if (e2 >= dy) { if (e2 >= dy) {
if (p0.column == p1.column) { if (p0.x == p1.x) {
break; break;
} }
error += dy; error += dy;
p0.column += sx; p0.x += sx;
} }
if (e2 <= dx) { if (e2 <= dx) {
if (p0.row == p1.row) { if (p0.y == p1.y) {
break; break;
} }
error += dx; error += dx;
p0.row += sy; p0.y += sy;
} }
} }
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include <stdint.h> #include <stdint.h>
#include "Point.h" #include "Point.h"
#include "utils.h"
#define MAKE_COLOR(r, g, b) \ #define MAKE_COLOR(r, g, b) \
((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16)) ((uint32_t)b | ((uint32_t)g << 8) | ((uint32_t)r << 16))
...@@ -40,7 +39,7 @@ extern void gfx_destroy(struct gfx_context_t *ctxt); ...@@ -40,7 +39,7 @@ extern void gfx_destroy(struct gfx_context_t *ctxt);
extern void gfx_present(struct gfx_context_t *ctxt); extern void gfx_present(struct gfx_context_t *ctxt);
extern SDL_Keycode gfx_keypressed(); 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); void gfx_draw_circle(Graphics *graphics, Point c, uint32_t r, uint32_t color);
#endif #endif
TARGET = program TARGET = program
LIBS = -lm LIBS = -lm
CC = gcc CC = gcc
CFLAGS = -g -Ofast -Wall -Wextra CFLAGS = -g -Wall -Wextra -pedantic -Ofast
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
LIBS += -lmingw32 -lSDL2main -lSDL2 LIBS += -lmingw32 -lSDL2main -lSDL2
else else
LIBS += -lSDL2 LIBS += -lSDL2
CFLAGS += -fsanitize=address -fsanitize=leak
endif endif
default: $(TARGET) .PHONY: default all clean
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 $<
main.o: main.c default: $(TARGET)
$(CC) ${CFLAGS} -c $< all: default
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 $<
Simulation.o: Simulation.c Simulation.h OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
$(CC) ${CFLAGS} -c $< HEADERS = $(wildcard *.h)
utils.o: utils.c utils.h %.o: %.c $(HEADERS)
$(CC) ${CFLAGS} -c $< $(CC) $(CFLAGS) -c $< -o $@
Vector2.o: Vector2.c Vector2.h .PRECIOUS: $(TARGET) $(OBJECTS)
$(CC) ${CFLAGS} -c $<
$(TARGET): Charge.o constants.o Graphics.o main.o Point.o random_number.o Rectangle.o Simulation.o utils.o Vector2.o $(TARGET): $(OBJECTS)
$(CC) -Wall -o $@ $^ $(LIBS) $(CC) $(OBJECTS) ${CFLAGS} $(LIBS) -o $@
clean: clean:
rm -f *.o ${TARGET}* rm -f *.o ${TARGET}*
#include "Point.h" #include "Point.h"
#include <math.h>
#include "Rectangle.h"
#include "Vector2.h"
Point point_init(int x, int y) { Point point_init(int x, int y) {
return (Point){.x = x, .y = 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);
}
#ifndef POINT_H #ifndef POINT_H
#define POINT_H #define POINT_H
#include "Rectangle.h"
#include "Vector2.h"
typedef struct Point { typedef struct Point {
int x; int x;
int y; int y;
} Point; } Point;
Point point_init(int x, int y); Point point_init(int x, int y);
Point position_to_point(Vector2 position, Rectangle *universe, int width, int height);
#endif #endif
...@@ -7,7 +7,8 @@ ...@@ -7,7 +7,8 @@
#include "Vector2.h" #include "Vector2.h"
#include "constants.h" #include "constants.h"
#include "random_number.h" #include "random_number.h"
#include "utils.h"
static bool is_out_of_bounds(Rectangle *universe, Vector2 point);
static Charge generate_random_charge() { static Charge generate_random_charge() {
Vector2 position = vector2_init(random_number_between_0_and_1(), random_number_between_0_and_1()); 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() { ...@@ -15,13 +16,35 @@ static Charge generate_random_charge() {
return charge_init(ELEMENTARY_CHARGE * sign, position); 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); *charges_length = random_number_between(MIN_CHARGES, MAX_CHARGES);
Charge *charges = (Charge *)malloc(sizeof(Charge) * *charges_length); Charge *charges = (Charge *)malloc(sizeof(Charge) * *charges_length);
for (int i = 0; i < *charges_length; i++) { for (int i = 0; i < *charges_length; i++) {
charges[i] = generate_random_charge(); while (true) {
// TODO : check if charge is not close to border or close to another charge 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; return charges;
...@@ -48,7 +71,7 @@ static bool compute_e(Charge charge, Vector2 point, double eps, Vector2 *e) { ...@@ -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) { static bool compute_total_normalized_e(int charges_length, Charge *charges, Vector2 point, double eps, Vector2 *e) {
*e = vector2_init_zero(); *e = vector2_init_zero();
for (int i = 0; i < charges_length; i += 1) { for (int i = 0; i < charges_length; i++) {
Vector2 e_i; Vector2 e_i;
if (!compute_e(charges[i], point, eps, &e_i)) { if (!compute_e(charges[i], point, eps, &e_i)) {
return false; return false;
...@@ -65,70 +88,79 @@ static bool is_out_of_bounds(Rectangle *universe, Vector2 point) { ...@@ -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; 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) { static bool compute_next_point(Simulation *simulation, int direction, Vector2 current_point, double eps, Vector2 *next_point) {
Vector2 electric_field; Vector2 electric_field_normalized;
if (!compute_total_normalized_e(charges_length, charges, current_point, eps, &electric_field)) { if (!compute_total_normalized_e(simulation->charges_length, simulation->charges, current_point, eps, &electric_field_normalized)) {
return false; 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 false;
} }
return true; 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; 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) { while (true) {
Vector2 next_point; 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; break;
} }
coordinates_t current_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, current_point); Point p0 = position_to_point(current_point, simulation->universe, SCREEN_WIDTH, SCREEN_HEIGHT);
coordinates_t next_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, next_point); Point p1 = position_to_point(next_point, simulation->universe, SCREEN_WIDTH, SCREEN_HEIGHT);
gfx_draw_line(graphics, current_coordinates, next_coordinates, COLOR_WHITE); gfx_draw_line(graphics, p0, p1, COLOR_WHITE);
current_point = next_point; current_point = next_point;
} }
} }
static void draw_field_line(Graphics *graphics, Rectangle *universe, int charges_length, Charge *charges, double dx, Vector2 starting_point) { static void draw_field_line(Simulation *simulation, Graphics *graphics, Vector2 starting_point) {
draw_field_line_with_direction(graphics, universe, charges_length, charges, dx, starting_point, -1); draw_field_line_with_direction(simulation, graphics, starting_point, -1);
draw_field_line_with_direction(graphics, universe, charges_length, charges, dx, 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_init(Rectangle *universe, double delta_x) {
Simulation *simulation = (Simulation *)malloc(sizeof(Simulation)); Simulation *simulation = (Simulation *)malloc(sizeof(Simulation));
simulation->universe = universe; 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; simulation->delta_x = delta_x;
return simulation; return simulation;
} }
void simulation_destroy(Simulation **simulation) {
free((*simulation)->charges);
free(*simulation);
*simulation = NULL;
}
void simulation_draw(Simulation *simulation, Graphics *graphics) { void simulation_draw(Simulation *simulation, Graphics *graphics) {
draw_charges(simulation, graphics); draw_charges(simulation, graphics);
// // Drawing of field lines from randomly placed points. // // Drawing of field lines from randomly placed points.
// int number_random_points = 100; // int number_of_random_points = 100;
// for (int i = 0; i < number_random_points; i += 1) { // for (int i = 0; i < number_of_random_points; i++) {
// 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); // 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). // 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) { for (int32_t i = 0; i < simulation->charges_length; i++) {
Vector2 pos = simulation->charges[i].position; Vector2 position = simulation->charges[i].position;
double angle = 0; double angle = 0;
while (angle < 2 * M_PI) { while (angle < 2 * M_PI) {
angle += 2 * M_PI / 64; angle += 2 * M_PI / 64;
Vector2 starting_point = vector2_add(pos, vector2_init(cos(angle) * 0.1, sin(angle) * 0.1)); Vector2 starting_point = vector2_add(position, 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); draw_field_line(simulation, graphics, starting_point);
} }
} }
} }
#include "Charge.h" #include "Charge.h"
#include "Graphics.h" #include "Graphics.h"
#include "Point.h"
#include "Rectangle.h" #include "Rectangle.h"
#include "Vector2.h" #include "Vector2.h"
#include "constants.h" #include "constants.h"
#include "utils.h"
#include "Point.h"
Charge charge_init(double q, Vector2 position) { Charge charge_init(double q, Vector2 position) {
return (Charge){.q = q, .position = position}; return (Charge){.q = q, .position = position};
} }
void charge_draw(Charge charge, Graphics *graphics, Rectangle *universe) { 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; 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 color = charge.q > 0 ? COLOR_RED : COLOR_BLUE;
int half_length = (int)(radius * .6); 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) { 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);
} }
} }
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include "Rectangle.h" #include "Rectangle.h"
#include "Simulation.h" #include "Simulation.h"
#include "constants.h" #include "constants.h"
#include "utils.h"
// https://stackoverflow.com/questions/3417837/what-is-the-best-way-to-suppress-a-unused-variable-x-warning // https://stackoverflow.com/questions/3417837/what-is-the-best-way-to-suppress-a-unused-variable-x-warning
#ifdef UNUSED #ifdef UNUSED
...@@ -24,8 +23,9 @@ double compute_delta_x(int width, int height) { ...@@ -24,8 +23,9 @@ double compute_delta_x(int width, int height) {
int main(int UNUSED(argc), char *UNUSED(argv[])) { int main(int UNUSED(argc), char *UNUSED(argv[])) {
Graphics *graphics = gfx_create("Field Lines Simulation", SCREEN_WIDTH, SCREEN_HEIGHT); Graphics *graphics = gfx_create("Field Lines Simulation", SCREEN_WIDTH, SCREEN_HEIGHT);
// srand(time(NULL)); srand(time(NULL));
srand(0); // srand(10);
// srand(11);
if (graphics == NULL) { if (graphics == NULL) {
fprintf(stderr, "Graphic initialization failed!\n"); fprintf(stderr, "Graphic initialization failed!\n");
...@@ -36,6 +36,8 @@ int main(int UNUSED(argc), char *UNUSED(argv[])) { ...@@ -36,6 +36,8 @@ int main(int UNUSED(argc), char *UNUSED(argv[])) {
Rectangle *universe = rectangle_init(UNIVERSE_X0, UNIVERSE_Y0, UNIVERSE_X1, UNIVERSE_Y1); 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 *simulation = simulation_init(universe, compute_delta_x(SCREEN_WIDTH, SCREEN_HEIGHT));
simulation_draw(simulation, graphics); simulation_draw(simulation, graphics);
simulation_destroy(&simulation);
rectangle_destroy(&universe);
gfx_present(graphics); gfx_present(graphics);
while (true) { while (true) {
......
#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));
}
#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
#include "Vector2.h" #include "Vector2.h"
#include <math.h> #include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
Vector2 vector2_init(double x, double y) { Vector2 vector2_init(double x, double y) {
return (Vector2){.x = x, .y = y}; return (Vector2){.x = x, .y = y};
......
#ifndef VECTOR2_H #ifndef VECTOR2_H
#define VECTOR2_H #define VECTOR2_H
#include <stdbool.h>
#include <stdint.h>
typedef struct Vector2 { typedef struct Vector2 {
double x; double x;
double y; double y;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment