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

Refactoring 1

parent 7d8edffb
Branches
No related tags found
No related merge requests found
......@@ -8,3 +8,8 @@ cd src
make
./program
```
## Windows
mingw32-make.exe
pacman -S mingw-w64-x86_64-SDL2
......@@ -11,7 +11,7 @@ endif
default: $(TARGET)
charge.o: charge.c charge.h
Charge.o: Charge.c Charge.h
$(CC) ${CFLAGS} -c $<
main.o: main.c
......@@ -23,10 +23,19 @@ utils.o: utils.c utils.h
vector2.o: vector2.c vector2.h
$(CC) ${CFLAGS} -c $<
Rectangle.o: Rectangle.c Rectangle.h
$(CC) ${CFLAGS} -c $<
Simulation.o: Simulation.c Simulation.h
$(CC) ${CFLAGS} -c $<
random_number.o: random_number.c random_number.h
$(CC) ${CFLAGS} -c $<
gfx.o: ./gfx/gfx.c ./gfx/gfx.h
$(CC) ${CFLAGS} -c $<
$(TARGET): charge.o main.o utils.o vector2.o gfx.o
$(TARGET): Charge.o main.o utils.o vector2.o gfx.o Rectangle.o Simulation.o random_number.o
$(CC) -Wall -o $@ $^ $(LIBS)
clean:
......
mingw32-make.exe
pacman -S mingw-w64-x86_64-SDL2
#include "Rectangle.h"
#include <stdlib.h>
#include "vector2.h"
Rectangle *rectangle_init(int x0, int y0, int x1, int y1) {
Rectangle *rectangle = (Rectangle *)malloc(sizeof(Rectangle));
rectangle->top_left = vector2_create(x0, y0);
rectangle->bottom_right = vector2_create(x1, y1);
return rectangle;
}
void rectangle_destroy(Rectangle **rectangle) {
free(*rectangle);
*rectangle = NULL;
}
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "vector2.h"
typedef struct Rectangle {
vector2_t top_left;
vector2_t bottom_right;
} Rectangle;
Rectangle *rectangle_init(int x0, int y0, int x1, int y1);
void rectangle_destroy(Rectangle **rectangle);
#endif
#include "Simulation.h"
#include <stdlib.h>
#include "Charge.h"
#include "gfx/gfx.h"
#include "random_number.h"
#include "utils.h"
#include "vector2.h"
static const int MIN_CHARGES = 2;
static const int MAX_CHARGES = 5;
const int CHARGE_CIRCLE_RADIUS = 20;
const double K = 8.988e9;
const double ELEMENTARY_CHARGE = 1.602e-19;
static Charge generate_random_charge() {
vector2_t position = vector2_create(random_number_between_0_and_1(), random_number_between_0_and_1());
int sign = rand() % 2 == 0 ? 1 : -1;
return charge_init(ELEMENTARY_CHARGE * sign, position);
}
static Charge *generate_random_charges(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
}
return charges;
}
static void draw_charge(Charge charge, struct gfx_context_t *ctxt, Rectangle *universe) {
coordinates_t c = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, universe, charge.pos);
int radius = CHARGE_CIRCLE_RADIUS;
gfx_draw_circle(ctxt, c, radius, COLOR_WHITE);
int color = charge.q > 0 ? COLOR_RED : COLOR_BLUE;
int half_length = (int)(radius * .6);
gfx_draw_line(ctxt, coordinates_create(c.row, c.column - half_length), coordinates_create(c.row, c.column + half_length), color);
if (charge.q > 0) {
gfx_draw_line(ctxt, coordinates_create(c.row - half_length, c.column), coordinates_create(c.row + half_length, c.column), color);
}
}
static void draw_charges(Simulation *simulation, struct gfx_context_t *ctxt) {
for (int i = 0; i < simulation->charges_length; i++) {
draw_charge(simulation->charges[i], ctxt, simulation->universe);
}
}
static bool compute_e(Charge charge, vector2_t p, double eps, vector2_t *e) {
vector2_t r = vector2_substract(charge.pos, p);
double e_intensity = K * fabs(charge.q) / vector2_norm_sqr(r);
*e = vector2_multiply(vector2_normalize(r), e_intensity);
if (charge.q > 0) {
*e = vector2_multiply(*e, -1);
}
return vector2_norm(r) >= eps;
}
static bool compute_total_normalized_e(int charges_length, Charge *charges, vector2_t p, double eps, vector2_t *e) {
*e = vector2_create_zero();
for (int i = 0; i < charges_length; i += 1) {
vector2_t e_i;
if (!compute_e(charges[i], p, eps, &e_i)) {
return false;
}
*e = vector2_add(*e, e_i);
}
*e = vector2_normalize(*e);
return true;
}
static bool is_out_of_bounds(Rectangle *universe, vector2_t 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_t current_pos, double eps, double dx, int direction, vector2_t *next_point) {
vector2_t electric_field;
if (!compute_total_normalized_e(charges_length, charges, current_pos, eps, &electric_field)) {
return false;
}
*next_point = vector2_add(current_pos, vector2_multiply(vector2_multiply(electric_field, dx), direction));
if (is_out_of_bounds(universe, *next_point)) {
return false;
}
return true;
}
static void draw_field_line_with_direction(struct gfx_context_t *ctxt, Rectangle *universe, int charges_length, Charge *charges, double dx, vector2_t pos0, int direction) {
vector2_t current_point = pos0;
while (true) {
vector2_t next_point;
if (!compute_next_point(universe, charges_length, charges, current_point, 0.027, dx, direction, &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(ctxt, current_coordinates, next_coordinates, COLOR_WHITE);
current_point = next_point;
}
}
static void draw_field_line(struct gfx_context_t *ctxt, Rectangle *universe, int charges_length, Charge *charges, double dx, vector2_t pos0) {
draw_field_line_with_direction(ctxt, universe, charges_length, charges, dx, pos0, -1);
draw_field_line_with_direction(ctxt, universe, charges_length, charges, dx, pos0, 1);
}
// ---
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->delta_x = delta_x;
return simulation;
}
void simulation_draw(Simulation *simulation, struct gfx_context_t *ctxt) {
draw_charges(simulation, ctxt);
// // 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_create(random_number_between_0_and_1(), random_number_between_0_and_1()), x0, x1, y0, y1);
// }
// 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_t pos = simulation->charges[i].pos;
double angle = 0;
while (angle < 2 * M_PI) {
angle += 2 * M_PI / 64;
vector2_t pos0 = vector2_add(pos, vector2_create(cos(angle) * 0.1, sin(angle) * 0.1));
draw_field_line(ctxt, simulation->universe, simulation->charges_length, simulation->charges, simulation->delta_x, pos0);
}
}
}
#ifndef SIMULATION_H
#define SIMULATION_H
#include "Charge.h"
#include "Rectangle.h"
#include "gfx/gfx.h"
typedef struct Simulation {
Rectangle *universe;
int charges_length;
Charge *charges;
double delta_x;
} Simulation;
Simulation *simulation_init(Rectangle *universe, double delta_x);
void simulation_destroy(Simulation **simulation);
void simulation_draw(Simulation *simulation, struct gfx_context_t *ctxt);
#endif
#include "charge.h"
#include "Charge.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "gfx/gfx.h"
#include "utils.h"
#include "vector2.h"
const double K = 8.988e9;
const double ELEMENTARY_CHARGE = 1.602e-19;
const double THRESHOLD_CHARGES_DISTANCES = 0.5;
const double EPSILON = 0.05;
double compute_delta_x(int width, int height) {
return 1.0 / sqrt((width * width) + (height * height));
}
bool compute_next_point(charge_t *charges, int num_charges, vector2_t current_pos, double eps, vector2_t *new_pos, double dx, int orientation) {
vector2_t electric_field;
if (compute_total_normalized_e(charges, num_charges, current_pos, eps, &electric_field)) {
*new_pos = vector2_add(current_pos, vector2_multiply(vector2_multiply(electric_field, dx), orientation));
return true;
}
return false;
}
bool is_out_of_bounds(vector2_t position, double x0, double x1, double y0, double y1) {
return position.x < x0 || position.x > x1 || position.y < y0 || position.y > y1;
}
charge_t charge_create(double q, vector2_t pos) {
charge_t c = {.q = q, .pos = pos};
return c;
}
bool compute_e(charge_t c, vector2_t p, double eps, vector2_t *e) {
*e = vector2_create_zero();
vector2_t r = vector2_substract(c.pos, p);
double norm_r = vector2_norm(r);
double E_i = K * (fabs(c.q) / (norm_r * norm_r));
*e = vector2_multiply(vector2_normalize(r), E_i);
if (c.q > 0) {
*e = vector2_multiply(*e, -1);
}
return norm_r >= eps;
}
bool compute_total_normalized_e(charge_t *charges, int num_charges, vector2_t p, double eps, vector2_t *e) {
*e = vector2_create_zero();
for (int i = 0; i < num_charges; i += 1) {
vector2_t tmp;
if (!compute_e(charges[i], p, eps, &tmp)) {
return false;
}
*e = vector2_add(*e, tmp);
}
*e = vector2_normalize(*e);
return true;
}
void draw_field_line(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double dx, vector2_t pos0, double x0, double x1, double y0, double y1, int orientation) {
vector2_t current_pos = pos0;
while (true) {
vector2_t new_pos;
if (!compute_next_point(charges, num_charges, current_pos, 0.027, &new_pos, dx, orientation)) {
break;
}
if (is_out_of_bounds(new_pos, x0, x1, y0, y1)) {
break;
}
coordinates_t current_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, current_pos);
coordinates_t new_coordinates = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, new_pos);
gfx_draw_line(ctxt, current_coordinates, new_coordinates, COLOR_WHITE);
current_pos = new_pos;
}
}
void draw_field_lines(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double dx, vector2_t pos0, double x0, double x1, double y0, double y1){
draw_field_line(ctxt, charges, num_charges, dx, pos0, x0, x1, y0, y1, -1);
draw_field_line(ctxt, charges, num_charges, dx, pos0, x0, x1, y0, y1, 1);
}
void draw_charges(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double x0, double x1, double y0, double y1) {
for (int32_t i = 0; i < num_charges; i += 1) {
coordinates_t c = position_to_coordinates(SCREEN_WIDTH, SCREEN_HEIGHT, x0, x1, y0, y1, charges[i].pos);
int32_t radius = 20;
gfx_draw_circle(ctxt, c, radius, COLOR_WHITE);
int32_t color = charges[i].q > 0 ? COLOR_RED : COLOR_BLUE;
int32_t half_length = (int32_t)(radius * .6);
gfx_draw_line(ctxt, coordinates_create(c.row, c.column - half_length), coordinates_create(c.row, c.column + half_length), color);
if (charges[i].q > 0) {
gfx_draw_line(ctxt, coordinates_create(c.row - half_length, c.column), coordinates_create(c.row + half_length, c.column), color);
}
}
Charge charge_init(double q, vector2_t pos) {
return (Charge){.q = q, .pos = pos};
}
#ifndef CHARGE_H
#define CHARGE_H
#include <stdbool.h>
#include <stdint.h>
#include "gfx/gfx.h"
#include "utils.h"
#include "vector2.h"
extern const double K;
extern const double ELEMENTARY_CHARGE;
typedef struct _charge_t {
typedef struct Charge {
double q;
vector2_t pos;
} charge_t;
double compute_delta_x(int width, int height);
} Charge;
charge_t charge_create(double q, vector2_t pos);
Charge charge_init(double q, vector2_t pos);
bool compute_e(charge_t c, vector2_t p, double eps, vector2_t *e);
bool compute_total_normalized_e(charge_t *charges, int num_charges, vector2_t p, double eps, vector2_t *e);
void draw_field_line(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double dx, vector2_t pos0, double x0, double x1, double y0, double y1, int orientation);
void draw_charges(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double x0, double x1, double y0, double y1);
void draw_field_lines(struct gfx_context_t *ctxt, charge_t *charges, int num_charges, double dx, vector2_t pos0, double x0, double x1, double y0, double y1);
#endif
#include <math.h>
#include <stdio.h>
// #include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "charge.h"
#include "Rectangle.h"
#include "Simulation.h"
#include "gfx/gfx.h"
#include "utils.h"
#include "vector2.h"
static const int UNIVERSE_X0 = 0;
static const int UNIVERSE_Y0 = 0;
static const int UNIVERSE_X1 = 1;
static const int UNIVERSE_Y1 = 1;
double compute_delta_x(int width, int height) {
return 1.0 / sqrt((width * width) + (height * height));
}
int main(int argc, char *argv[]) {
srand(time(NULL));
......@@ -17,49 +26,11 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
double x0 = 0;
double y0 = 0;
double x1 = 1;
double y1 = 1;
int num_charges = 2;
charge_t *charges = (charge_t *)malloc(sizeof(charge_t) * num_charges);
charges[0] = charge_create(ELEMENTARY_CHARGE, vector2_create(.25, .8));
charges[1] = charge_create(-ELEMENTARY_CHARGE * 5, vector2_create(.85, .2));
// charges[2] = charge_create(-ELEMENTARY_CHARGE * 4, vector2_create(.5, .25));
// charges[3] = charge_create(ELEMENTARY_CHARGE * 5, vector2_create(.7, .75));
double dx = compute_delta_x(SCREEN_WIDTH, SCREEN_HEIGHT);
gfx_clear(canvas, COLOR_BLACK);
draw_charges(canvas, charges, num_charges, x0, x1, y0, y1);
// // Default strategy.
// int num_points = 100;
// for (int i = 0; i < num_points; i += 1) {
// draw_field_lines(canvas, charges, num_charges, dx, vector2_create(rand_one(), rand_one()), x0, x1, y0, y1);
// }
// // Alternative strategy 1.
// for (int32_t i = 1; i < SCREEN_HEIGHT; i += 1) {
// for (int32_t j = 1; j < SCREEN_WIDTH; j += 1) {
// double x = 1.0 / (SCREEN_WIDTH * .05) * j;
// double y = 1.0 / (SCREEN_HEIGHT * .05) * i;
// draw_field_lines(canvas, charges, num_charges, dx, vector2_create(x, y), x0, x1, y0, y1);
// }
// }
// Alternative strategy 2.
for (int32_t i = 0; i < num_charges; i += 1) {
vector2_t pos = charges[i].pos;
double angle = 0;
while (angle < 2 * M_PI) {
angle += 2 * M_PI / 64;
vector2_t pos0 = vector2_add(pos, vector2_create(cos(angle) * 0.1, sin(angle) * 0.1));
draw_field_lines(canvas, charges, num_charges, dx, pos0, x0, x1, y0, 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_draw(simulation, canvas);
gfx_present(canvas);
......
#include "random_number.h"
#include <stdlib.h>
int random_number_between(int min, int max) {
return min + rand() % (max - min + 1);
}
double random_number_between_0_and_1() {
return (double)rand() / RAND_MAX;
}
#ifndef RANDOM_NUMBER_H
#define RANDOM_NUMBER_H
int random_number_between(int min, int max);
double random_number_between_0_and_1();
#endif
......@@ -3,6 +3,7 @@
#include <math.h>
#include <stdlib.h>
#include "Rectangle.h"
#include "vector2.h"
const int SCREEN_WIDTH = 750;
......@@ -13,12 +14,8 @@ coordinates_t coordinates_create(int row_, int column_) {
return c;
}
coordinates_t position_to_coordinates(int width, int height, double x0, double x1, double y0, double y1, vector2_t pos) {
double dx = x1 - x0;
double dy = y1 - y0;
return coordinates_create((int)round(height * (pos.y - y0) / dy), (int)round(width * (pos.x - x0) / dx));
}
double rand_one() {
return (double)rand() / (double)RAND_MAX;
coordinates_t position_to_coordinates(int width, int height, Rectangle *universe, vector2_t 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));
}
......@@ -3,6 +3,7 @@
#include <stdint.h>
#include "Rectangle.h"
#include "vector2.h"
extern const int SCREEN_WIDTH;
......@@ -14,7 +15,6 @@ typedef struct _coordinates_t {
} coordinates_t;
coordinates_t coordinates_create(int row_, int column_);
coordinates_t position_to_coordinates(int width, int height, double x0, double x1, double y0, double y1, vector2_t pos);
double rand_one();
coordinates_t position_to_coordinates(int width, int height, Rectangle *universe, vector2_t pos);
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment